/*
* Helper to verify scanner output.
* Copyright © 2023-2024 Nick Bowler
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include "scan.h"
#include "cdecl-internal.h"
#define PROGNAME "scantest"
#include "test.h"
/* Stubs */
static union { struct parse_item item; char buf[1000]; } stub_item;
struct parse_item *cdecl__alloc_item(size_t sz)
{
return &stub_item.item;
}
void cdecl__errmsg(unsigned msg)
{
}
void cdecl__err(const char *fmt, const char *arg)
{
}
size_t cdecl__strlcpy(char *dst, const char *src, size_t len)
{
abort();
}
static const char sopts[] = "ECVH";
static const struct option lopts[] = {
{ "cdecl", 0, NULL, 'C' },
{ "english", 0, NULL, 'E' },
{ "version", 0, NULL, 'V' },
{ "help", 0, NULL, 'H' },
{ 0 }
};
static void print_usage(FILE *f)
{
fprintf(f, "Usage: %s [options] string [string ...]\n", progname);
}
static void print_help(void)
{
print_usage(stdout);
puts("Test the scanner by tokenizing one or more strings.\n");
test_print_options(lopts);
}
enum {
MODE_CDECL,
MODE_ENGLISH
};
static int print_uintmax_rec(char *buf, uintmax_t v)
{
int rc = 0;
if (v > 9) {
rc = print_uintmax_rec(buf, v/10);
v %= 10;
}
buf[rc] = '0' + v;
return rc + 1;
}
static void print_uintmax(char *buf, uintmax_t v)
{
buf[print_uintmax_rec(buf, v)] = 0;
}
static int do_scan(const char *s, int mode)
{
YY_BUFFER_STATE state;
yyscan_t scanner;
YYSTYPE lval;
YYLTYPE lloc;
int tok;
if (cdecl__yylex_init_extra(mode, &scanner) != 0)
return -1;
state = cdecl__yy_scan_string(s, scanner);
while ((tok = cdecl__yylex(&lval, &lloc, scanner))) {
const char *tname = cdecl__token_name(tok);
switch (tok) {
case T_UINT:
print_uintmax(stub_item.item.s, lval.uintval);
lval.item = &stub_item.item;
case T_IDENT:
printf("%s %s\n", tname, lval.item->s);
break;
default:
printf("%s\n", tname);
}
}
printf("eof\n");
cdecl__yy_delete_buffer(state, scanner);
cdecl__yylex_destroy(scanner);
return 0;
}
int main(int argc, char **argv)
{
int i, opt, mode = MODE_CDECL;
if (argc > 0)
progname = argv[0];
while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
switch (opt) {
case 'C':
mode = MODE_CDECL;
break;
case 'E':
mode = MODE_ENGLISH;
break;
case 'V':
test_print_version(PROGNAME);
return EXIT_SUCCESS;
case 'H':
print_help();
return EXIT_SUCCESS;
default:
print_usage(stderr);
return EXIT_FAILURE;
}
}
if (!argv[optind]) {
print_usage(stderr);
return EXIT_FAILURE;
}
for (i = optind; i < argc; i++) {
if (do_scan(argv[i], mode) != 0)
return EXIT_FAILURE;
}
return 0;
}