1# Simple calculator. -*- Autotest -*- 2 3# Copyright (C) 2000-2015, 2018-2021 Free Software Foundation, Inc. 4 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18## ---------------------------------------------------- ## 19## Compile the grammar described in the documentation. ## 20## ---------------------------------------------------- ## 21 22# -------------- # 23# AT_CALC_MAIN. # 24# -------------- # 25 26m4_pushdef([AT_CALC_MAIN], [AT_LANG_DISPATCH([$0], $@)]) 27 28# Whether token translation is supported. 29m4_pushdef([AT_TOKEN_TRANSLATE_IF], 30[AT_ERROR_CUSTOM_IF([$1], [AT_ERROR_DETAILED_IF([$1], [$2])])]) 31 32m4_define([AT_CALC_MAIN(c)], 33[[#include <assert.h> 34#include <unistd.h> 35 36]AT_CXX_IF([[ 37namespace 38{ 39 /* A C++ ]AT_NAME_PREFIX[parse that simulates the C signature. */ 40 int 41 ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([semantic_value *result, int *count, int *nerrs]))[ 42 { 43 ]AT_NAME_PREFIX[::parser parser]AT_PARAM_IF([ (result, count, nerrs)])[; 44 #if ]AT_API_PREFIX[DEBUG 45 parser.set_debug_level (1); 46 #endif 47 return parser.parse (); 48 } 49} 50]])[ 51 52/* Value of the last computation. */ 53semantic_value global_result = 0; 54/* Total number of computations. */ 55int global_count = 0; 56/* Total number of errors. */ 57int global_nerrs = 0; 58 59/* A C main function. */ 60int 61main (int argc, const char **argv) 62{]AT_PARAM_IF([[ 63 semantic_value result = 0; 64 int count = 0; 65 int nerrs = 0;]])[ 66 int status; 67 68 /* This used to be alarm (10), but that isn't enough time for a July 69 1995 vintage DEC Alphastation 200 4/100 system, according to 70 Nelson H. F. Beebe. 100 seconds was enough for regular users, 71 but the Hydra build farm, which is heavily loaded needs more. */ 72 73 alarm (200); 74 75 if (argc == 2) 76 input = fopen (argv[1], "r"); 77 else 78 input = stdin; 79 80 if (!input) 81 { 82 perror (argv[1]); 83 return 3; 84 } 85 86]AT_CXX_IF([], [AT_DEBUG_IF([ ]AT_NAME_PREFIX[debug = 1;])])[ 87 status = ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([[&result, &count, &nerrs]])[); 88 if (fclose (input)) 89 perror ("fclose");]AT_PARAM_IF([[ 90 assert (global_result == result); (void) result; 91 assert (global_count == count); (void) count; 92 assert (global_nerrs == nerrs); (void) nerrs; 93 printf ("final: %d %d %d\n", global_result, global_count, global_nerrs);]])[ 94 return status; 95} 96]]) 97 98m4_copy([AT_CALC_MAIN(c)], [AT_CALC_MAIN(c++)]) 99 100m4_define([AT_CALC_MAIN(d)], 101[[int main (string[] args) 102{]AT_PARAM_IF([[ 103 semantic_value result = 0; 104 int count = 0;]])[ 105 106 File input = args.length == 2 ? File (args[1], "r") : stdin; 107 auto l = calcLexer (input); 108 auto p = new YYParser (l);]AT_DEBUG_IF([[ 109 p.setDebugLevel (1);]])[ 110 return !p.parse (); 111} 112]]) 113 114 115m4_define([AT_CALC_MAIN(java)], 116[[public static void main (String[] args) throws IOException 117 {]AT_LEXPARAM_IF([[ 118 Calc p = new Calc (System.in);]], [[ 119 CalcLexer l = new CalcLexer (System.in); 120 Calc p = new Calc (l);]])AT_DEBUG_IF([[ 121 p.setDebugLevel (1);]])[ 122 boolean success = p.parse (); 123 if (!success) 124 System.exit (1); 125 } 126]]) 127 128 129# --------------- # 130# AT_CALC_YYLEX. # 131# --------------- # 132 133m4_pushdef([AT_CALC_YYLEX], [AT_LANG_DISPATCH([$0], $@)]) 134 135 136m4_define([AT_CALC_YYLEX(c)], 137[[#include <ctype.h> 138 139]AT_YYLEX_DECLARE_EXTERN[ 140 141]AT_LOCATION_IF([ 142static AT_YYLTYPE last_yylloc; 143])[ 144static int 145get_char (]AT_YYLEX_FORMALS[) 146{ 147 int res = getc (input); 148 ]AT_USE_LEX_ARGS[; 149]AT_LOCATION_IF([ 150 last_yylloc = AT_LOC; 151 if (res == '\n') 152 { 153 AT_LOC_LAST_LINE++; 154 AT_LOC_LAST_COLUMN = 1; 155 } 156 else 157 AT_LOC_LAST_COLUMN++; 158])[ 159 return res; 160} 161 162static void 163unget_char (]AT_YYLEX_PRE_FORMALS[ int c) 164{ 165 ]AT_USE_LEX_ARGS[; 166]AT_LOCATION_IF([ 167 /* Wrong when C == '\n'. */ 168 AT_LOC = last_yylloc; 169])[ 170 ungetc (c, input); 171} 172 173static int 174read_integer (]AT_YYLEX_FORMALS[) 175{ 176 int c = get_char (]AT_YYLEX_ARGS[); 177 int res = 0; 178 179 ]AT_USE_LEX_ARGS[; 180 while (isdigit (c)) 181 { 182 res = 10 * res + (c - '0'); 183 c = get_char (]AT_YYLEX_ARGS[); 184 } 185 186 unget_char (]AT_YYLEX_PRE_ARGS[ c); 187 188 return res; 189} 190 191 192/*---------------------------------------------------------------. 193| Lexical analyzer returns an integer on the stack and the token | 194| NUM, or the ASCII character read if not a number. Skips all | 195| blanks and tabs, returns 0 for EOF. | 196`---------------------------------------------------------------*/ 197 198]AT_YYLEX_PROTOTYPE[ 199{ 200 int c; 201 /* Skip white spaces. */ 202 do 203 { 204]AT_LOCATION_IF([ 205 AT_LOC_FIRST_COLUMN = AT_LOC_LAST_COLUMN; 206 AT_LOC_FIRST_LINE = AT_LOC_LAST_LINE; 207])[ 208 } 209 while ((c = get_char (]AT_YYLEX_ARGS[)) == ' ' || c == '\t'); 210 211 /* Process numbers. */ 212 if (isdigit (c)) 213 { 214 unget_char (]AT_YYLEX_PRE_ARGS[ c); 215 ]AT_VAL[.ival = read_integer (]AT_YYLEX_ARGS[); 216 return ]AT_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[NUM; 217 } 218 219 /* Return end-of-file. */ 220 if (c == EOF) 221 return ]AT_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[CALC_EOF; 222 223 /* An explicit error raised by the scanner. */ 224 if (c == '#') 225 {]AT_LOCATION_IF([ 226 fprintf (stderr, "%d.%d: ", 227 AT_LOC_FIRST_LINE, AT_LOC_FIRST_COLUMN);])[ 228 fputs ("syntax error: invalid character: '#'\n", stderr); 229 return ]AT_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[]AT_API_PREFIX[error; 230 } 231 232 /* Return single chars. */ 233 return c; 234} 235]]) 236 237m4_copy([AT_CALC_YYLEX(c)], [AT_CALC_YYLEX(c++)]) 238 239m4_define([AT_CALC_YYLEX(d)], 240[[import std.range.primitives; 241import std.stdio; 242 243auto calcLexer(R)(R range) 244 if (isInputRange!R && is (ElementType!R : dchar)) 245{ 246 return new CalcLexer!R(range); 247} 248 249auto calcLexer (File f) 250{ 251 import std.algorithm : map, joiner; 252 import std.utf : byDchar; 253 254 return f.byChunk(1024) // avoid making a syscall roundtrip per char 255 .map!(chunk => cast(char[]) chunk) // because byChunk returns ubyte[] 256 .joiner // combine chunks into a single virtual range of char 257 .calcLexer; // forward to other overload 258} 259 260class CalcLexer(R) : Lexer 261 if (isInputRange!R && is (ElementType!R : dchar)) 262{ 263 R input; 264 265 this(R r) { 266 input = r; 267 } 268 269 ]AT_YYERROR_DEFINE[ 270 271 YYSemanticType semanticVal_;]AT_LOCATION_IF([[ 272 YYLocation location = new YYLocation; 273 274 public final @property YYPosition startPos() 275 { 276 return location.begin; 277 } 278 279 public final @property YYPosition endPos() 280 { 281 return location.end; 282 } 283]])[ 284 public final @property YYSemanticType semanticVal() 285 { 286 return semanticVal_; 287 } 288 289 int parseInt () 290 { 291 auto res = 0; 292 import std.uni : isNumber; 293 while (input.front.isNumber) 294 { 295 res = res * 10 + (input.front - '0');]AT_LOCATION_IF([[ 296 location.end.column += 1;]])[ 297 input.popFront; 298 } 299 return res; 300 } 301 302 int yylex () 303 {]AT_LOCATION_IF([[ 304 location.begin = location.end;]])[ 305 306 import std.uni : isWhite, isNumber; 307 308 // Skip initial spaces 309 while (!input.empty && input.front != '\n' && isWhite (input.front)) 310 { 311 input.popFront;]AT_LOCATION_IF([[ 312 location.begin.column += 1; 313 location.end.column += 1;]])[ 314 } 315 316 // EOF. 317 if (input.empty) 318 return TokenKind.CALC_EOF; 319 320 // Numbers. 321 if (input.front.isNumber) 322 { 323 semanticVal_.ival = parseInt; 324 return TokenKind.NUM; 325 } 326 327 // Individual characters 328 auto c = input.front;]AT_LOCATION_IF([[ 329 if (c == '\n') 330 { 331 location.end.line += 1; 332 location.end.column = 1; 333 } 334 else 335 location.end.column += 1;]])[ 336 input.popFront; 337 338 // An explicit error raised by the scanner. */ 339 if (c == '#') 340 { 341 stderr.writeln (]AT_LOCATION_IF([location, ": ", ])["syntax error: invalid character: '#'"); 342 return TokenKind.YYerror; 343 } 344 345 return c; 346 } 347} 348]]) 349 350 351m4_define([AT_CALC_YYLEX(java)], 352[AT_LEXPARAM_IF([[%code lexer {]], 353 [[%code epilogue { class CalcLexer implements Calc.Lexer {]])[ 354 StreamTokenizer st;]AT_LOCATION_IF([[ 355 PositionReader reader;]])[ 356 357 public ]AT_LEXPARAM_IF([[YYLexer]], [[CalcLexer]])[ (InputStream is) 358 {]AT_LOCATION_IF([[ 359 reader = new PositionReader (new InputStreamReader (is)); 360 st = new StreamTokenizer (reader);]], [[ 361 st = new StreamTokenizer (new InputStreamReader (is));]])[ 362 st.resetSyntax (); 363 st.eolIsSignificant (true); 364 st.wordChars ('0', '9'); 365 } 366 367]AT_LOCATION_IF([[ 368 Position start = new Position (1, 0); 369 Position end = new Position (1, 0); 370 371 public Position getStartPos () { 372 return new Position (start); 373 } 374 375 public Position getEndPos () { 376 return new Position (end); 377 } 378 379]])[ 380 ]AT_YYERROR_DEFINE[ 381 382 Integer yylval; 383 384 public Object getLVal () { 385 return yylval; 386 } 387 388 public int yylex () throws IOException {;]AT_LOCATION_IF([[ 389 start.set (reader.getPosition ());]])[ 390 int tkind = st.nextToken ();]AT_LOCATION_IF([[ 391 end.set (reader.getPosition ());]])[ 392 switch (tkind) 393 { 394 case StreamTokenizer.TT_EOF: 395 return CALC_EOF; 396 case StreamTokenizer.TT_EOL:;]AT_LOCATION_IF([[ 397 end.line += 1; 398 end.column = 0;]])[ 399 return (int) '\n'; 400 case StreamTokenizer.TT_WORD: 401 yylval = new Integer (st.sval);]AT_LOCATION_IF([[ 402 end.set (reader.getPreviousPosition ());]])[ 403 return NUM; 404 case ' ': case '\t': 405 return yylex (); 406 case '#': 407 System.err.println(]AT_LOCATION_IF([[start + ": " + ]])["syntax error: invalid character: '#'"); 408 return YYerror; 409 default: 410 return tkind; 411 } 412 } 413]AT_LEXPARAM_IF([], [[}]])[ 414}; 415]]) 416 417 418# -------------- # 419# AT_DATA_CALC. # 420# -------------- # 421 422 423# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES]) 424# ----------------------------------------------- 425# Produce 'calc.y' and, if %defines was specified, 'calc-lex.c' or 426# 'calc-lex.cc'. 427# 428# Don't call this macro directly, because it contains some occurrences 429# of '$1' etc. which will be interpreted by m4. So you should call it 430# with $1, $2, and $3 as arguments, which is what AT_DATA_CALC_Y does. 431# 432# When %defines is not passed, generate a single self-contained file. 433# Otherwise, generate three: calc.y with the parser, calc-lex.c with 434# the scanner, and calc-main.c with "main()". This is in order to 435# stress the use of the generated parser header. To avoid code 436# duplication, AT_CALC_YYLEX and AT_CALC_MAIN contain the body of these 437# two later files. 438m4_pushdef([_AT_DATA_CALC_Y], 439[m4_if([$1$2$3], $[1]$[2]$[3], [], 440 [m4_fatal([$0: Invalid arguments: $@])])dnl 441AT_LANG_DISPATCH([$0], $@)]) 442 443m4_define([_AT_DATA_CALC_Y(c)], 444[AT_DATA_GRAMMAR([calc.y], 445[[/* Infix notation calculator--calc */ 446]$4[ 447]AT_LANG_MATCH( 448[d], [[ 449%code imports { 450 alias semantic_value = int; 451} 452]], 453[c\|c++], [[ 454%code requires 455{ 456]AT_LOCATION_TYPE_SPAN_IF([[ 457 typedef struct 458 { 459 int l; 460 int c; 461 } Point; 462 463 typedef struct 464 { 465 Point first; 466 Point last; 467 } Span; 468 469# define YYLLOC_DEFAULT(Current, Rhs, N) \ 470 do \ 471 if (N) \ 472 { \ 473 (Current).first = YYRHSLOC (Rhs, 1).first; \ 474 (Current).last = YYRHSLOC (Rhs, N).last; \ 475 } \ 476 else \ 477 { \ 478 (Current).first = (Current).last = YYRHSLOC (Rhs, 0).last; \ 479 } \ 480 while (0) 481 482]AT_C_IF( 483[[#include <stdio.h> 484void location_print (FILE *o, Span s); 485#define LOCATION_PRINT location_print 486]])[ 487 488]])[ 489 /* Exercise pre-prologue dependency to %union. */ 490 typedef int semantic_value; 491} 492]])[ 493 494/* Exercise %union. */ 495%union 496{ 497 semantic_value ival; 498}; 499%printer { ]AT_CXX_IF([[yyo << $$]], 500 [[fprintf (yyo, "%d", $$)]])[; } <ival>; 501 502]AT_LANG_MATCH([c\|c++], [[ 503%code provides 504{ 505 #include <stdio.h> 506 /* The input. */ 507 extern FILE *input; 508 extern semantic_value global_result; 509 extern int global_count; 510 extern int global_nerrs; 511} 512 513%code 514{ 515 #include <assert.h> 516 #include <string.h> 517 #define USE(Var) 518 519 FILE *input; 520 static int power (int base, int exponent); 521 522 ]AT_YYERROR_DECLARE[ 523 ]AT_YYLEX_DECLARE_EXTERN[ 524 525 ]AT_TOKEN_TRANSLATE_IF([[ 526#define N_ 527 static 528 const char * 529 _ (const char *cp) 530 { 531 if (strcmp (cp, "end of input") == 0) 532 return "end of file"; 533 else if (strcmp (cp, "number") == 0) 534 return "nombre"; 535 else 536 return cp; 537 } 538 ]])[ 539} 540]])[ 541 542]AT_LOCATION_TYPE_SPAN_IF([[ 543%initial-action 544{ 545 @$.first.l = @$.first.c = 1; 546 @$.last = @$.first; 547}]])[ 548 549/* Bison Declarations */ 550%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[ 551%token <ival> NUM "number" 552%type <ival> exp 553 554%nonassoc '=' /* comparison */ 555%left '-' '+' 556%left '*' '/' 557%precedence NEG /* negation--unary minus */ 558%right '^' /* exponentiation */ 559 560/* Grammar follows */ 561%% 562input: 563 line 564| input line { ]AT_PARAM_IF([++*count; ++global_count;])[ } 565; 566 567line: 568 '\n' 569| exp '\n' { ]AT_PARAM_IF([*result = global_result = $1;], [AT_D_IF([], [USE ($1);])])[ } 570; 571 572exp: 573 NUM 574| exp '=' exp 575 { 576 if ($1 != $3)]AT_LANG_CASE( 577 [c], [[ 578 { 579 char buf[1024]; 580 snprintf (buf, sizeof buf, "calc: error: %d != %d", $1, $3);]AT_YYERROR_ARG_LOC_IF([[ 581 yyerror (&@$, ]AT_PARAM_IF([result, count, nerrs, ])[buf);]], [[ 582 { 583 YYLTYPE old_yylloc = yylloc; 584 yylloc = @$; 585 yyerror (]AT_PARAM_IF([result, count, nerrs, ])[buf); 586 yylloc = old_yylloc; 587 } 588 ]])[ 589 }]], 590 [c++], [[ 591 { 592 char buf[1024]; 593 snprintf (buf, sizeof buf, "calc: error: %d != %d", $1, $3); 594 ]AT_GLR_IF([[yyparser.]])[error (]AT_LOCATION_IF([[@$, ]])[buf); 595 }]], 596 [d], [[ 597 yyerror (]AT_LOCATION_IF([[@$, ]])[format ("calc: error: %d != %d", $1, $3));]])[ 598 $$ = $1; 599 } 600| exp '+' exp { $$ = $1 + $3; } 601| exp '-' exp { $$ = $1 - $3; } 602| exp '*' exp { $$ = $1 * $3; } 603| exp '/' exp { $$ = $1 / $3; } 604| '-' exp %prec NEG { $$ = -$2; } 605| exp '^' exp { $$ = power ($1, $3); } 606| '(' exp ')' { $$ = $2; } 607| '(' error ')' { $$ = 1111; ]AT_D_IF([], [yyerrok;])[ } 608| '!' { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; } 609| '-' error { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; } 610; 611%% 612 613int 614power (int base, int exponent) 615{ 616 int res = 1; 617 assert (0 <= exponent); 618 for (/* Niente */; exponent; --exponent) 619 res *= base; 620 return res; 621} 622 623]AT_LOCATION_TYPE_SPAN_IF([AT_CXX_IF([[ 624#include <iostream> 625namespace 626{ 627 std::ostream& 628 operator<< (std::ostream& o, const Span& s) 629 { 630 o << s.first.l << '.' << s.first.c; 631 if (s.first.l != s.last.l) 632 o << '-' << s.last.l << '.' << s.last.c - 1; 633 else if (s.first.c != s.last.c - 1) 634 o << '-' << s.last.c - 1; 635 return o; 636 } 637} 638]], [[ 639void 640location_print (FILE *o, Span s) 641{ 642 fprintf (o, "%d.%d", s.first.l, s.first.c); 643 if (s.first.l != s.last.l) 644 fprintf (o, "-%d.%d", s.last.l, s.last.c - 1); 645 else if (s.first.c != s.last.c - 1) 646 fprintf (o, "-%d", s.last.c - 1); 647} 648]])])[ 649]AT_YYERROR_DEFINE[ 650]AT_DEFINES_IF([], 651[AT_CALC_YYLEX 652AT_CALC_MAIN])]) 653 654AT_DEFINES_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT], 655[[#include "calc.]AT_LANG_HDR[" 656 657]AT_CALC_YYLEX]) 658AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT], 659[[#include "calc.]AT_LANG_HDR[" 660 661]AT_CALC_MAIN]) 662]) 663])# _AT_DATA_CALC_Y 664 665 666m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)]) 667m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(d)]) 668 669m4_define([_AT_DATA_CALC_Y(java)], 670[AT_DATA_GRAMMAR([Calc.y], 671[[/* Infix notation calculator--calc */ 672%define api.prefix {Calc} 673%define api.parser.class {Calc} 674%define public 675 676]$4[ 677 678%code imports {]AT_LOCATION_IF([[ 679 import java.io.BufferedReader;]])[ 680 import java.io.IOException; 681 import java.io.InputStream; 682 import java.io.InputStreamReader; 683 import java.io.Reader; 684 import java.io.StreamTokenizer; 685} 686 687%code { 688 ]AT_CALC_MAIN[ 689 690 ]AT_TOKEN_TRANSLATE_IF([[ 691 static String i18n(String s) 692 { 693 if (s.equals ("end of input")) 694 return "end of file"; 695 else if (s.equals ("number")) 696 return "nombre"; 697 else 698 return s; 699 } 700 ]])[ 701} 702 703/* Bison Declarations */ 704%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[ 705%token <Integer> NUM "number" 706%type <Integer> exp 707 708%nonassoc '=' /* comparison */ 709%left '-' '+' 710%left '*' '/' 711%precedence NEG /* negation--unary minus */ 712%right '^' /* exponentiation */ 713 714/* Grammar follows */ 715%% 716input: 717 line 718| input line 719; 720 721line: 722 '\n' 723| exp '\n' 724; 725 726exp: 727 NUM 728| exp '=' exp 729 { 730 if ($1.intValue () != $3.intValue ()) 731 yyerror (]AT_LOCATION_IF([[@$, ]])["calc: error: " + $1 + " != " + $3); 732 } 733| exp '+' exp { $$ = $1 + $3; } 734| exp '-' exp { $$ = $1 - $3; } 735| exp '*' exp { $$ = $1 * $3; } 736| exp '/' exp { $$ = $1 / $3; } 737| '-' exp %prec NEG { $$ = -$2; } 738| exp '^' exp { $$ = (int) Math.pow ($1, $3); } 739| '(' exp ')' { $$ = $2; } 740| '(' error ')' { $$ = 1111; } 741| '!' { $$ = 0; return YYERROR; } 742| '-' error { $$ = 0; return YYERROR; } 743; 744]AT_CALC_YYLEX[ 745]AT_LOCATION_IF([[ 746%% 747]AT_JAVA_POSITION_DEFINE])[ 748]]) 749])# _AT_DATA_JAVA_CALC_Y 750 751 752 753# AT_DATA_CALC_Y([BISON-OPTIONS]) 754# ------------------------------- 755# Produce 'calc.y' and, if %defines was specified, 'calc-lex.c' or 756# 'calc-lex.cc'. 757m4_define([AT_DATA_CALC_Y], 758[_AT_DATA_CALC_Y($[1], $[2], $[3], [$1]) 759]) 760 761 762 763# _AT_CHECK_CALC(BISON-OPTIONS, INPUT, [STDOUT], [NUM-STDERR-LINES]) 764# ------------------------------------------------------------------ 765# Run 'calc' on INPUT and expect no STDOUT nor STDERR. 766# 767# If BISON-OPTIONS contains '%debug' but not '%glr-parser', then 768# NUM-STDERR-LINES is the number of expected lines on stderr. 769# Currently this is ignored, though, since the output format is fluctuating. 770# 771# We don't count GLR's traces yet, since its traces are somewhat 772# different from LALR's. Likewise for D. 773# 774# The push traces are the same, except for "Return for a new token", don't 775# count them. 776m4_define([_AT_CHECK_CALC], 777[AT_DATA([[input]], 778[$2 779]) 780AT_JAVA_IF( 781 [AT_JAVA_PARSER_CHECK([Calc < input], 0, [AT_PARAM_IF([m4_n([$3])])], [stderr])], 782 [AT_PARSER_CHECK([calc input], 0, [AT_PARAM_IF([m4_n([$3])])], [stderr])]) 783AT_LANG_MATCH([c\|c++\|java], 784 [AT_GLR_IF([], 785 [AT_CHECK([grep -c -v 'Return for a new token:' stderr], 786 [ignore], 787 [m4_n([AT_DEBUG_IF([$4], [0])])])])]) 788]) 789 790 791# _AT_CHECK_CALC_ERROR($1 = BISON-OPTIONS, $2 = EXIT-STATUS, $3 = INPUT, 792# $4 = [STDOUT], 793# $5 = [NUM-STDERR-LINES], 794# $6 = [CUSTOM-ERROR-MESSAGE]) 795# ---------------------------------------------------------------------- 796# Run 'calc' on INPUT, and expect a 'syntax error' message. 797# 798# If INPUT starts with a slash, it is used as absolute input file name, 799# otherwise as contents. 800# 801# NUM-STDERR-LINES is the number of expected lines on stderr. 802# If BISON-OPTIONS contains '%debug' but not '%glr', then NUM-STDERR-LINES 803# is the number of expected lines on stderr. 804# 805# CUSTOM-ERROR-MESSAGE is the expected error message when parse.error 806# is 'custom' and locations are enabled. Other expected formats are 807# computed from it. 808m4_define([_AT_CHECK_CALC_ERROR], 809[m4_bmatch([$3], [^/], 810 [AT_JAVA_IF( 811 [AT_JAVA_PARSER_CHECK([Calc < $3], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])], 812 [AT_PARSER_CHECK([calc $3], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])])], 813 [AT_DATA([[input]], 814[[$3 815]]) 816 AT_JAVA_IF( 817 [AT_JAVA_PARSER_CHECK([Calc < input], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])], 818 [AT_PARSER_CHECK([calc input], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])]) 819]) 820 821# Normalize the observed and expected error messages, depending upon the 822# options. 823# 1. Remove the traces from observed. 824sed '/^Starting/d 825/^Entering/d 826/^Stack/d 827/^Reading/d 828/^Reducing/d 829/^Return/d 830/^Shifting/d 831/^state/d 832/^Cleanup:/d 833/^Error:/d 834/^Next/d 835/^Now/d 836/^Discarding/d 837/ \$[[0-9$]]* = /d 838/^yydestructor:/d' stderr >at-stderr 839mv at-stderr stderr 840 841# 2. Create the reference error message. 842AT_DATA([[expout]], 843[$6 844]) 845 846# 3. If locations are not used, remove them. 847AT_YYERROR_SEES_LOC_IF([], 848[[sed 's/^[-0-9.]*: //' expout >at-expout 849mv at-expout expout]]) 850 851# 4. If parse.error is not custom, turn the expected message to 852# the traditional one. 853AT_ERROR_CUSTOM_IF([], [ 854AT_PERL_REQUIRE([[-pi -e 'use strict; 855 s{syntax error on token \[(.*?)\] \(expected: (.*)\)} 856 { 857 my $unexp = $][1; 858 my @exps = $][2 =~ /\[(.*?)\]/g; 859 ($][#exps && $][#exps < 4) 860 ? "syntax error, unexpected $unexp, expecting @{[join(\" or \", @exps)]}" 861 : "syntax error, unexpected $unexp"; 862 }eg 863' expout]]) 864]) 865 866# 5. If parse.error is simple, strip the', unexpected....' part. 867AT_ERROR_SIMPLE_IF( 868[[sed 's/syntax error, .*$/syntax error/' expout >at-expout 869mv at-expout expout]]) 870 871# 6. Actually check. 872AT_CHECK([cat stderr], 0, [expout]) 873]) 874 875 876# AT_CHECK_SPACES([FILES]) 877# ------------------------ 878# Make sure we did not introduce bad spaces. Checked here because all 879# the skeletons are (or should be) exercised here. 880m4_define([AT_CHECK_SPACES], 881[AT_PERL_CHECK([-ne ' 882 chomp; 883 print "$ARGV:$.: {$_}\n" 884 if (# No starting/ending empty lines. 885 (eof || $. == 1) && /^\s*$/ 886 # No trailing space. 887 || /\s$/ 888 # No tabs. 889 || /\t/ 890 )' $1 891]) 892]) 893 894 895# AT_CHECK_JAVA_GREP(FILE, [LINE], [COUNT=1]) 896# ------------------------------------------- 897# Check that FILE contains exactly COUNT lines matching ^LINE$ 898# with grep. Unquoted so that COUNT can be a shell expression. 899m4_define([AT_CHECK_JAVA_GREP], 900[AT_CHECK_UNQUOTED([grep -c '^$2$' $1], [ignore], [m4_default([$3], [1]) 901])]) 902 903 904# AT_CHECK_CALC([BISON-OPTIONS], [COMPILER-OPTIONS]) 905# -------------------------------------------------- 906# Start a testing chunk which compiles 'calc' grammar with 907# BISON-OPTIONS, and performs several tests over the parser. 908m4_define([AT_CHECK_CALC], 909[m4_ifval([$3], [m4_fatal([$0: expected at most two arguments])]) 910 911# We use integers to avoid dependencies upon the precision of doubles. 912AT_SETUP([Calculator $1 $2]) 913 914AT_BISON_OPTION_PUSHDEFS([$1]) 915 916AT_DATA_CALC_Y([$1]) 917AT_FULL_COMPILE(AT_JAVA_IF([[Calc]], [[calc]]), AT_DEFINES_IF([[lex], [main]], [[], []]), [$2], [-Wno-deprecated]) 918 919AT_YACC_IF( 920 [# No direct calls to malloc/free. 921 AT_CHECK([[$EGREP '(malloc|free) *\(' calc.[ch] | $EGREP -v 'INFRINGES ON USER NAME SPACE']], 922 [1])]) 923 924AT_PUSH_IF([AT_JAVA_IF( 925 [# Verify that this is a push parser. 926 AT_CHECK_JAVA_GREP([[Calc.java]], 927 [[.*public void push_parse_initialize ().*]])])]) 928 929AT_CHECK_SPACES([AT_JAVA_IF([Calc], [calc]).AT_LANG_EXT AT_DEFINES_IF([AT_JAVA_IF([Calc], [calc]).AT_LANG_HDR])]) 930 931# Test the precedences. 932# The Java traces do not show the clean up sequence at the end, 933# since it does not support %destructor. 934_AT_CHECK_CALC([$1], 935[[1 + 2 * 3 = 7 9361 + 2 * -3 = -5 937 938-1^2 = -1 939(-1)^2 = 1 940 941---1 = -1 942 9431 - 2 - 3 = -4 9441 - (2 - 3) = 2 945 9462^2^3 = 256 947(2^2)^3 = 64]], 948[[final: 64 12 0]], 949 [AT_JAVA_IF([1014], [1017])]) 950 951# Some syntax errors. 952_AT_CHECK_CALC_ERROR([$1], [1], [1 2], 953 [[final: 0 0 1]], 954 [15], 955 [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]]) 956_AT_CHECK_CALC_ERROR([$1], [1], [1//2], 957 [[final: 0 0 1]], 958 [20], 959 [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token ['/'] (expected: [number] ['-'] ['('] ['!'])]]) 960_AT_CHECK_CALC_ERROR([$1], [1], [error], 961 [[final: 0 0 1]], 962 [5], 963 [AT_JAVA_IF([1.1-1.2], [1.1])[: syntax error on token [invalid token] (expected: [number] ['-'] ['\n'] ['('] ['!'])]]) 964_AT_CHECK_CALC_ERROR([$1], [1], [1 = 2 = 3], 965 [[final: 0 0 1]], 966 [30], 967 [AT_LAC_IF( 968 [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]], 969 [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'])]])]) 970_AT_CHECK_CALC_ERROR([$1], [1], 971 [ 972+1], 973 [[final: 0 0 1]], 974 [20], 975 [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'] ['('] ['!'])]]) 976# Exercise error messages with EOF: work on an empty file. 977_AT_CHECK_CALC_ERROR([$1], [1], [/dev/null], 978 [[final: 0 0 1]], 979 [4], 980 [[1.1: syntax error on token ]AT_TOKEN_TRANSLATE_IF([[[end of file]]], [[[end of input]]])[ (expected: [number] ['-'] ['\n'] ['('] ['!'])]]) 981 982# Exercise the error token: without it, we die at the first error, 983# hence be sure to 984# 985# - have several errors which exercise different shift/discardings 986# - (): nothing to pop, nothing to discard 987# - (1 + 1 + 1 +): a lot to pop, nothing to discard 988# - (* * *): nothing to pop, a lot to discard 989# - (1 + 2 * *): some to pop and discard 990# 991# - test the action associated to 'error' 992# 993# - check the lookahead that triggers an error is not discarded 994# when we enter error recovery. Below, the lookahead causing the 995# first error is ")", which is needed to recover from the error and 996# produce the "0" that triggers the "0 != 1" error. 997# 998_AT_CHECK_CALC_ERROR([$1], [0], 999 [() + (1 + 1 + 1 +) + (* * *) + (1 * 2 * *) = 1], 1000 [[final: 4444 0 5]], 1001 [250], 1002[AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!']) 1003]AT_JAVA_IF([1.18-1.19], [1.18])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!']) 1004]AT_JAVA_IF([1.23-1.24], [1.23])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) 1005]AT_JAVA_IF([1.41-1.42], [1.41])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) 1006]AT_JAVA_IF([1.1-1.47], [1.1-46])[: calc: error: 4444 != 1]]) 1007 1008# The same, but this time exercising explicitly triggered syntax errors. 1009# POSIX says the lookahead causing the error should not be discarded. 1010_AT_CHECK_CALC_ERROR([$1], [0], [(!) + (1 2) = 1], 1011 [[final: 2222 0 2]], 1012 [102], 1013[AT_JAVA_IF([1.10-1.11], [1.10])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')']) 1014]AT_JAVA_IF([1.1-1.16], [1.1-15])[: calc: error: 2222 != 1]]) 1015 1016_AT_CHECK_CALC_ERROR([$1], [0], [(- *) + (1 2) = 1], 1017 [[final: 2222 0 3]], 1018 [113], 1019[AT_JAVA_IF([1.4-1.5], [1.4])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) 1020]AT_JAVA_IF([1.12-1.13], [1.12])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')']) 1021]AT_JAVA_IF([1.1-1.18], [1.1-17])[: calc: error: 2222 != 1]]) 1022 1023# Check that yyerrok works properly: second error is not reported, 1024# third and fourth are. Parse status is successful. 1025_AT_CHECK_CALC_ERROR([$1], [0], [(* *) + (*) + (*)], 1026 [[final: 3333 0 3]], 1027 [113], 1028[AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) 1029]AT_JAVA_IF([1.10-1.11], [1.10])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!']) 1030]AT_JAVA_IF([1.16-1.17], [1.16])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])]]) 1031 1032 1033# YYerror. 1034# -------- 1035# Check that returning YYerror from the scanner properly enters 1036# error-recovery without issuing a second error message. 1037 1038_AT_CHECK_CALC_ERROR([$1], [0], [(#) + (#) = 2222], 1039 [[final: 2222 0 0]], 1040 [102], 1041[[1.2: syntax error: invalid character: '#' 10421.8: syntax error: invalid character: '#']]) 1043 1044_AT_CHECK_CALC_ERROR([$1], [0], [(1 + #) = 1111], 1045 [[final: 1111 0 0]], 1046 [102], 1047[[1.6: syntax error: invalid character: '#']]) 1048 1049_AT_CHECK_CALC_ERROR([$1], [0], [(# + 1) = 1111], 1050 [[final: 1111 0 0]], 1051 [102], 1052[[1.2: syntax error: invalid character: '#']]) 1053 1054_AT_CHECK_CALC_ERROR([$1], [0], [(1 + # + 1) = 1111], 1055 [[final: 1111 0 0]], 1056 [102], 1057[[1.6: syntax error: invalid character: '#']]) 1058 1059 1060 1061AT_BISON_OPTION_POPDEFS 1062 1063AT_CLEANUP 1064])# AT_CHECK_CALC 1065 1066 1067 1068 1069# ----------------- # 1070# LALR Calculator. # 1071# ----------------- # 1072 1073AT_BANNER([[LALR(1) Calculator.]]) 1074 1075# AT_CHECK_CALC_LALR([BISON-OPTIONS]) 1076# ----------------------------------- 1077# Start a testing chunk which compiles 'calc' grammar with 1078# BISON-OPTIONS, and performs several tests over the parser. 1079m4_define([AT_CHECK_CALC_LALR], 1080[AT_CHECK_CALC($@)]) 1081 1082AT_CHECK_CALC_LALR([%define parse.trace]) 1083 1084AT_CHECK_CALC_LALR([%defines]) 1085AT_CHECK_CALC_LALR([%debug %locations]) 1086AT_CHECK_CALC_LALR([%locations %define api.location.type {Span}]) 1087 1088AT_CHECK_CALC_LALR([%name-prefix "calc"]) 1089AT_CHECK_CALC_LALR([%verbose]) 1090AT_CHECK_CALC_LALR([%yacc]) 1091AT_CHECK_CALC_LALR([%define parse.error detailed]) 1092AT_CHECK_CALC_LALR([%define parse.error verbose]) 1093 1094AT_CHECK_CALC_LALR([%define api.pure full %locations]) 1095AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %locations]) 1096AT_CHECK_CALC_LALR([%define parse.error detailed %locations]) 1097 1098AT_CHECK_CALC_LALR([%define parse.error detailed %locations %defines %define api.prefix {calc} %verbose %yacc]) 1099AT_CHECK_CALC_LALR([%define parse.error detailed %locations %defines %name-prefix "calc" %define api.token.prefix {TOK_} %verbose %yacc]) 1100 1101AT_CHECK_CALC_LALR([%debug]) 1102AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %defines %name-prefix "calc" %verbose %yacc]) 1103AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc]) 1104 1105AT_CHECK_CALC_LALR([%define api.pure full %define parse.error detailed %debug %locations %defines %name-prefix "calc" %verbose %yacc]) 1106AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc]) 1107 1108AT_CHECK_CALC_LALR([%define api.pure %define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1109 1110AT_CHECK_CALC_LALR([%no-lines %define api.pure %define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1111AT_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}]) 1112 1113 1114AT_CHECK_CALC_LALR([%define parse.error custom]) 1115AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc}]) 1116AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1117AT_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]) 1118AT_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]) 1119 1120# ---------------- # 1121# GLR Calculator. # 1122# ---------------- # 1123 1124AT_BANNER([[GLR Calculator.]]) 1125 1126m4_define([AT_CHECK_CALC_GLR], 1127[AT_CHECK_CALC([%glr-parser] $@)]) 1128 1129AT_CHECK_CALC_GLR() 1130 1131AT_CHECK_CALC_GLR([%defines]) 1132AT_CHECK_CALC_GLR([%locations]) 1133AT_CHECK_CALC_GLR([%locations %define api.location.type {Span}]) 1134AT_CHECK_CALC_GLR([%name-prefix "calc"]) 1135AT_CHECK_CALC_GLR([%define api.prefix {calc}]) 1136AT_CHECK_CALC_GLR([%verbose]) 1137AT_CHECK_CALC_GLR([%define parse.error verbose]) 1138 1139AT_CHECK_CALC_GLR([%define api.pure %locations]) 1140AT_CHECK_CALC_GLR([%define parse.error verbose %locations]) 1141 1142AT_CHECK_CALC_GLR([%define parse.error custom %locations %defines %name-prefix "calc" %verbose]) 1143AT_CHECK_CALC_GLR([%define parse.error detailed %locations %defines %name-prefix "calc" %verbose]) 1144AT_CHECK_CALC_GLR([%define parse.error verbose %locations %defines %name-prefix "calc" %verbose]) 1145 1146AT_CHECK_CALC_GLR([%debug]) 1147AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %defines %name-prefix "calc" %verbose]) 1148AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %defines %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose]) 1149 1150AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %defines %name-prefix "calc" %verbose]) 1151 1152AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %defines %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1153AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %defines %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1154 1155AT_CHECK_CALC_GLR([%no-lines %define api.pure %define parse.error verbose %debug %locations %defines %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1156 1157 1158# ---------------------- # 1159# LALR1 C++ Calculator. # 1160# ---------------------- # 1161 1162AT_BANNER([[LALR(1) C++ Calculator.]]) 1163 1164# First let's try using %skeleton 1165AT_CHECK_CALC([%skeleton "lalr1.cc" %defines]) 1166 1167m4_define([AT_CHECK_CALC_LALR1_CC], 1168[AT_CHECK_CALC([%language "C++" $1], [$2])]) 1169 1170AT_CHECK_CALC_LALR1_CC([]) 1171AT_CHECK_CALC_LALR1_CC([%locations]) 1172AT_CHECK_CALC_LALR1_CC([%locations], [$NO_EXCEPTIONS_CXXFLAGS]) 1173AT_CHECK_CALC_LALR1_CC([%locations %define api.location.type {Span}]) 1174AT_CHECK_CALC_LALR1_CC([%defines %locations %define parse.error verbose %name-prefix "calc" %verbose]) 1175 1176AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %define api.prefix {calc} %verbose]) 1177AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %name-prefix "calc" %verbose]) 1178 1179AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %verbose]) 1180AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose]) 1181 1182AT_CHECK_CALC_LALR1_CC([%defines %locations %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1183 1184AT_CHECK_CALC_LALR1_CC([%define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1185AT_CHECK_CALC_LALR1_CC([%defines %locations %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1186 1187AT_CHECK_CALC_LALR1_CC([%defines %locations %define api.location.file none]) 1188AT_CHECK_CALC_LALR1_CC([%defines %locations %define api.location.file "my-location.hh"]) 1189 1190AT_CHECK_CALC_LALR1_CC([%no-lines %defines %locations %define api.location.file "my-location.hh"]) 1191 1192AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error verbose]) 1193AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error detailed]) 1194 1195AT_CHECK_CALC_LALR1_CC([%define parse.error custom]) 1196AT_CHECK_CALC_LALR1_CC([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1197AT_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]) 1198 1199# -------------------- # 1200# GLR C++ Calculator. # 1201# -------------------- # 1202 1203AT_BANNER([[GLR C++ Calculator.]]) 1204 1205# Again, we try also using %skeleton. 1206AT_CHECK_CALC([%skeleton "glr.cc"]) 1207 1208m4_define([AT_CHECK_CALC_GLR_CC], 1209[AT_CHECK_CALC([%language "C++" %glr-parser] $@)]) 1210 1211AT_CHECK_CALC_GLR_CC([]) 1212AT_CHECK_CALC_GLR_CC([%locations]) 1213AT_CHECK_CALC_GLR_CC([%locations %define api.location.type {Span}]) 1214AT_CHECK_CALC_GLR_CC([%defines %define parse.error verbose %name-prefix "calc" %verbose]) 1215AT_CHECK_CALC_GLR_CC([%define parse.error verbose %define api.prefix {calc} %verbose]) 1216 1217AT_CHECK_CALC_GLR_CC([%debug]) 1218 1219AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %verbose]) 1220AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %define api.token.prefix {TOK_} %verbose]) 1221 1222AT_CHECK_CALC_GLR_CC([%locations %defines %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1223AT_CHECK_CALC_GLR_CC([%locations %defines %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1224 1225AT_CHECK_CALC_GLR_CC([%no-lines %locations %defines %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1226 1227 1228# -------------------- # 1229# LALR1 D Calculator. # 1230# -------------------- # 1231 1232AT_BANNER([[LALR(1) D Calculator.]]) 1233 1234# First let's try using %skeleton 1235AT_CHECK_CALC([%skeleton "lalr1.d"]) 1236 1237m4_define([AT_CHECK_CALC_LALR1_D], 1238[AT_CHECK_CALC([%language "D" $1], [$2])]) 1239 1240AT_CHECK_CALC_LALR1_D([]) 1241AT_CHECK_CALC_LALR1_D([%locations]) 1242#AT_CHECK_CALC_LALR1_D([%locations %define api.location.type {Span}]) 1243AT_CHECK_CALC_LALR1_D([%define parse.error verbose %define api.prefix {calc} %verbose]) 1244 1245AT_CHECK_CALC_LALR1_D([%debug]) 1246 1247AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %verbose]) 1248#AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %define api.token.prefix {TOK_} %verbose]) 1249 1250#AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose %debug %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1251#AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}]) 1252 1253 1254# ----------------------- # 1255# LALR1 Java Calculator. # 1256# ----------------------- # 1257 1258AT_BANNER([[LALR(1) Java Calculator.]]) 1259 1260m4_define([AT_CHECK_CALC_LALR1_JAVA], 1261[AT_CHECK_CALC([%language "Java" $1], [$2])]) 1262 1263AT_CHECK_CALC_LALR1_JAVA 1264AT_CHECK_CALC_LALR1_JAVA([%define parse.error custom]) 1265AT_CHECK_CALC_LALR1_JAVA([%define parse.error detailed]) 1266AT_CHECK_CALC_LALR1_JAVA([%define parse.error verbose]) 1267AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error custom]) 1268AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error detailed]) 1269AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error verbose]) 1270AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose]) 1271AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is}]) 1272 1273AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both]) 1274AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both %define parse.error detailed %locations]) 1275AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %lex-param {InputStream is} %define api.push-pull both]) 1276AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is} %define api.push-pull both]) 1277 1278 1279m4_popdef([AT_TOKEN_TRANSLATE_IF]) 1280m4_popdef([AT_CALC_MAIN]) 1281m4_popdef([AT_CALC_YYLEX]) 1282