1# Executing Actions. -*- Autotest -*- 2# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. 3 4# This program is free software; you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation; either version 2, or (at your option) 7# any later version. 8 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13 14# You should have received a copy of the GNU General Public License 15# along with this program; if not, write to the Free Software 16# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17# 02110-1301, USA. 18 19AT_BANNER([[User Actions.]]) 20 21## ------------------ ## 22## Mid-rule actions. ## 23## ------------------ ## 24 25AT_SETUP([Mid-rule actions]) 26 27# Bison once forgot the mid-rule actions. It was because the action 28# was attached to the host rule (the one with the mid-rule action), 29# instead of being attached to the empty rule dedicated to this 30# action. 31 32AT_DATA_GRAMMAR([[input.y]], 33[[%error-verbose 34%debug 35%{ 36# include <stdio.h> 37# include <stdlib.h> 38 static void yyerror (const char *msg); 39 static int yylex (void); 40%} 41%% 42exp: { putchar ('0'); } 43 '1' { putchar ('1'); } 44 '2' { putchar ('2'); } 45 '3' { putchar ('3'); } 46 '4' { putchar ('4'); } 47 '5' { putchar ('5'); } 48 '6' { putchar ('6'); } 49 '7' { putchar ('7'); } 50 '8' { putchar ('8'); } 51 '9' { putchar ('9'); } 52 { putchar ('\n'); } 53 ; 54%% 55static int 56yylex (void) 57{ 58 static const char *input = "123456789"; 59 return *input++; 60} 61 62static void 63yyerror (const char *msg) 64{ 65 fprintf (stderr, "%s\n", msg); 66} 67 68int 69main (void) 70{ 71 return yyparse (); 72} 73]]) 74 75AT_CHECK([bison -d -v -o input.c input.y]) 76AT_COMPILE([input]) 77AT_PARSER_CHECK([./input], 0, 78[[0123456789 79]]) 80 81AT_CLEANUP 82 83 84 85 86 87## ---------------- ## 88## Exotic Dollars. ## 89## ---------------- ## 90 91AT_SETUP([Exotic Dollars]) 92 93AT_DATA_GRAMMAR([[input.y]], 94[[%error-verbose 95%debug 96%{ 97# include <stdio.h> 98# include <stdlib.h> 99 static void yyerror (const char *msg); 100 static int yylex (void); 101# define USE(Var) 102%} 103 104%union 105{ 106 int val; 107}; 108 109%type <val> a_1 a_2 a_5 110 sum_of_the_five_previous_values 111 112%% 113exp: a_1 a_2 { $<val>$ = 3; } { $<val>$ = $<val>3 + 1; } a_5 114 sum_of_the_five_previous_values 115 { 116 USE (($1, $2, $<foo>3, $<foo>4, $5)); 117 printf ("%d\n", $6); 118 } 119; 120a_1: { $$ = 1; }; 121a_2: { $$ = 2; }; 122a_5: { $$ = 5; }; 123 124sum_of_the_five_previous_values: 125 { 126 $$ = $<val>0 + $<val>-1 + $<val>-2 + $<val>-3 + $<val>-4; 127 } 128; 129 130%% 131static int 132yylex (void) 133{ 134 return EOF; 135} 136 137static void 138yyerror (const char *msg) 139{ 140 fprintf (stderr, "%s\n", msg); 141} 142 143int 144main (void) 145{ 146 return yyparse (); 147} 148]]) 149 150AT_CHECK([bison -d -v -o input.c input.y], 0) 151AT_COMPILE([input]) 152AT_PARSER_CHECK([./input], 0, 153[[15 154]]) 155 156AT_CLEANUP 157 158 159 160## -------------------------- ## 161## Printers and Destructors. ## 162## -------------------------- ## 163 164# _AT_CHECK_PRINTER_AND_DESTRUCTOR($1, $2, $3, $4, BISON-DIRECTIVE, UNION-FLAG) 165# ----------------------------------------------------------------------------- 166m4_define([_AT_CHECK_PRINTER_AND_DESTRUCTOR], 167[# Make sure complex $n work. 168m4_if([$1$2$3], $[1]$[2]$[3], [], 169 [m4_fatal([$0: Invalid arguments: $@])])dnl 170 171# Be sure to pass all the %directives to this macro to have correct 172# helping macros. So don't put any directly in the Bison file. 173AT_BISON_OPTION_PUSHDEFS([$5]) 174AT_DATA_GRAMMAR([[input.y]], 175[[%{ 176#include <stdio.h> 177#include <stdlib.h> 178#include <assert.h> 179 180#define YYINITDEPTH 10 181#define YYMAXDEPTH 10 182]AT_LALR1_CC_IF( 183 [#define RANGE(Location) (Location).begin.line, (Location).end.line], 184 [#define RANGE(Location) (Location).first_line, (Location).last_line]) 185[%} 186 187$5] 188m4_ifval([$6], [%union 189{ 190 int ival; 191}]) 192AT_LALR1_CC_IF([%define "global_tokens_and_yystype"]) 193[ 194%{ 195]AT_LALR1_CC_IF([typedef yy::location YYLTYPE; 196 m4_ifval([$6], , [#define YYSTYPE int])]) 197[static int yylex (]AT_LEX_FORMALS[); 198]AT_LALR1_CC_IF([], [static void yyerror (const char *msg);]) 199[%} 200 201]m4_ifval([$6], [%type <ival> '(' 'x' 'y' ')' ';' thing line input])[ 202 203%printer 204 { 205 ]AT_LALR1_CC_IF([debug_stream () << $$;], 206 [fprintf (yyoutput, "%d", $$)])[; 207 } 208 input line thing 'x' 'y' 209 210%destructor 211 { printf ("Freeing nterm input (%d@%d-%d)\n", $$, RANGE (@$)); } 212 input 213 214%destructor 215 { printf ("Freeing nterm line (%d@%d-%d)\n", $$, RANGE (@$)); } 216 line 217 218%destructor 219 { printf ("Freeing nterm thing (%d@%d-%d)\n", $$, RANGE (@$)); } 220 thing 221 222%destructor 223 { printf ("Freeing token 'x' (%d@%d-%d)\n", $$, RANGE (@$)); } 224 'x' 225 226%destructor 227 { printf ("Freeing token 'y' (%d@%d-%d)\n", $$, RANGE (@$)); } 228 'y' 229 230%% 231/* 232 This grammar is made to exercise error recovery. 233 "Lines" starting with `(' support error recovery, with 234 ')' as synchronizing token. Lines starting with 'x' can never 235 be recovered from if in error. 236*/ 237 238input: 239 /* Nothing. */ 240 { 241 $$ = 0; 242 printf ("input (%d@%d-%d): /* Nothing */\n", $$, RANGE (@$)); 243 } 244| line input /* Right recursive to load the stack so that popping at 245 EOF can be exercised. */ 246 { 247 $$ = 2; 248 printf ("input (%d@%d-%d): line (%d@%d-%d) input (%d@%d-%d)\n", 249 $$, RANGE (@$), $1, RANGE (@1), $2, RANGE (@2)); 250 } 251; 252 253line: 254 thing thing thing ';' 255 { 256 $$ = $1; 257 printf ("line (%d@%d-%d): thing (%d@%d-%d) thing (%d@%d-%d) thing (%d@%d-%d) ';' (%d@%d-%d)\n", 258 $$, RANGE (@$), $1, RANGE (@1), $2, RANGE (@2), 259 $3, RANGE (@3), $4, RANGE (@4)); 260 } 261| '(' thing thing ')' 262 { 263 $$ = $1; 264 printf ("line (%d@%d-%d): '(' (%d@%d-%d) thing (%d@%d-%d) thing (%d@%d-%d) ')' (%d@%d-%d)\n", 265 $$, RANGE (@$), $1, RANGE (@1), $2, RANGE (@2), 266 $3, RANGE (@3), $4, RANGE (@4)); 267 } 268| '(' thing ')' 269 { 270 $$ = $1; 271 printf ("line (%d@%d-%d): '(' (%d@%d-%d) thing (%d@%d-%d) ')' (%d@%d-%d)\n", 272 $$, RANGE (@$), $1, RANGE (@1), $2, RANGE (@2), $3, RANGE (@3)); 273 } 274| '(' error ')' 275 { 276 $$ = -1; 277 printf ("line (%d@%d-%d): '(' (%d@%d-%d) error (@%d-%d) ')' (%d@%d-%d)\n", 278 $$, RANGE (@$), $1, RANGE (@1), RANGE (@2), $3, RANGE (@3)); 279 } 280; 281 282thing: 283 'x' 284 { 285 $$ = $1; 286 printf ("thing (%d@%d-%d): 'x' (%d@%d-%d)\n", 287 $$, RANGE (@$), $1, RANGE (@1)); 288 } 289; 290%% 291/* Alias to ARGV[1]. */ 292const char *source = 0; 293 294static int 295yylex (]AT_LEX_FORMALS[) 296{ 297 static unsigned int counter = 0; 298 299 int c = ]AT_VAL[]m4_ifval([$6], [.ival])[ = counter++; 300 /* As in BASIC, line numbers go from 10 to 10. */ 301]AT_LALR1_CC_IF( 302[ AT_LOC.begin.line = AT_LOC.begin.column = 10 * c; 303 AT_LOC.end.line = AT_LOC.end.column = AT_LOC.begin.line + 9; 304], 305[ AT_LOC.first_line = AT_LOC.first_column = 10 * c; 306 AT_LOC.last_line = AT_LOC.last_column = AT_LOC.first_line + 9; 307])[ 308 309 if (source[c]) 310 printf ("sending: '%c'", source[c]); 311 else 312 printf ("sending: EOF"); 313 printf (" (%d@%d-%d)\n", c, RANGE (]AT_LOC[)); 314 return source[c]; 315} 316 317]AT_LALR1_CC_IF( 318[/* A C++ error reporting function. */ 319void 320yy::parser::error (const location& l, const std::string& m) 321{ 322 printf ("%d-%d: %s\n", RANGE (l), m.c_str()); 323} 324 325static bool yydebug; 326int 327yyparse () 328{ 329 yy::parser parser; 330 parser.set_debug_level (yydebug); 331 return parser.parse (); 332} 333], 334[static void 335yyerror (const char *msg) 336{ 337 printf ("%d-%d: %s\n", RANGE (yylloc), msg); 338}])[ 339 340int 341main (int argc, const char *argv[]) 342{ 343 int status; 344 yydebug = !!getenv ("YYDEBUG"); 345 assert (argc == 2); 346 source = argv[1]; 347 status = yyparse (); 348 switch (status) 349 { 350 case 0: printf ("Successful parse.\n"); break; 351 case 1: printf ("Parsing FAILED.\n"); break; 352 default: printf ("Parsing FAILED (status %d).\n", status); break; 353 } 354 return status; 355} 356]]) 357 358AT_LALR1_CC_IF( 359 [AT_CHECK([bison -o input.cc input.y]) 360 AT_COMPILE_CXX([input])], 361 [AT_CHECK([bison -o input.c input.y]) 362 AT_COMPILE([input])]) 363 364 365# Check the location of "empty" 366# ----------------------------- 367# I.e., epsilon-reductions, as in "(x)" which ends by reducing 368# an empty "line" nterm. 369# FIXME: This location is not satisfying. Depend on the lookahead? 370AT_PARSER_CHECK([./input '(x)'], 0, 371[[sending: '(' (0@0-9) 372sending: 'x' (1@10-19) 373thing (1@10-19): 'x' (1@10-19) 374sending: ')' (2@20-29) 375line (0@0-29): '(' (0@0-9) thing (1@10-19) ')' (2@20-29) 376sending: EOF (3@30-39) 377input (0@29-29): /* Nothing */ 378input (2@0-29): line (0@0-29) input (0@29-29) 379Freeing nterm input (2@0-29) 380Successful parse. 381]]) 382 383 384# Check locations in error recovery 385# --------------------------------- 386# '(y)' is an error, but can be recovered from. But what's the location 387# of the error itself ('y'), and of the resulting reduction ('(error)'). 388AT_PARSER_CHECK([./input '(y)'], 0, 389[[sending: '(' (0@0-9) 390sending: 'y' (1@10-19) 39110-19: syntax error, unexpected 'y', expecting 'x' 392Freeing token 'y' (1@10-19) 393sending: ')' (2@20-29) 394line (-1@0-29): '(' (0@0-9) error (@10-19) ')' (2@20-29) 395sending: EOF (3@30-39) 396input (0@29-29): /* Nothing */ 397input (2@0-29): line (-1@0-29) input (0@29-29) 398Freeing nterm input (2@0-29) 399Successful parse. 400]]) 401 402 403# Syntax errors caught by the parser 404# ---------------------------------- 405# Exercise the discarding of stack top and input until `error' 406# can be reduced. 407# 408# '(', 'x', 'x', 'x', 'x', 'x', ')', 409# 410# Load the stack and provoke an error that cannot be caught by the 411# grammar, to check that the stack is cleared. And make sure the 412# lookahead is freed. 413# 414# '(', 'x', ')', 415# '(', 'x', ')', 416# 'y' 417AT_PARSER_CHECK([./input '(xxxxx)(x)(x)y'], 1, 418[[sending: '(' (0@0-9) 419sending: 'x' (1@10-19) 420thing (1@10-19): 'x' (1@10-19) 421sending: 'x' (2@20-29) 422thing (2@20-29): 'x' (2@20-29) 423sending: 'x' (3@30-39) 42430-39: syntax error, unexpected 'x', expecting ')' 425Freeing nterm thing (2@20-29) 426Freeing nterm thing (1@10-19) 427Freeing token 'x' (3@30-39) 428sending: 'x' (4@40-49) 429Freeing token 'x' (4@40-49) 430sending: 'x' (5@50-59) 431Freeing token 'x' (5@50-59) 432sending: ')' (6@60-69) 433line (-1@0-69): '(' (0@0-9) error (@10-59) ')' (6@60-69) 434sending: '(' (7@70-79) 435sending: 'x' (8@80-89) 436thing (8@80-89): 'x' (8@80-89) 437sending: ')' (9@90-99) 438line (7@70-99): '(' (7@70-79) thing (8@80-89) ')' (9@90-99) 439sending: '(' (10@100-109) 440sending: 'x' (11@110-119) 441thing (11@110-119): 'x' (11@110-119) 442sending: ')' (12@120-129) 443line (10@100-129): '(' (10@100-109) thing (11@110-119) ')' (12@120-129) 444sending: 'y' (13@130-139) 445input (0@129-129): /* Nothing */ 446input (2@100-129): line (10@100-129) input (0@129-129) 447input (2@70-129): line (7@70-99) input (2@100-129) 448input (2@0-129): line (-1@0-69) input (2@70-129) 449130-139: syntax error, unexpected 'y', expecting $end 450Freeing nterm input (2@0-129) 451Freeing token 'y' (13@130-139) 452Parsing FAILED. 453]]) 454 455# Check destruction upon stack overflow 456# ------------------------------------- 457# Upon stack overflow, all symbols on the stack should be destroyed. 458# Only check for yacc.c. 459AT_YACC_IF([ 460AT_PARSER_CHECK([./input '(x)(x)(x)(x)(x)(x)(x)'], 2, 461[[sending: '(' (0@0-9) 462sending: 'x' (1@10-19) 463thing (1@10-19): 'x' (1@10-19) 464sending: ')' (2@20-29) 465line (0@0-29): '(' (0@0-9) thing (1@10-19) ')' (2@20-29) 466sending: '(' (3@30-39) 467sending: 'x' (4@40-49) 468thing (4@40-49): 'x' (4@40-49) 469sending: ')' (5@50-59) 470line (3@30-59): '(' (3@30-39) thing (4@40-49) ')' (5@50-59) 471sending: '(' (6@60-69) 472sending: 'x' (7@70-79) 473thing (7@70-79): 'x' (7@70-79) 474sending: ')' (8@80-89) 475line (6@60-89): '(' (6@60-69) thing (7@70-79) ')' (8@80-89) 476sending: '(' (9@90-99) 477sending: 'x' (10@100-109) 478thing (10@100-109): 'x' (10@100-109) 479sending: ')' (11@110-119) 480line (9@90-119): '(' (9@90-99) thing (10@100-109) ')' (11@110-119) 481sending: '(' (12@120-129) 482sending: 'x' (13@130-139) 483thing (13@130-139): 'x' (13@130-139) 484sending: ')' (14@140-149) 485line (12@120-149): '(' (12@120-129) thing (13@130-139) ')' (14@140-149) 486sending: '(' (15@150-159) 487sending: 'x' (16@160-169) 488thing (16@160-169): 'x' (16@160-169) 489sending: ')' (17@170-179) 490line (15@150-179): '(' (15@150-159) thing (16@160-169) ')' (17@170-179) 491sending: '(' (18@180-189) 492sending: 'x' (19@190-199) 493thing (19@190-199): 'x' (19@190-199) 494sending: ')' (20@200-209) 495200-209: memory exhausted 496Freeing nterm thing (19@190-199) 497Freeing nterm line (15@150-179) 498Freeing nterm line (12@120-149) 499Freeing nterm line (9@90-119) 500Freeing nterm line (6@60-89) 501Freeing nterm line (3@30-59) 502Freeing nterm line (0@0-29) 503Parsing FAILED (status 2). 504]]) 505]) 506 507]) 508 509 510# AT_CHECK_PRINTER_AND_DESTRUCTOR([BISON-OPTIONS], [UNION-FLAG], [SKIP_FLAG]) 511# --------------------------------------------------------------------------- 512m4_define([AT_CHECK_PRINTER_AND_DESTRUCTOR], 513[AT_SETUP([Printers and Destructors $2: $1]) 514 515$3 516_AT_CHECK_PRINTER_AND_DESTRUCTOR($[1], $[2], $[3], $[4], 517[%error-verbose 518%debug 519%verbose 520%locations 521$1], [$2]) 522 523AT_CLEANUP 524]) 525 526 527AT_CHECK_PRINTER_AND_DESTRUCTOR([]) 528AT_CHECK_PRINTER_AND_DESTRUCTOR([], [with union]) 529 530# These tests currently fail on a Debian GNU/Linux 3.0r2 x86 host, 531# but the 2nd test succeeds on a Solaris 9 sparc hosts (Forte 7 cc). 532# Skip them until we figure out what the problem is. 533AT_CHECK_PRINTER_AND_DESTRUCTOR([%defines %skeleton "lalr1.cc"]) 534AT_CHECK_PRINTER_AND_DESTRUCTOR([%defines %skeleton "lalr1.cc"], [with union]) 535 536AT_CHECK_PRINTER_AND_DESTRUCTOR([%glr-parser]) 537AT_CHECK_PRINTER_AND_DESTRUCTOR([%glr-parser], [with union]) 538