mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-23 03:03:02 +00:00
examples: add a complete example with all the bells and whistles
* examples/c/bistromathic/Makefile, * examples/c/bistromathic/README.md, * examples/c/bistromathic/bistromathic.test, * examples/c/bistromathic/local.mk, * examples/c/bistromathic/parse.y, * examples/c/bistromathic/scan.l: New. * Makefile.am (AM_YFLAGS_WITH_LINES): Add -Wdangling-alias. * examples/test: Make failure errors easier to read.
This commit is contained in:
225
examples/c/bistromathic/parse.y
Normal file
225
examples/c/bistromathic/parse.y
Normal file
@@ -0,0 +1,225 @@
|
||||
%require "3.6"
|
||||
|
||||
%code top {
|
||||
#include <ctype.h> // isdigit
|
||||
#include <math.h> // cos, sin, etc.
|
||||
#include <stddef.h> // ptrdiff_t
|
||||
#include <stdio.h> // printf
|
||||
#include <string.h> // strcmp
|
||||
}
|
||||
|
||||
%code requires {
|
||||
// Function type.
|
||||
typedef double (func_t) (double);
|
||||
|
||||
// Data type for links in the chain of symbols.
|
||||
typedef struct symrec symrec;
|
||||
struct symrec
|
||||
{
|
||||
char *name; // name of symbol
|
||||
int type; // type of symbol: either VAR or FUN
|
||||
union
|
||||
{
|
||||
double var; // value of a VAR
|
||||
func_t *fun; // value of a FUN
|
||||
} value;
|
||||
symrec *next; // link field
|
||||
};
|
||||
|
||||
symrec *putsym (char const *name, int sym_type);
|
||||
symrec *getsym (char const *name);
|
||||
}
|
||||
|
||||
%code provides {
|
||||
#define YY_DECL \
|
||||
int yylex (YYSTYPE *yylval, YYLTYPE *yylloc)
|
||||
YY_DECL;
|
||||
|
||||
void yyerror (YYLTYPE *yylloc, char const *);
|
||||
}
|
||||
|
||||
%code {
|
||||
#define N_
|
||||
#define _
|
||||
}
|
||||
|
||||
// Don't share global variables between the scanner and the parser.
|
||||
%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_}
|
||||
|
||||
// Customized syntax error messages (see yyreport_syntax_error).
|
||||
%define parse.error custom
|
||||
|
||||
// with locations.
|
||||
%locations
|
||||
|
||||
// and acurate list of expected tokens.
|
||||
%define parse.lac full
|
||||
|
||||
// Generate the parser description file (calc.output).
|
||||
%verbose
|
||||
|
||||
// Generate YYSTYPE from the types assigned to symbols.
|
||||
%define api.value.type union
|
||||
%token
|
||||
PLUS "+"
|
||||
MINUS "-"
|
||||
STAR "*"
|
||||
SLASH "/"
|
||||
CARET "^"
|
||||
LPAREN "("
|
||||
RPAREN ")"
|
||||
EQUAL "="
|
||||
EOL _("end of line")
|
||||
EOF 0 _("end of file")
|
||||
<double>
|
||||
NUM _("double precision number")
|
||||
<symrec*>
|
||||
FUN _("function")
|
||||
VAR _("variable")
|
||||
|
||||
%nterm <double> exp
|
||||
|
||||
// Enable run-time traces (yydebug).
|
||||
%define parse.trace
|
||||
|
||||
// Formatting semantic values in debug traces.
|
||||
%printer { fprintf (yyo, "%s", $$->name); } VAR;
|
||||
%printer { fprintf (yyo, "%s()", $$->name); } FUN;
|
||||
%printer { fprintf (yyo, "%g", $$); } <double>;
|
||||
|
||||
|
||||
// Precedence (from lowest to highest) and associativity.
|
||||
%precedence "="
|
||||
%left "+" "-"
|
||||
%left "*" "/"
|
||||
%precedence NEG // negation--unary minus
|
||||
%right "^" // exponentiation
|
||||
|
||||
%% // The grammar follows.
|
||||
input:
|
||||
%empty
|
||||
| input line
|
||||
;
|
||||
|
||||
line:
|
||||
EOL
|
||||
| exp EOL { printf ("%.10g\n", $1); }
|
||||
| error EOL { yyerrok; }
|
||||
;
|
||||
|
||||
exp:
|
||||
NUM
|
||||
| VAR { $$ = $1->value.var; }
|
||||
| VAR "=" exp { $$ = $3; $1->value.var = $3; }
|
||||
| FUN "(" exp ")" { $$ = $1->value.fun ($3); }
|
||||
| exp "+" exp { $$ = $1 + $3; }
|
||||
| exp "-" exp { $$ = $1 - $3; }
|
||||
| exp "*" exp { $$ = $1 * $3; }
|
||||
| exp "/" exp
|
||||
{
|
||||
if ($3 == 0)
|
||||
{
|
||||
yyerror (&@$, "division by zero");
|
||||
YYERROR;
|
||||
}
|
||||
else
|
||||
$$ = $1 / $3;
|
||||
}
|
||||
| "-" exp %prec NEG { $$ = -$2; }
|
||||
| exp "^" exp { $$ = pow ($1, $3); }
|
||||
| "(" exp ")" { $$ = $2; }
|
||||
;
|
||||
|
||||
// End of grammar.
|
||||
%%
|
||||
|
||||
struct init
|
||||
{
|
||||
char const *name;
|
||||
func_t *fun;
|
||||
};
|
||||
|
||||
static struct init const funs[] =
|
||||
{
|
||||
{ "atan", atan },
|
||||
{ "cos", cos },
|
||||
{ "exp", exp },
|
||||
{ "ln", log },
|
||||
{ "sin", sin },
|
||||
{ "sqrt", sqrt },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
// The symbol table: a chain of 'struct symrec'.
|
||||
static symrec *sym_table;
|
||||
|
||||
// Put functions in table.
|
||||
static void
|
||||
init_table (void)
|
||||
{
|
||||
for (int i = 0; funs[i].name; i++)
|
||||
{
|
||||
symrec *ptr = putsym (funs[i].name, TOK_FUN);
|
||||
ptr->value.fun = funs[i].fun;
|
||||
}
|
||||
}
|
||||
|
||||
symrec *
|
||||
putsym (char const *name, int sym_type)
|
||||
{
|
||||
symrec *res = (symrec *) malloc (sizeof (symrec));
|
||||
res->name = strdup (name);
|
||||
res->type = sym_type;
|
||||
res->value.var = 0; // Set value to 0 even if fun.
|
||||
res->next = sym_table;
|
||||
sym_table = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
symrec *
|
||||
getsym (char const *name)
|
||||
{
|
||||
for (symrec *p = sym_table; p; p = p->next)
|
||||
if (strcmp (p->name, name) == 0)
|
||||
return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
yyreport_syntax_error (const yyparse_context_t *ctx)
|
||||
{
|
||||
enum { ARGMAX = 10 };
|
||||
int arg[ARGMAX];
|
||||
int n = yysyntax_error_arguments (ctx, arg, ARGMAX);
|
||||
if (n == -2)
|
||||
return 2;
|
||||
YY_LOCATION_PRINT (stderr, *yyparse_context_location (ctx));
|
||||
fprintf (stderr, ": syntax error");
|
||||
for (int i = 1; i < n; ++i)
|
||||
fprintf (stderr, " %s %s",
|
||||
i == 1 ? "expected" : "or", yysymbol_name (arg[i]));
|
||||
if (n)
|
||||
fprintf (stderr, " before %s", yysymbol_name (arg[0]));
|
||||
fprintf (stderr, "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Called by yyparse on error.
|
||||
void yyerror (YYLTYPE *loc, char const *s)
|
||||
{
|
||||
YY_LOCATION_PRINT (stderr, *loc);
|
||||
fprintf (stderr, ": %s\n", s);
|
||||
}
|
||||
|
||||
int main (int argc, char const* argv[])
|
||||
{
|
||||
// Enable parse traces on option -p.
|
||||
if (argc == 2 && strcmp(argv[1], "-p") == 0)
|
||||
yydebug = 1;
|
||||
init_table ();
|
||||
return yyparse ();
|
||||
}
|
||||
Reference in New Issue
Block a user