/* * 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; }