examples: clean up

* examples/c/calc/calc.y: Restore to its original state, with
parse.error=detailed instead of parse.error=custom (this example
should be simple).
* examples/c/calc/calc.test: Check syntax errors.
* examples/c/lexcalc/parse.y: Add comments.
This commit is contained in:
Akim Demaille
2020-01-25 07:59:26 +01:00
parent 0917f4dc76
commit c592202345
5 changed files with 42 additions and 58 deletions

View File

@@ -34,4 +34,10 @@ cat >input <<EOF
(1+2) * 3 (1+2) * 3
EOF EOF
run 0 9 run 0 9
# Check the traces.
run -noerr 0 9 -p run -noerr 0 9 -p
cat >input <<EOF
1++2
EOF
run 0 "err: syntax error, unexpected '+', expecting number or '('"

View File

@@ -1,50 +1,35 @@
%code top { %code top {
#include <ctype.h> /* isdigit. */ #include <ctype.h> /* isdigit. */
#include <stdbool.h>
#include <stdio.h> /* For printf, etc. */ #include <stdio.h> /* For printf, etc. */
#include <string.h> /* strcmp. */ #include <string.h> /* strcmp. */
int yylex (void); int yylex (void);
void yyerror (char const *); void yyerror (char const *);
bool show_expected = false;
#define PRINT_EXPECTED_TOKENS() \
do { \
if (show_expected) \
{ \
yyparse_context_t ctx \
= {yyssp, yytoken, yyesa, &yyes, &yyes_capacity}; \
int tokens[YYNTOKENS]; \
int cnt = yyexpected_tokens (&ctx, tokens, YYNTOKENS); \
fprintf (stderr, "expected tokens in state %d rule %d (%d):", \
*yyssp, yyn - 1, cnt); \
for (int i = 0; i < cnt; ++i) \
fprintf (stderr, " %s", yysymbol_name(tokens[i])); \
fprintf (stderr, "\n"); \
} \
} while (0)
} }
%define api.header.include {"calc.h"} %define api.header.include {"calc.h"}
%define api.value.type union /* Generate YYSTYPE from these types: */
%define parse.error custom /* Generate YYSTYPE from the types used in %token and %type. */
%define parse.lac full %define api.value.type union
%token <double> NUM "number" %token <double> NUM "number"
%type <double> expr term fact %type <double> expr term fact
/* Generate the parser description file. */ /* Generate the parser description file (calc.output). */
%verbose %verbose
/* Nice error messages with details. */
%define parse.error detailed
/* Enable run-time traces (yydebug). */ /* Enable run-time traces (yydebug). */
%define parse.trace %define parse.trace
/* Formatting semantic values. */ /* Formatting semantic values in debug traces. */
%printer { fprintf (yyo, "%g", $$); } <double>; %printer { fprintf (yyo, "%g", $$); } <double>;
%% /* The grammar follows. */ %% /* The grammar follows. */
input: input:
%empty { PRINT_EXPECTED_TOKENS (); } %empty
| input line { PRINT_EXPECTED_TOKENS (); } | input line
; ;
line: line:
@@ -66,34 +51,12 @@ term:
; ;
fact: fact:
"number" { PRINT_EXPECTED_TOKENS (); } "number"
| '(' expr { PRINT_EXPECTED_TOKENS (); } ')' { $$ = $expr; } | '(' expr ')' { $$ = $2; }
; ;
%% %%
int
yyreport_syntax_error (const yyparse_context_t *ctx)
{
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 10 };
/* Arguments of yyformat: reported tokens (one for the "unexpected",
one per "expected"). */
int arg[YYERROR_VERBOSE_ARGS_MAXIMUM];
int n = yysyntax_error_arguments (ctx, arg, sizeof arg / sizeof *arg);
if (n == -2)
return 2;
fprintf (stderr, "SYNTAX ERROR on token [%s]", yysymbol_name (arg[0]));
if (1 < n)
{
fprintf (stderr, " (expected:");
for (int i = 1; i < n; ++i)
fprintf (stderr, " [%s]", yysymbol_name (arg[i]));
fprintf (stderr, ")");
}
fprintf (stderr, "\n");
return 0;
}
int int
yylex (void) yylex (void)
{ {
@@ -130,9 +93,7 @@ main (int argc, char const* argv[])
{ {
/* Enable parse traces on option -p. */ /* Enable parse traces on option -p. */
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
if (!strcmp (argv[i], "-e")) if (!strcmp (argv[i], "-p"))
show_expected = 1;
else if (!strcmp (argv[i], "-p"))
yydebug = 1; yydebug = 1;
return yyparse (); return yyparse ();
} }

View File

@@ -19,12 +19,24 @@
#include <stdlib.h> // getenv. #include <stdlib.h> // getenv.
} }
// Don't share global variables between the scanner and the parser.
%define api.pure full %define api.pure full
// To avoid name clashes (e.g., with C's EOF) prefix token definitions
// with TOK_ (e.g., TOK_EOF).
%define api.token.prefix {TOK_} %define api.token.prefix {TOK_}
// %token and %type use genuine types (e.g., "%token <int>"). Let
// %bison define YYSTYPE as a union of all these types.
%define api.value.type union %define api.value.type union
%define parse.error verbose
// Generate detailed error messages.
%define parse.error detailed
// Enable debug traces (see yydebug in main).
%define parse.trace %define parse.trace
// Error count, exchanged between main, yyparse and yylex.
// Error count, exchanged between main, yyparse and yylex.
%param {int *nerrs} %param {int *nerrs}
%token %token
@@ -77,6 +89,7 @@ exp:
; ;
%% %%
// Epilogue (C code). // Epilogue (C code).
void yyerror (int *nerrs, const char *msg) void yyerror (int *nerrs, const char *msg)
{ {
fprintf (stderr, "%s\n", msg); fprintf (stderr, "%s\n", msg);

View File

@@ -1,4 +1,4 @@
/* Prologue (directives). -*- C++ -*- */ /* Prologue (directives). -*- C -*- */
/* Disable Flex features we don't need, to avoid warnings. */ /* Disable Flex features we don't need, to avoid warnings. */
%option nodefault noinput nounput noyywrap %option nodefault noinput nounput noyywrap

View File

@@ -1,4 +1,4 @@
/* Prologue (directives). -*- C++ -*- */ /* Prologue (directives). -*- C -*- */
/* Disable Flex features we don't need, to avoid warnings. */ /* Disable Flex features we don't need, to avoid warnings. */
%option nodefault noinput nounput noyywrap %option nodefault noinput nounput noyywrap
@@ -17,10 +17,14 @@
%% %%
%{ %{
// Number of opened parentheses.
int nesting = 0; int nesting = 0;
// A buffer storing the text inside the outer parentheses.
char *str = NULL; char *str = NULL;
int size = 0; // Its allocated size.
int capacity = 0; int capacity = 0;
// Its used size.
int size = 0;
#define STR_APPEND() \ #define STR_APPEND() \
do { \ do { \
if (capacity < size + yyleng + 1) \ if (capacity < size + yyleng + 1) \