# Simple calculator. -*- Autotest -*- # Copyright (C) 2000-2015, 2018-2022 Free Software Foundation, Inc. # 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 . ## ---------------------------------------------------- ## ## Compile the grammar described in the documentation. ## ## ---------------------------------------------------- ## m4_pushdef([AT_CALC_MAIN], [AT_LANG_DISPATCH([$0], $@)]) m4_pushdef([AT_CALC_YYLEX], [AT_LANG_DISPATCH([$0], $@)]) # -------------- # # AT_DATA_CALC. # # -------------- # # _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES]) # ----------------------------------------------- # Produce 'calc.y' and, if %header was specified, 'calc-lex.c' or # 'calc-lex.cc'. # # Don't call this macro directly, because it contains some occurrences # of '$1' etc. which will be interpreted by m4. So you should call it # with $1, $2, and $3 as arguments, which is what AT_DATA_CALC_Y does. # # When %header is not passed, generate a single self-contained file. # Otherwise, generate three: calc.y with the parser, calc-lex.c with # the scanner, and calc-main.c with "main()". This is in order to # stress the use of the generated parser header. To avoid code # duplication, AT_CALC_YYLEX and AT_CALC_MAIN contain the body of these # two later files. m4_pushdef([_AT_DATA_CALC_Y], [m4_if([$1$2$3], $[1]$[2]$[3], [], [m4_fatal([$0: Invalid arguments: $@])])dnl AT_LANG_DISPATCH([$0], $@)]) ## ----------- ## ## Calc in C. ## ## ----------- ## # AT_CALC_MAIN(c). m4_define([AT_CALC_MAIN(c)], [[#include #include /* exit */ #include /* strcmp */ #include ]AT_CXX_IF([[ namespace { /* A C++ ]AT_NAME_PREFIX[parse that simulates the C signature. */ int ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([semantic_value *result, int *count, int *nerrs]))[ { ]AT_NAME_PREFIX[::parser parser]AT_PARAM_IF([ (result, count, nerrs)])[; #if ]AT_API_PREFIX[DEBUG parser.set_debug_level (1); #endif return parser.parse (); } } ]])[ /* Value of the last computation. */ semantic_value global_result = 0; /* Total number of computations. */ int global_count = 0; /* Total number of errors. */ int global_nerrs = 0; #ifndef EX_NOINPUT # define EX_NOINPUT 66 #endif static FILE * open_file (const char *file) { FILE *res = (file && *file && strcmp (file, "-")) ? fopen (file, "r") : stdin; if (!res) { perror (file); exit (EX_NOINPUT); } return res; } /* A C main function. */ int main (int argc, const char **argv) {]AT_PARAM_IF([[ semantic_value result = 0; int count = 0; int nerrs = 0;]])[ int status = 0; /* This used to be alarm (10), but that isn't enough time for a July 1995 vintage DEC Alphastation 200 4/100 system, according to Nelson H. F. Beebe. 100 seconds was enough for regular users, but the Hydra build farm, which is heavily loaded needs more. */ alarm (200); ]AT_CXX_IF([], [AT_DEBUG_IF([ ]AT_NAME_PREFIX[debug = 1;])])[ { int i; for (i = 1; i < argc; ++i) { ]AT_MULTISTART_IF([[ if (!strcmp (argv[i], "--exp") && i+1 < argc) { input = open_file (argv[i+1]); ignore_eol = 1; ]AT_NAME_PREFIX[parse_exp_t res = ]AT_NAME_PREFIX[parse_exp (); printf ("exp => %d (status: %d, errors: %d)\n", res.yystatus == 0 ? res.yyvalue : 0, res.yystatus, res.yynerrs); status = res.yystatus; ++i; } else if (!strcmp (argv[i], "--num") && i+1 < argc) { input = open_file (argv[i+1]); ignore_eol = 1; ]AT_NAME_PREFIX[parse_NUM_t res = ]AT_NAME_PREFIX[parse_NUM (); printf ("NUM => %d (status: %d, errors: %d)\n", res.yystatus == 0 ? res.yyvalue : 0, res.yystatus, res.yynerrs); status = res.yystatus; ++i; } else]])[ { input = open_file (argv[i]); status = ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([[&result, &count, &nerrs]])[); } if (input != stdin && fclose (input)) perror ("fclose"); } } ]AT_PARAM_IF([[ assert (global_result == result); (void) result; assert (global_count == count); (void) count; assert (global_nerrs == nerrs); (void) nerrs; printf ("final: %d %d %d\n", global_result, global_count, global_nerrs);]])[ return status; } ]]) # AT_CALC_YYLEX(c). m4_define([AT_CALC_YYLEX(c)], [[#include ]AT_YYLEX_DECLARE_EXTERN[ ]AT_LOCATION_IF([ static AT_YYLTYPE last_yylloc; ])[ static int get_char (]AT_YYLEX_FORMALS[) { int res = getc (input); ]AT_USE_LEX_ARGS[; ]AT_LOCATION_IF([ last_yylloc = AT_LOC; if (res == '\n') { AT_LOC_LAST_LINE++; AT_LOC_LAST_COLUMN = 1; } else AT_LOC_LAST_COLUMN++; ])[ return res; } static void unget_char (]AT_YYLEX_PRE_FORMALS[ int c) { ]AT_USE_LEX_ARGS[; ]AT_LOCATION_IF([ /* Wrong when C == '\n'. */ AT_LOC = last_yylloc; ])[ ungetc (c, input); } static int read_integer (]AT_YYLEX_FORMALS[) { int c = get_char (]AT_YYLEX_ARGS[); int res = 0; ]AT_USE_LEX_ARGS[; while (isdigit (c)) { res = 10 * res + (c - '0'); c = get_char (]AT_YYLEX_ARGS[); } unget_char (]AT_YYLEX_PRE_ARGS[ c); return res; } /*---------------------------------------------------------------. | Lexical analyzer returns an integer on the stack and the token | | NUM, or the ASCII character read if not a number. Skips all | | blanks and tabs, returns 0 for EOF. | `---------------------------------------------------------------*/ ]AT_YYLEX_PROTOTYPE[ { int c; /* Skip white spaces. */ do { ]AT_LOCATION_IF([ AT_LOC_FIRST_COLUMN = AT_LOC_LAST_COLUMN; AT_LOC_FIRST_LINE = AT_LOC_LAST_LINE; ])[ } while ((c = get_char (]AT_YYLEX_ARGS[)) == ' ' || c == '\t' || (ignore_eol && c == '\n')); /* Process numbers. */ if (isdigit (c)) { unget_char (]AT_YYLEX_PRE_ARGS[ c); ]AT_VAL[.]AT_VALUE_UNION_IF([NUM], [ival])[ = read_integer (]AT_YYLEX_ARGS[); return ]AT_TOKEN([NUM])[; } /* Return end-of-file. */ if (c == EOF) return ]AT_TOKEN([CALC_EOF])[; /* An explicit error raised by the scanner. */ if (c == '#') {]AT_LOCATION_IF([ fprintf (stderr, "%d.%d: ", AT_LOC_FIRST_LINE, AT_LOC_FIRST_COLUMN);])[ fputs ("syntax error: invalid character: '#'\n", stderr); return ]AT_TOKEN(AT_API_PREFIX[][error])[; } /* Return single chars. */ return c; } ]]) m4_define([_AT_DATA_CALC_Y(c)], [AT_DATA_GRAMMAR([calc.y.tmp], [[/* Infix notation calculator--calc */ ]$4[ %code requires { ]AT_LOCATION_TYPE_SPAN_IF([[ typedef struct { int l; int c; } Point; typedef struct { Point first; Point last; } Span; # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (N) \ { \ (Current).first = YYRHSLOC (Rhs, 1).first; \ (Current).last = YYRHSLOC (Rhs, N).last; \ } \ else \ { \ (Current).first = (Current).last = YYRHSLOC (Rhs, 0).last; \ } \ while (0) ]AT_C_IF( [[#include void location_print (FILE *o, Span s); #define LOCATION_PRINT location_print ]])[ ]])[ /* Exercise pre-prologue dependency to %union. */ typedef int semantic_value; } ]AT_VALUE_UNION_IF([], [[/* Exercise %union. */ %union { semantic_value ival; };]])[ %printer { ]AT_CXX_IF([[yyo << $$]], [[fprintf (yyo, "%d", $$)]])[; } <]AT_VALUE_UNION_IF([int], [ival])[>; %code provides { #include /* The input. */ extern FILE *input; /* Whether \n is a blank. */ extern int ignore_eol; extern semantic_value global_result; extern int global_count; extern int global_nerrs; } %code { #include #include #define USE(Var) FILE *input; int ignore_eol = 0; static int power (int base, int exponent); ]AT_YYERROR_DECLARE[ ]AT_YYLEX_DECLARE_EXTERN[ ]AT_TOKEN_TRANSLATE_IF([[ #define N_ static const char * _ (const char *cp) { if (strcmp (cp, "end of input") == 0) return "end of file"; else if (strcmp (cp, "number") == 0) return "nombre"; else return cp; } ]])[ } ]AT_LOCATION_TYPE_SPAN_IF([[ %initial-action { @$.first.l = @$.first.c = 1; @$.last = @$.first; }]])[ /* Bison Declarations */ %token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[ %token <]AT_VALUE_UNION_IF([int], [ival])[> NUM "number" %type <]AT_VALUE_UNION_IF([int], [ival])[> exp %nonassoc '=' /* comparison */ %left '-' '+' %left '*' '/' %precedence NEG /* negation--unary minus */ %right '^' /* exponentiation */ /* Grammar follows */ %% input: line | input line { ]AT_PARAM_IF([++*count; ++global_count;])[ } ; line: '\n' | exp '\n' { ]AT_PARAM_IF([*result = global_result = $1;], [USE ($1);])[ } ; exp: NUM | exp '=' exp { if ($1 != $3)]AT_LANG_CASE( [c], [[ { char buf[1024]; snprintf (buf, sizeof buf, "error: %d != %d", $1, $3);]AT_YYERROR_ARG_LOC_IF([[ yyerror (&@$, ]AT_PARAM_IF([result, count, nerrs, ])[buf);]], [[ { YYLTYPE old_yylloc = yylloc; yylloc = @$; yyerror (]AT_PARAM_IF([result, count, nerrs, ])[buf); yylloc = old_yylloc; } ]])[ }]], [c++], [[ { char buf[1024]; snprintf (buf, sizeof buf, "error: %d != %d", $1, $3); ]AT_GLR_IF([[yyparser.]])[error (]AT_LOCATION_IF([[@$, ]])[buf); }]])[ $$ = $1; } | exp '+' exp { $$ = $1 + $3; } | exp '-' exp { $$ = $1 - $3; } | exp '*' exp { $$ = $1 * $3; } | exp '/' exp { if ($3 == 0)]AT_LANG_CASE( [c], [[ {]AT_YYERROR_ARG_LOC_IF([[ yyerror (&@3, ]AT_PARAM_IF([result, count, nerrs, ])["error: null divisor");]], [[ { YYLTYPE old_yylloc = yylloc; yylloc = @3; yyerr][or (]AT_PARAM_IF([result, count, nerrs, ])["error: null divisor"); yylloc = old_yylloc; } ]])[ }]], [c++], [[ { ]AT_GLR_IF([[yyparser.]])[err][or (]AT_LOCATION_IF([[@3, ]])["error: null divisor"); }]])[ else $$ = $1 / $3; } | '-' exp %prec NEG { $$ = -$2; } | exp '^' exp { $$ = power ($1, $3); } | '(' exp ')' { $$ = $2; } | '(' error ')' { $$ = 1111; yyerrok; } | '-' error { $$ = 0; YYERROR; } | '!' '!' { $$ = 0; YYERROR; } | '!' '+' { $$ = 0; YYACCEPT; } | '!' '-' { $$ = 0; YYABORT; }]AT_C_IF([[ | '!' '*' { $$ = 0; YYNOMEM; }]])[ ; %% int power (int base, int exponent) { int res = 1; assert (0 <= exponent); for (/* Niente */; exponent; --exponent) res *= base; return res; } ]AT_LOCATION_TYPE_SPAN_IF([AT_CXX_IF([[ #include namespace { std::ostream& operator<< (std::ostream& o, const Span& s) { o << s.first.l << '.' << s.first.c; if (s.first.l != s.last.l) o << '-' << s.last.l << '.' << s.last.c - 1; else if (s.first.c != s.last.c - 1) o << '-' << s.last.c - 1; return o; } } ]], [[ void location_print (FILE *o, Span s) { fprintf (o, "%d.%d", s.first.l, s.first.c); if (s.first.l != s.last.l) fprintf (o, "-%d.%d", s.last.l, s.last.c - 1); else if (s.first.c != s.last.c - 1) fprintf (o, "-%d", s.last.c - 1); } ]])])[ ]AT_YYERROR_DEFINE[ ]AT_HEADER_IF([], [AT_CALC_YYLEX AT_CALC_MAIN])]) # Remove the generated prototypes. AT_CHECK( [AT_YACC_IF([[ if "$POSIXLY_CORRECT_IS_EXPORTED"; then sed -e '/\/\* !POSIX \*\//d' calc.y.tmp >calc.y else mv calc.y.tmp calc.y fi ]], [[mv calc.y.tmp calc.y]]) ]) AT_HEADER_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT], [[#include "calc.]AT_LANG_HDR[" ]AT_CALC_YYLEX]) AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT], [[#include "calc.]AT_LANG_HDR[" ]AT_CALC_MAIN]) ]) ])# _AT_DATA_CALC_Y(c) ## ------------- ## ## Calc in C++. ## ## ------------- ## m4_copy([AT_CALC_MAIN(c)], [AT_CALC_MAIN(c++)]) m4_copy([AT_CALC_YYLEX(c)], [AT_CALC_YYLEX(c++)]) m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)]) ## ----------- ## ## Calc in D. ## ## ----------- ## # AT_YYLEX_RETURN_VAL # ------------------- # Produce the return value for yylex(). m4_define([AT_YYLEX_RETURN_VAL], [return dnl AT_TOKEN_CTOR_IF( [[Symbol.]AT_TOKEN_PREFIX[$1](m4_ifval([$2], [$2])[]AT_LOCATION_IF([m4_ifval([$2], [, ])[location]])[);]], [[Symbol(TokenKind.]AT_TOKEN_PREFIX[$1]m4_ifval([$2], [, $2])[]AT_LOCATION_IF([[, location]])[);]])] ) # AT_CALC_MAIN(d). m4_define([AT_CALC_MAIN(d)], [[int main (string[] args) {]AT_PARAM_IF([[ semantic_value result = 0; int count = 0;]])[ File input = args.length == 2 ? File (args[1], "r") : stdin; auto l = calcLexer (input); auto p = new YYParser (l);]AT_DEBUG_IF([[ p.setDebugLevel (1);]])[ return !p.parse(); } ]]) m4_define([AT_CALC_YYLEX(d)], [[import std.range.primitives; import std.stdio; auto calcLexer(R)(R range) if (isInputRange!R && is (ElementType!R : dchar)) { return new CalcLexer!R(range); } auto calcLexer (File f) { import std.algorithm : map, joiner; import std.utf : byDchar; return f.byChunk(1024) // avoid making a syscall roundtrip per char .map!(chunk => cast(char[]) chunk) // because byChunk returns ubyte[] .joiner // combine chunks into a single virtual range of char .calcLexer; // forward to other overload } class CalcLexer(R) : Lexer if (isInputRange!R && is (ElementType!R : dchar)) { R input; this(R r) { input = r; } ]AT_YYERROR_DEFINE[ ]AT_LOCATION_IF([[ Location location; ]])[ int parseInt () { auto res = 0; import std.uni : isNumber; while (input.front.isNumber) { res = res * 10 + (input.front - '0');]AT_LOCATION_IF([[ location.end.column += 1;]])[ input.popFront; } return res; } Symbol yylex () {]AT_LOCATION_IF([[ location.step();]])[ import std.uni : isWhite, isNumber; // Skip initial spaces while (!input.empty && input.front != '\n' && isWhite (input.front)) { input.popFront;]AT_LOCATION_IF([[ location.end.column += 1;]])[ }]AT_LOCATION_IF([[ location.step();]])[ // EOF. if (input.empty) ]AT_YYLEX_RETURN_VAL([EOF])[ // Numbers. if (input.front.isNumber) ]AT_YYLEX_RETURN_VAL([NUM], [parseInt])[ // Individual characters auto c = input.front;]AT_LOCATION_IF([[ if (c == '\n') { location.end.line += 1; location.end.column = 1; } else location.end.column += 1;]])[ input.popFront; // An explicit error raised by the scanner. */ if (c == '#') { stderr.writeln (]AT_LOCATION_IF([location, ": ", ])["syntax error: invalid character: '#'"); ]AT_YYLEX_RETURN_VAL([YYerror])[ } switch (c) { case '+': ]AT_YYLEX_RETURN_VAL([PLUS])[ case '-': ]AT_YYLEX_RETURN_VAL([MINUS])[ case '*': ]AT_YYLEX_RETURN_VAL([STAR])[ case '/': ]AT_YYLEX_RETURN_VAL([SLASH])[ case '(': ]AT_YYLEX_RETURN_VAL([LPAR])[ case ')': ]AT_YYLEX_RETURN_VAL([RPAR])[ case '\n': ]AT_YYLEX_RETURN_VAL([EOL])[ case '=': ]AT_YYLEX_RETURN_VAL([EQUAL])[ case '^': ]AT_YYLEX_RETURN_VAL([POW])[ case '!': ]AT_YYLEX_RETURN_VAL([NOT])[ default: ]AT_YYLEX_RETURN_VAL([YYUNDEF])[ } } } ]]) m4_define([_AT_DATA_CALC_Y(d)], [AT_DATA_GRAMMAR([calc.y], [[/* Infix notation calculator--calc */ ]$4[ %code imports { alias semantic_value = int; } /* Exercise %union. */ ]AT_UNION_IF([[]], [[%union { semantic_value ival; };]])[ %printer { yyo.write($$); } <]AT_UNION_IF([[int]], [[ival]])[>; %code { ]AT_TOKEN_TRANSLATE_IF([[ static string _(string s) { switch (s) { case "end of input": return "end of file"; case "number": return "nombre"; default: return s; } } ]])[ } /* Bison Declarations */ %token EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[ %token <]AT_UNION_IF([[int]], [[ival]])[> NUM "number" %type <]AT_UNION_IF([[int]], [[ival]])[> exp %token EQUAL "=" MINUS "-" PLUS "+" STAR "*" SLASH "/" POW "^" EOL "'\\n'" LPAR "(" RPAR ")" NOT "!" %nonassoc "=" /* comparison */ %left "-" "+" %left "*" "/" %precedence NEG /* negation--unary minus */ %right "^" /* exponentiation */ /* Grammar follows */ %% input: line | input line { ]AT_PARAM_IF([++*count; ++global_count;])[ } ; line: EOL | exp EOL { ]AT_PARAM_IF([*result = global_result = $1;])[ } ; exp: NUM | exp "=" exp { if ($1 != $3) yyerror (]AT_LOCATION_IF([[@$, ]])[format ("error: %d != %d", $1, $3)); $$ = $1; } | exp "+" exp { $$ = $1 + $3; } | exp "-" exp { $$ = $1 - $3; } | exp "*" exp { $$ = $1 * $3; } | exp "/" exp { if ($3 == 0) yyerror (]AT_LOCATION_IF([[@3, ]])["error: null divisor"); else $$ = $1 / $3; } | "-" exp %prec NEG { $$ = -$2; } | exp "^" exp { $$ = power ($1, $3); } | "(" exp ")" { $$ = $2; } | "(" error ")" { $$ = 1111; yyerrok(); } | "-" error { $$ = 0; return YYERROR; } | "!" "!" { $$ = 0; return YYERROR; } | "!" "+" { $$ = 0; return YYACCEPT; } | "!" "-" { $$ = 0; return YYABORT; } ; %% int power (int base, int exponent) { int res = 1; assert (0 <= exponent); for (/* Niente */; exponent; --exponent) res *= base; return res; } ]AT_CALC_YYLEX[ ]AT_CALC_MAIN]) ])# _AT_DATA_CALC_Y(d) ## -------------- ## ## Calc in Java. ## ## -------------- ## m4_define([AT_CALC_MAIN(java)], [[public static void main (String[] args) throws IOException {]AT_LEXPARAM_IF([[ Calc p = new Calc (System.in);]], [[ CalcLexer l = new CalcLexer (System.in); Calc p = new Calc (l);]])AT_DEBUG_IF([[ p.setDebugLevel (1);]])[ boolean success = p.parse (); if (!success) System.exit (1); } ]]) m4_define([AT_CALC_YYLEX(java)], [AT_LEXPARAM_IF([[%code lexer {]], [[%code epilogue { class CalcLexer implements Calc.Lexer {]])[ StreamTokenizer st;]AT_LOCATION_IF([[ PositionReader reader;]])[ public ]AT_LEXPARAM_IF([[YYLexer]], [[CalcLexer]])[ (InputStream is) {]AT_LOCATION_IF([[ reader = new PositionReader (new InputStreamReader (is)); st = new StreamTokenizer (reader);]], [[ st = new StreamTokenizer (new InputStreamReader (is));]])[ st.resetSyntax (); st.eolIsSignificant (true); st.wordChars ('0', '9'); } ]AT_LOCATION_IF([[ Position start = new Position (1, 0); Position end = new Position (1, 0); public Position getStartPos () { return new Position (start); } public Position getEndPos () { return new Position (end); } ]])[ ]AT_YYERROR_DEFINE[ Integer yylval; public Object getLVal () { return yylval; } public int yylex() throws IOException {;]AT_LOCATION_IF([[ start.set(reader.getPosition());]])[ int tkind = st.nextToken();]AT_LOCATION_IF([[ end.set(reader.getPosition());]])[ switch (tkind) { case StreamTokenizer.TT_EOF: return CALC_EOF; case StreamTokenizer.TT_EOL:;]AT_LOCATION_IF([[ end.line += 1; end.column = 0;]])[ return (int) '\n'; case StreamTokenizer.TT_WORD: yylval = Integer.parseInt(st.sval);]AT_LOCATION_IF([[ end.set(reader.getPreviousPosition());]])[ return NUM; case ' ': case '\t': return yylex(); case '#': System.err.println(]AT_LOCATION_IF([[start + ": " + ]])["syntax error: invalid character: '#'"); return YYerror; default: return tkind; } } ]AT_LEXPARAM_IF([], [[}]])[ }; ]]) m4_define([_AT_DATA_CALC_Y(java)], [AT_DATA_GRAMMAR([Calc.y], [[/* Infix notation calculator--calc */ %define api.prefix {Calc} %define api.parser.class {Calc} %define public ]$4[ %code imports {]AT_LOCATION_IF([[ import java.io.BufferedReader;]])[ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StreamTokenizer; } %code { ]AT_CALC_MAIN[ ]AT_TOKEN_TRANSLATE_IF([[ static String i18n(String s) { if (s.equals ("end of input")) return "end of file"; else if (s.equals ("number")) return "nombre"; else return s; } ]])[ } /* Bison Declarations */ %token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[ %token NUM "number" %type exp %nonassoc '=' /* comparison */ %left '-' '+' %left '*' '/' %precedence NEG /* negation--unary minus */ %right '^' /* exponentiation */ /* Grammar follows */ %% input: line | input line ; line: '\n' | exp '\n' ; exp: NUM | exp '=' exp { if ($1.intValue () != $3.intValue ()) yyerror (]AT_LOCATION_IF([[@$, ]])["error: " + $1 + " != " + $3); } | exp '+' exp { $$ = $1 + $3; } | exp '-' exp { $$ = $1 - $3; } | exp '*' exp { $$ = $1 * $3; } | exp '/' exp { if ($3.intValue () == 0) yyerror (]AT_LOCATION_IF([[@3, ]])["error: null divisor"); else $$ = $1 / $3; } | '-' exp %prec NEG { $$ = -$2; } | exp '^' exp { $$ = (int) Math.pow ($1, $3); } | '(' exp ')' { $$ = $2; } | '(' error ')' { $$ = 1111; } | '-' error { $$ = 0; return YYERROR; } | '!' '!' { $$ = 0; return YYERROR; } | '!' '+' { $$ = 0; return YYACCEPT; } | '!' '-' { $$ = 0; return YYABORT; } ; ]AT_CALC_YYLEX[ ]AT_LOCATION_IF([[ %% ]AT_JAVA_POSITION_DEFINE])[ ]]) ])# _AT_DATA_JAVA_CALC_Y ## ------------------ ## ## Calculator tests. ## ## ------------------ ## # AT_DATA_CALC_Y([BISON-OPTIONS]) # ------------------------------- # Produce 'calc.y' and, if %header was specified, 'calc-lex.c' or # 'calc-lex.cc'. m4_define([AT_DATA_CALC_Y], [_AT_DATA_CALC_Y($[1], $[2], $[3], [$1]) ]) # _AT_CHECK_CALC(CALC-OPTIONS, INPUT, [STDOUT], [NUM-STDERR-LINES]) # ----------------------------------------------------------------- # Run 'calc' on INPUT and expect no STDOUT nor STDERR. # # If BISON-OPTIONS contains '%debug' but not '%glr-parser', then # NUM-STDERR-LINES is the number of expected lines on stderr. # Currently this is ignored, though, since the output format is fluctuating. # # We don't count GLR's traces yet, since its traces are somewhat # different from LALR's. Likewise for D. # # The push traces are the same, except for "Return for a new token", don't # count them. m4_define([_AT_CHECK_CALC], [AT_DATA([[input]], [$2 ]) echo "input:" sed -e 's/^/ | /' at-stderr mv at-stderr stderr # 2. Create the reference error message. AT_DATA([[expout]], [m4_n([$6])]) # 3. If locations are not used, remove them. AT_YYERROR_SEES_LOC_IF([], [[sed 's/^[-0-9.]*: //' expout >at-expout mv at-expout expout]]) # 4. If parse.error is not custom, turn the expected message to # the traditional one. AT_ERROR_CUSTOM_IF([], [ AT_PERL_REQUIRE([[-pi -e 'use strict; s{syntax error on token \[(.*?)\] \(expected: (.*)\)} { my $unexp = $][1; my @exps = $][2 =~ /\[(.*?)\]/g;]AT_D_IF([[ # In the case of D, there are no single quotes around the symbols. $unexp =~ s/'"'(.)'"'/$][1/g; s/'"'(.)'"'/$][1/g for @exps;]])[ ($][#exps && $][#exps < 4) ? "syntax error, unexpected $unexp, expecting @{[join(\" or \", @exps)]}" : "syntax error, unexpected $unexp"; }eg ' expout]]) ]) # 5. If parse.error is simple, strip the', unexpected....' part. AT_ERROR_SIMPLE_IF( [[sed 's/syntax error, .*$/syntax error/' expout >at-expout mv at-expout expout]]) # 6. Actually check. AT_CHECK([cat stderr], 0, [expout]) ]) # AT_CHECK_SPACES([FILES]) # ------------------------ # Make sure we did not introduce bad spaces. Checked here because all # the skeletons are (or should be) exercised here. m4_define([AT_CHECK_SPACES], [AT_PERL_CHECK([-ne ' chomp; print "$ARGV:$.: {$_}\n" if (# No starting/ending empty lines. (eof || $. == 1) && /^\s*$/ # No trailing space. || /\s$/ # No tabs. || /\t/ )' $1 ]) ]) # AT_CHECK_JAVA_GREP(FILE, [LINE], [COUNT=1]) # ------------------------------------------- # Check that FILE contains exactly COUNT lines matching ^LINE$ # with grep. Unquoted so that COUNT can be a shell expression. m4_define([AT_CHECK_JAVA_GREP], [AT_CHECK_UNQUOTED([grep -c '^$2$' $1], [ignore], [m4_default([$3], [1]) ])]) # AT_CHECK_CALC([BISON-OPTIONS], [COMPILER-OPTIONS]) # -------------------------------------------------- # Start a testing chunk which compiles 'calc' grammar with # BISON-OPTIONS, and performs several tests over the parser. m4_define([AT_CHECK_CALC], [m4_ifval([$3], [m4_fatal([$0: expected at most two arguments])]) # We use integers to avoid dependencies upon the precision of doubles. AT_SETUP([Calculator $1 $2]) AT_BISON_OPTION_PUSHDEFS([$1]) AT_DATA_CALC_Y([$1]) AT_FULL_COMPILE(AT_JAVA_IF([[Calc]], [[calc]]), AT_HEADER_IF([[lex], [main]], [[], []]), [$2], [-Wno-deprecated]) AT_YACC_C_IF( [# No direct calls to malloc/free. AT_CHECK([[$EGREP '(malloc|free) *\(' calc.[ch] | $EGREP -v 'INFRINGES ON USER NAME SPACE']], [1])]) AT_PUSH_IF([AT_JAVA_IF( [# Verify that this is a push parser. AT_CHECK_JAVA_GREP([[Calc.java]], [[.*public void push_parse_initialize ().*]])])]) AT_CHECK_SPACES([AT_JAVA_IF([Calc], [calc]).AT_LANG_EXT AT_HEADER_IF([AT_JAVA_IF([Calc], [calc]).AT_LANG_HDR])]) # Test the precedences. # The Java traces do not show the clean up sequence at the end, # since it does not support %destructor. _AT_CHECK_CALC([], [[1 + 2 * 3 = 7 1 + 2 * -3 = -5 -1^2 = -1 (-1)^2 = 1 ---1 = -1 1 - 2 - 3 = -4 1 - (2 - 3) = 2 2^2^3 = 256 (2^2)^3 = 64]], [AT_PARAM_IF([final: 64 12 0])], [AT_JAVA_IF([1014], [1017])]) # Some syntax errors. _AT_CHECK_CALC_ERROR([$1], [1], [1 2], [AT_PARAM_IF([final: 0 0 1])], [15], [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]]) _AT_CHECK_CALC_ERROR([$1], [1], [1//2], [AT_PARAM_IF([final: 0 0 1])], [20], [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token ['/'] (expected: [number] ['-'] ['('] ['!'])]]) _AT_CHECK_CALC_ERROR([$1], [1], [error], [AT_PARAM_IF([final: 0 0 1])], [5], [AT_JAVA_IF([1.1-1.2], [1.1])[: syntax error on token [invalid token] (expected: [number] ['-'] ['\n'] ['('] ['!'])]]) _AT_CHECK_CALC_ERROR([$1], [1], [1 = 2 = 3], [AT_PARAM_IF([final: 0 0 1])], [30], [AT_LAC_IF( [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]], [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'])]])]) _AT_CHECK_CALC_ERROR([$1], [1], [ +1], [AT_PARAM_IF([final: 0 0 1])], [20], [AT_JAVA_IF([2.1-2.2], [2.1])[: syntax error on token ['+'] (expected: ]AT_TOKEN_TRANSLATE_IF([[[end of file]]], [[[end of input]]])[ [number] ['-'] ['\n'] ['('] ['!'])]]) # Exercise error messages with EOF: work on an empty file. _AT_CHECK_CALC_ERROR([$1], [1], [/dev/null], [AT_PARAM_IF([final: 0 0 1])], [4], [[1.1: syntax error on token ]AT_TOKEN_TRANSLATE_IF([[[end of file]]], [[[end of input]]])[ (expected: [number] ['-'] ['\n'] ['('] ['!'])]]) # Exercise the error token: without it, we die at the first error, # hence be sure to # # - have several errors which exercise different shift/discardings # - (): nothing to pop, nothing to discard # - (1 + 1 + 1 +): a lot to pop, nothing to discard # - (* * *): nothing to pop, a lot to discard # - (1 + 2 * *): some to pop and discard # # - test the action associated to 'error' # # - check the lookahead that triggers an error is not discarded # when we enter error recovery. Below, the lookahead causing the # first error is ")", which is needed to recover from the error and # produce the "0" that triggers the "0 != 1" error. # _AT_CHECK_CALC_ERROR([$1], [0], [() + (1 + 1 + 1 +) + (* * *) + (1 * 2 * *) = 1], [AT_PARAM_IF([final: 4444 0 5])], [250], [AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!']) ]AT_JAVA_IF([1.18-1.19], [1.18])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!']) ]AT_JAVA_IF([1.23-1.24], [1.23])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) ]AT_JAVA_IF([1.41-1.42], [1.41])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) ]AT_JAVA_IF([1.1-1.47], [1.1-46])[: error: 4444 != 1]]) # The same, but this time exercising explicitly triggered syntax errors. # POSIX says the lookahead causing the error should not be discarded. _AT_CHECK_CALC_ERROR([$1], [0], [(!!) + (1 2) = 1], [AT_PARAM_IF([final: 2222 0 2])], [102], [AT_JAVA_IF([1.11-1.12], [1.11])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')']) ]AT_JAVA_IF([1.1-1.17], [1.1-16])[: error: 2222 != 1]]) _AT_CHECK_CALC_ERROR([$1], [0], [(- *) + (1 2) = 1], [AT_PARAM_IF([final: 2222 0 3])], [113], [AT_JAVA_IF([1.4-1.5], [1.4])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) ]AT_JAVA_IF([1.12-1.13], [1.12])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')']) ]AT_JAVA_IF([1.1-1.18], [1.1-17])[: error: 2222 != 1]]) # Check that yyerrok works properly: second error is not reported, # third and fourth are. Parse status is successful. _AT_CHECK_CALC_ERROR([$1], [0], [(* *) + (*) + (*)], [AT_PARAM_IF([final: 3333 0 3])], [113], [AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) ]AT_JAVA_IF([1.10-1.11], [1.10])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) ]AT_JAVA_IF([1.16-1.17], [1.16])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])]]) # Special actions. # ---------------- # !+ => YYACCEPT, !- => YYABORT, !! => YYERROR, !* => YYNOMEM. # YYACCEPT. # Java lacks the traces at the end for cleaning the stack # -Stack now 0 8 20 # -Cleanup: popping token '+' (1.1: ) # -Cleanup: popping nterm exp (1.1: 7) _AT_CHECK_CALC([], [1 + 2 * 3 + !+ ++], [AT_PARAM_IF([final: 0 0 0])], [AT_JAVA_IF([77], [80])]) # YYABORT. _AT_CHECK_CALC_ERROR([$1], [1], [1 + 2 * 3 + !- ++], [AT_PARAM_IF([final: 0 0 0])], [102]) AT_C_IF( [# YYNOMEM. _AT_CHECK_CALC_ERROR([$1], [2], [1 + 2 * 3 + !* ++], [AT_PARAM_IF([final: 0 0 1])], [102], [1.14: memory exhausted])]) # YYerror. # -------- # Check that returning YYerror from the scanner properly enters # error-recovery without issuing a second error message. _AT_CHECK_CALC_ERROR([$1], [0], [(#) + (#) = 2222], [AT_PARAM_IF([final: 2222 0 0])], [102], [[1.2: syntax error: invalid character: '#' 1.8: syntax error: invalid character: '#']]) _AT_CHECK_CALC_ERROR([$1], [0], [(1 + #) = 1111], [AT_PARAM_IF([final: 1111 0 0])], [102], [[1.6: syntax error: invalid character: '#']]) _AT_CHECK_CALC_ERROR([$1], [0], [(# + 1) = 1111], [AT_PARAM_IF([final: 1111 0 0])], [102], [[1.2: syntax error: invalid character: '#']]) _AT_CHECK_CALC_ERROR([$1], [0], [(1 + # + 1) = 1111], [AT_PARAM_IF([final: 1111 0 0])], [102], [[1.6: syntax error: invalid character: '#']]) _AT_CHECK_CALC_ERROR([$1], [0], [(1 + 1) / (1 - 1)], [AT_PARAM_IF([final: 2 0 1])], [102], [AT_JAVA_IF([1.11-1.18], [1.11-17])[: error: null divisor]]) # Multiple start symbols. AT_MULTISTART_IF([ _AT_CHECK_CALC([--num], [[123]], [[NUM => 123 (status: 0, errors: 0)]], [AT_JAVA_IF([1014], [1017])]) _AT_CHECK_CALC_ERROR([$1], [1], [1 + 2 * 3], [NUM => 0 (status: 1, errors: 1)], [102], [[1.3: syntax error, unexpected '+', expecting end of file]], [--num]) _AT_CHECK_CALC([--exp], [[1 + 2 * 3]], [[exp => 7 (status: 0, errors: 0)]], [AT_JAVA_IF([1014], [1017])]) ]) AT_BISON_OPTION_POPDEFS AT_CLEANUP ])# AT_CHECK_CALC # ----------------- # # LALR Calculator. # # ----------------- # AT_BANNER([[LALR(1) Calculator.]]) # AT_CHECK_CALC_LALR([BISON-OPTIONS]) # ----------------------------------- # Start a testing chunk which compiles 'calc' grammar with # BISON-OPTIONS, and performs several tests over the parser. m4_define([AT_CHECK_CALC_LALR], [AT_CHECK_CALC($@)]) AT_CHECK_CALC_LALR([%define parse.trace]) AT_CHECK_CALC_LALR([%header]) AT_CHECK_CALC_LALR([%debug %locations]) AT_CHECK_CALC_LALR([%locations %define api.location.type {Span}]) AT_CHECK_CALC_LALR([%name-prefix "calc"]) AT_CHECK_CALC_LALR([%verbose]) AT_CHECK_CALC_LALR([%yacc]) AT_CHECK_CALC_LALR([%define parse.error detailed]) AT_CHECK_CALC_LALR([%define parse.error verbose]) AT_CHECK_CALC_LALR([%define api.pure full %locations]) AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %locations]) AT_CHECK_CALC_LALR([%define parse.error detailed %locations]) AT_CHECK_CALC_LALR([%define parse.error detailed %locations %header %define api.prefix {calc} %verbose %yacc]) AT_CHECK_CALC_LALR([%define parse.error detailed %locations %header %name-prefix "calc" %define api.token.prefix {TOK_} %verbose %yacc]) AT_CHECK_CALC_LALR([%debug]) AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %header %name-prefix "calc" %verbose %yacc]) AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc]) AT_CHECK_CALC_LALR([%define api.pure full %define parse.error detailed %debug %locations %header %name-prefix "calc" %verbose %yacc]) AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc]) AT_CHECK_CALC_LALR([%define api.pure %define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR([%no-lines %define api.pure %define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR([%no-lines %define api.pure %define parse.error verbose %debug %locations %header %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR([%no-lines %define api.pure %define parse.error verbose %debug %locations %defines %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}]) # parse.error custom. AT_CHECK_CALC_LALR([%define parse.error custom]) AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc}]) AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs} %define api.push-pull both %define api.pure full]) AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs} %define api.push-pull both %define api.pure full %define parse.lac full]) # multistart. AT_CHECK_CALC_LALR([%start input exp NUM %define api.value.type union]) AT_CHECK_CALC_LALR([%start input exp NUM %define api.value.type union %locations %define parse.error detailed]) # ---------------- # # GLR Calculator. # # ---------------- # AT_BANNER([[GLR Calculator.]]) m4_define([AT_CHECK_CALC_GLR], [AT_CHECK_CALC([%glr-parser] $@)]) AT_CHECK_CALC_GLR() AT_CHECK_CALC_GLR([%header]) AT_CHECK_CALC_GLR([%locations]) AT_CHECK_CALC_GLR([%locations %define api.location.type {Span}]) AT_CHECK_CALC_GLR([%name-prefix "calc"]) AT_CHECK_CALC_GLR([%define api.prefix {calc}]) AT_CHECK_CALC_GLR([%verbose]) AT_CHECK_CALC_GLR([%define parse.error verbose]) AT_CHECK_CALC_GLR([%define api.pure %locations]) AT_CHECK_CALC_GLR([%define parse.error verbose %locations]) AT_CHECK_CALC_GLR([%define parse.error custom %locations %header %name-prefix "calc" %verbose]) AT_CHECK_CALC_GLR([%define parse.error custom %locations %header %name-prefix "calc" %verbose %define api.pure]) AT_CHECK_CALC_GLR([%define parse.error detailed %locations %header %name-prefix "calc" %verbose]) AT_CHECK_CALC_GLR([%define parse.error verbose %locations %header %name-prefix "calc" %verbose]) AT_CHECK_CALC_GLR([%define parse.error custom %locations %header %name-prefix "calc" %verbose]) AT_CHECK_CALC_GLR([%debug]) AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %header %name-prefix "calc" %verbose]) AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %header %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose]) AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %header %name-prefix "calc" %verbose]) AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %header %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %header %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_GLR([%no-lines %define api.pure %define parse.error verbose %debug %locations %header %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) # ---------------------- # # LALR1 C++ Calculator. # # ---------------------- # AT_BANNER([[LALR(1) C++ Calculator.]]) # First let's try using %skeleton AT_CHECK_CALC([%skeleton "lalr1.cc" %header]) m4_define([AT_CHECK_CALC_LALR1_CC], [AT_CHECK_CALC([%language "C++" $1], [$2])]) AT_CHECK_CALC_LALR1_CC([]) AT_CHECK_CALC_LALR1_CC([%locations]) AT_CHECK_CALC_LALR1_CC([%locations], [$NO_EXCEPTIONS_CXXFLAGS]) AT_CHECK_CALC_LALR1_CC([%locations %define api.location.type {Span}]) AT_CHECK_CALC_LALR1_CC([%header %locations %define parse.error verbose %name-prefix "calc" %verbose]) AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %define api.prefix {calc} %verbose]) AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %name-prefix "calc" %verbose]) AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %verbose]) AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose]) AT_CHECK_CALC_LALR1_CC([%header %locations %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR1_CC([%define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR1_CC([%header %locations %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR1_CC([%header %locations %define api.location.file none]) AT_CHECK_CALC_LALR1_CC([%header %locations %define api.location.file "my-location.hh"]) AT_CHECK_CALC_LALR1_CC([%no-lines %header %locations %define api.location.file "my-location.hh"]) AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error verbose]) AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error detailed]) AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error detailed %define parse.trace]) AT_CHECK_CALC_LALR1_CC([%define parse.error custom]) AT_CHECK_CALC_LALR1_CC([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR1_CC([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs} %define parse.lac full]) # -------------------- # # GLR C++ Calculator. # # -------------------- # AT_BANNER([[GLR C++ Calculator.]]) # Again, we try also using %skeleton. AT_CHECK_CALC([%skeleton "glr.cc"]) AT_CHECK_CALC([%skeleton "glr2.cc"]) m4_define([AT_CHECK_CALC_GLR_CC], [AT_CHECK_CALC([%language "C++" %glr-parser] $@) # glr.cc AT_CHECK_CALC([%skeleton "glr2.cc"] $@) ]) AT_CHECK_CALC_GLR_CC([]) AT_CHECK_CALC_GLR_CC([%locations]) AT_CHECK_CALC_GLR_CC([%locations %define api.location.type {Span}]) AT_CHECK_CALC_GLR_CC([%header %define parse.error verbose %name-prefix "calc" %verbose]) AT_CHECK_CALC_GLR_CC([%define parse.error verbose %define api.prefix {calc} %verbose]) AT_CHECK_CALC_GLR_CC([%debug]) # parse.error. AT_CHECK_CALC_GLR_CC([%define parse.error detailed %debug %name-prefix "calc" %verbose]) AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %verbose]) AT_CHECK_CALC([%skeleton "glr2.cc" %define parse.error custom %debug %name-prefix "calc" %verbose]) # Only glr2.cc. AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %define api.token.prefix {TOK_} %verbose]) AT_CHECK_CALC_GLR_CC([%locations %header %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_GLR_CC([%locations %header %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_GLR_CC([%no-lines %locations %header %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) # -------------------- # # LALR1 D Calculator. # # -------------------- # AT_BANNER([[LALR(1) D Calculator.]]) # First let's try using %skeleton AT_CHECK_CALC([%skeleton "lalr1.d"]) m4_define([AT_CHECK_CALC_LALR1_D], [AT_CHECK_CALC([%language "D" $1], [$2])]) AT_CHECK_CALC_LALR1_D([]) AT_CHECK_CALC_LALR1_D([%locations]) #AT_CHECK_CALC_LALR1_D([%locations %define api.location.type {Span}]) AT_CHECK_CALC_LALR1_D([%define parse.error detailed %define api.prefix {calc} %verbose]) AT_CHECK_CALC_LALR1_D([%debug]) AT_CHECK_CALC_LALR1_D([%define parse.error custom]) AT_CHECK_CALC_LALR1_D([%locations %define parse.error custom]) AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed]) AT_CHECK_CALC_LALR1_D([%locations %define parse.error simple]) AT_CHECK_CALC_LALR1_D([%define parse.error detailed %debug %verbose]) AT_CHECK_CALC_LALR1_D([%define parse.error detailed %debug %define api.symbol.prefix {SYMB_} %define api.token.prefix {TOK_} %verbose]) AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error detailed]) AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error custom]) AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error detailed %define parse.trace]) #AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed %debug %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) #AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error custom %define api.value.type union]) AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error detailed]) AT_CHECK_CALC_LALR1_D([%define api.push-pull both]) AT_CHECK_CALC_LALR1_D([%define parse.trace %define parse.error custom %locations %define api.push-pull both %define parse.lac full]) # ----------------------- # # LALR1 Java Calculator. # # ----------------------- # AT_BANNER([[LALR(1) Java Calculator.]]) m4_define([AT_CHECK_CALC_LALR1_JAVA], [AT_CHECK_CALC([%language "Java" $1], [$2])]) AT_CHECK_CALC_LALR1_JAVA AT_CHECK_CALC_LALR1_JAVA([%define parse.error custom]) AT_CHECK_CALC_LALR1_JAVA([%define parse.error detailed]) AT_CHECK_CALC_LALR1_JAVA([%define parse.error verbose]) AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error custom]) AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error detailed]) AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error verbose]) AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose]) AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is}]) AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both]) AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both %define parse.error detailed %locations]) AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %lex-param {InputStream is} %define api.push-pull both]) AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is} %define api.push-pull both]) # parse.lac. AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %define parse.lac full]) AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %define api.push-pull both %define parse.lac full]) m4_popdef([AT_CALC_MAIN]) m4_popdef([AT_CALC_YYLEX])