26 |
# ------------------------- # |
# ------------------------- # |
27 |
|
|
28 |
|
|
29 |
# _AT_DATA_CALC_Y($1, $2, $3, [CPP-DIRECTIVES]) |
# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES]) |
30 |
# --------------------------------------------- |
# ----------------------------------------------- |
31 |
# Produce `calc.y'. Don't call this macro directly, because it contains |
# Produce `calc.y'. Don't call this macro directly, because it contains |
32 |
# some occurrences of `$1' etc. which will be interpreted by m4. So |
# some occurrences of `$1' etc. which will be interpreted by m4. So |
33 |
# you should call it with $1, $2, and $3 as arguments, which is what |
# you should call it with $1, $2, and $3 as arguments, which is what |
37 |
[m4_fatal([$0: Invalid arguments: $@])])dnl |
[m4_fatal([$0: Invalid arguments: $@])])dnl |
38 |
AT_DATA([calc.y], |
AT_DATA([calc.y], |
39 |
[[/* Infix notation calculator--calc */ |
[[/* Infix notation calculator--calc */ |
40 |
|
]$4[ |
41 |
%{ |
%{ |
42 |
#include <config.h> |
#include <config.h> |
43 |
/* We don't need perfect functions for these tests. */ |
/* We don't need perfect functions for these tests. */ |
63 |
|
|
64 |
%} |
%} |
65 |
|
|
|
%parse-param "value_t *result", "result" |
|
|
%parse-param "int *count", "count" |
|
|
|
|
66 |
/* Exercise %union. */ |
/* Exercise %union. */ |
67 |
%union |
%union |
68 |
{ |
{ |
78 |
# define VAL (yylval) |
# define VAL (yylval) |
79 |
#endif |
#endif |
80 |
|
|
81 |
|
#define YYLLOC_FORMAL ]AT_LOCATION_IF([, YYLTYPE *yylloc])[ |
82 |
|
#define YYLLOC_ARG ]AT_LOCATION_IF([, yylloc])[ |
83 |
|
#define USE_YYLLOC ]AT_LOCATION_IF([(void) yylloc;])[ |
84 |
|
|
85 |
#if YYPURE |
#if YYPURE |
86 |
# if YYLSP_NEEDED |
# define LEX_FORMALS YYSTYPE *yylval YYLLOC_FORMAL |
87 |
# define LEX_FORMALS YYSTYPE *yylval, YYLTYPE *yylloc |
# define LEX_ARGS yylval YYLLOC_ARG |
88 |
# define LEX_ARGS yylval, yylloc |
# define USE_LEX_ARGS (void) yylval; USE_YYLLOC |
|
# define USE_LEX_ARGS (void) yylval; (void) yylloc; |
|
|
# else |
|
|
# define LEX_FORMALS YYSTYPE *yylval |
|
|
# define LEX_ARGS yylval |
|
|
# define USE_LEX_ARGS (void) yylval |
|
|
# endif |
|
89 |
# define LEX_PRE_FORMALS LEX_FORMALS, |
# define LEX_PRE_FORMALS LEX_FORMALS, |
90 |
# define LEX_PRE_ARGS LEX_ARGS, |
# define LEX_PRE_ARGS LEX_ARGS, |
91 |
#else |
#else |
97 |
#endif |
#endif |
98 |
|
|
99 |
static int power (int base, int exponent); |
static int power (int base, int exponent); |
100 |
static void yyerror (const char *s); |
/* yyerror receives the location if: |
101 |
|
- %location & %pure & %glr |
102 |
|
- %location & %pure & %yacc & %parse-param. */ |
103 |
|
static void yyerror (const char *s |
104 |
|
]AT_YYERROR_ARG_LOC_IF([, YYLTYPE *yylloc])[ |
105 |
|
]AT_PARAM_IF([, value_t *result, int *count])[ |
106 |
|
); |
107 |
static int yylex (LEX_FORMALS); |
static int yylex (LEX_FORMALS); |
108 |
static int yygetc (LEX_FORMALS); |
static int yygetc (LEX_FORMALS); |
109 |
static void yyungetc (LEX_PRE_FORMALS int c); |
static void yyungetc (LEX_PRE_FORMALS int c); |
120 |
%left NEG /* negation--unary minus */ |
%left NEG /* negation--unary minus */ |
121 |
%right '^' /* exponentiation */ |
%right '^' /* exponentiation */ |
122 |
|
|
|
]$4[ |
|
|
|
|
123 |
/* Grammar follows */ |
/* Grammar follows */ |
124 |
%% |
%% |
125 |
input: |
input: |
126 |
line |
line |
127 |
| input line { ++*count; ++global_count; } |
| input line { ]AT_PARAM_IF([++*count; ++global_count;])[ } |
128 |
; |
; |
129 |
|
|
130 |
line: |
line: |
131 |
'\n' |
'\n' |
132 |
| exp '\n' { *result = global_result = $1; } |
| exp '\n' { ]AT_PARAM_IF([*result = global_result = $1;])[ } |
133 |
; |
; |
134 |
|
|
135 |
exp: |
exp: |
136 |
NUM { $$ = $1; } |
NUM { $$ = $1; } |
137 |
| exp '=' exp |
| exp '=' exp |
138 |
{ |
{ |
139 |
if ($1 != $3) |
if ($1 != $3) |
140 |
fprintf (stderr, "calc: error: %d != %d\n", $1, $3); |
fprintf (stderr, "calc: error: %d != %d\n", $1, $3); |
141 |
$$ = $1; |
$$ = $1; |
142 |
} |
} |
143 |
| exp '+' exp { $$ = $1 + $3; } |
| exp '+' exp { $$ = $1 + $3; } |
144 |
| exp '-' exp { $$ = $1 - $3; } |
| exp '-' exp { $$ = $1 - $3; } |
154 |
FILE *yyin; |
FILE *yyin; |
155 |
|
|
156 |
static void |
static void |
157 |
yyerror (const char *s) |
yyerror (const char *s |
158 |
|
]AT_YYERROR_ARG_LOC_IF([, YYLTYPE *yylloc])[ |
159 |
|
]AT_PARAM_IF([, value_t *result, int *count])[) |
160 |
{ |
{ |
161 |
#if YYLSP_NEEDED |
]AT_YYERROR_SEES_LOC_IF([ |
162 |
fprintf (stderr, "%d.%d-%d.%d: ", |
fprintf (stderr, "%d.%d-%d.%d: ", |
163 |
LOC.first_line, LOC.first_column, |
LOC.first_line, LOC.first_column, |
164 |
LOC.last_line, LOC.last_column); |
LOC.last_line, LOC.last_column); |
165 |
#endif |
])[ |
166 |
fprintf (stderr, "%s\n", s); |
fprintf (stderr, "%s\n", s); |
167 |
} |
} |
168 |
|
|
169 |
|
|
170 |
#if YYLSP_NEEDED |
]AT_LOCATION_IF([ |
171 |
static YYLTYPE last_yylloc; |
static YYLTYPE last_yylloc; |
172 |
#endif |
])[ |
173 |
static int |
static int |
174 |
yygetc (LEX_FORMALS) |
yygetc (LEX_FORMALS) |
175 |
{ |
{ |
176 |
int res = getc (yyin); |
int res = getc (yyin); |
177 |
USE_LEX_ARGS; |
USE_LEX_ARGS; |
178 |
#if YYLSP_NEEDED |
]AT_LOCATION_IF([ |
179 |
last_yylloc = LOC; |
last_yylloc = LOC; |
180 |
if (res == '\n') |
if (res == '\n') |
181 |
{ |
{ |
184 |
} |
} |
185 |
else |
else |
186 |
LOC.last_column++; |
LOC.last_column++; |
187 |
#endif |
])[ |
188 |
return res; |
return res; |
189 |
} |
} |
190 |
|
|
193 |
yyungetc (LEX_PRE_FORMALS int c) |
yyungetc (LEX_PRE_FORMALS int c) |
194 |
{ |
{ |
195 |
USE_LEX_ARGS; |
USE_LEX_ARGS; |
196 |
#if YYLSP_NEEDED |
]AT_LOCATION_IF([ |
197 |
/* Wrong when C == `\n'. */ |
/* Wrong when C == `\n'. */ |
198 |
LOC = last_yylloc; |
LOC = last_yylloc; |
199 |
#endif |
])[ |
200 |
ungetc (c, yyin); |
ungetc (c, yyin); |
201 |
} |
} |
202 |
|
|
242 |
if (init) |
if (init) |
243 |
{ |
{ |
244 |
init = 0; |
init = 0; |
245 |
#if YYLSP_NEEDED |
]AT_LOCATION_IF([ |
246 |
LOC.last_column = 1; |
LOC.last_column = 1; |
247 |
LOC.last_line = 1; |
LOC.last_line = 1; |
248 |
#endif |
])[ |
249 |
} |
} |
250 |
|
|
251 |
#if YYLSP_NEEDED |
]AT_LOCATION_IF([ |
252 |
LOC.first_column = LOC.last_column; |
LOC.first_column = LOC.last_column; |
253 |
LOC.first_line = LOC.last_line; |
LOC.first_line = LOC.last_line; |
254 |
#endif |
])[ |
255 |
|
|
256 |
/* Skip white space. */ |
/* Skip white space. */ |
257 |
while ((c = yygetc (LEX_ARGS)) == ' ' || c == '\t') |
while ((c = yygetc (LEX_ARGS)) == ' ' || c == '\t') |
258 |
{ |
{ |
259 |
#if YYLSP_NEEDED |
]AT_LOCATION_IF([ |
260 |
LOC.first_column = LOC.last_column; |
LOC.first_column = LOC.last_column; |
261 |
LOC.first_line = LOC.last_line; |
LOC.first_line = LOC.last_line; |
262 |
#endif |
])[ |
263 |
} |
} |
264 |
|
|
265 |
/* process numbers */ |
/* process numbers */ |
310 |
#if YYDEBUG |
#if YYDEBUG |
311 |
yydebug = 1; |
yydebug = 1; |
312 |
#endif |
#endif |
313 |
yyparse (&result, &count); |
yyparse (]AT_PARAM_IF([&result, &count])[); |
314 |
assert (global_result == result); |
assert (global_result == result); |
315 |
assert (global_count == count); |
assert (global_count == count); |
316 |
|
|
353 |
|
|
354 |
|
|
355 |
# _AT_CHECK_CALC_ERROR(BISON-OPTIONS, INPUT, [NUM-DEBUG-LINES], |
# _AT_CHECK_CALC_ERROR(BISON-OPTIONS, INPUT, [NUM-DEBUG-LINES], |
356 |
# [ERROR-LOCATION], [IF-YYERROR-VERBOSE]) |
# [VERBOSE-AND-LOCATED-ERROR-MESSAGE]) |
357 |
# ------------------------------------------------------------ |
# ------------------------------------------------------------- |
358 |
# Run `calc' on INPUT, and expect a `parse error' message. |
# Run `calc' on INPUT, and expect a `parse error' message. |
359 |
# |
# |
360 |
# If INPUT starts with a slash, it is used as absolute input file name, |
# If INPUT starts with a slash, it is used as absolute input file name, |
403 |
[$4 |
[$4 |
404 |
]) |
]) |
405 |
# 3. If locations are not used, remove them. |
# 3. If locations are not used, remove them. |
406 |
m4_bmatch([$1], [%locations], [], |
AT_YYERROR_SEES_LOC_IF([], |
407 |
[[sed 's/^[-0-9.]*: //' expout >at-expout |
[[sed 's/^[-0-9.]*: //' expout >at-expout |
408 |
mv at-expout expout]]) |
mv at-expout expout]]) |
409 |
# 4. If error-verbose is not used, strip the`, unexpected....' part. |
# 4. If error-verbose is not used, strip the`, unexpected....' part. |
415 |
]) |
]) |
416 |
|
|
417 |
|
|
418 |
|
# AT_CALC_PUSHDEFS($1, $2, [BISON-OPTIONS]) |
419 |
|
# ----------------------------------------- |
420 |
|
# This macro works around the impossibility to define macros |
421 |
|
# inside macros, because issuing `[$1]' is not possible in M4 :(. |
422 |
|
# This sucks hard, GNU M4 should really provide M5 like $$1. |
423 |
|
m4_define([AT_CHECK_PUSHDEFS], |
424 |
|
[m4_if([$1$2], $[1]$[2], [], |
425 |
|
[m4_fatal([$0: Invalid arguments: $@])])dnl |
426 |
|
m4_pushdef([AT_PARAM_IF], |
427 |
|
[m4_bmatch([$3], [%parse-param], [$1], [$2])]) |
428 |
|
m4_pushdef([AT_LOCATION_IF], |
429 |
|
[m4_bmatch([$3], [%locations], [$1], [$2])]) |
430 |
|
m4_pushdef([AT_PURE_IF], |
431 |
|
[m4_bmatch([$3], [%pure-parser], [$1], [$2])]) |
432 |
|
m4_pushdef([AT_GLR_IF], |
433 |
|
[m4_bmatch([$3], [%glr-parser], [$1], [$2])]) |
434 |
|
m4_pushdef([AT_PURE_AND_LOC_IF], |
435 |
|
[m4_bmatch([$3], [%locations.*%pure-parser\|%pure-parser.*%locations], |
436 |
|
[$1], [$2])]) |
437 |
|
m4_pushdef([AT_GLR_OR_PARAM_IF], |
438 |
|
[m4_bmatch([$3], [%glr-parser\|%parse-param], [$1], [$2])]) |
439 |
|
|
440 |
|
# yyerror receives the location if %location & %pure & (%glr or %parse-param). |
441 |
|
m4_pushdef([AT_YYERROR_ARG_LOC_IF], |
442 |
|
[AT_GLR_OR_PARAM_IF([AT_PURE_AND_LOC_IF([$1], [$2])], |
443 |
|
[$2])]) |
444 |
|
# yyerror cannot see the locations if !glr & pure. |
445 |
|
m4_pushdef([AT_YYERROR_SEES_LOC_IF], |
446 |
|
[AT_LOCATION_IF([AT_GLR_IF([$1], |
447 |
|
[AT_PURE_IF([$2], [$1])])], |
448 |
|
[$2])]) |
449 |
|
]) |
450 |
|
|
451 |
|
|
452 |
|
# AT_CALC_POPDEFS |
453 |
|
# --------------- |
454 |
|
m4_define([AT_CHECK_POPDEFS], |
455 |
|
[m4_popdef([AT_YYERROR_SEES_LOC_IF]) |
456 |
|
m4_popdef([AT_YYERROR_ARG_LOC_IF]) |
457 |
|
m4_popdef([AT_GLR_OR_PARAM_IF]) |
458 |
|
m4_popdef([AT_PURE_AND_LOC_IF]) |
459 |
|
m4_popdef([AT_GLR_IF]) |
460 |
|
m4_popdef([AT_LOCATION_IF]) |
461 |
|
m4_popdef([AT_PARAM_IF]) |
462 |
|
]) |
463 |
|
|
464 |
|
|
465 |
|
|
466 |
# AT_CHECK_CALC([BISON-OPTIONS]) |
# AT_CHECK_CALC([BISON-OPTIONS]) |
467 |
# ------------------------------ |
# ------------------------------ |
468 |
# Start a testing chunk which compiles `calc' grammar with |
# Start a testing chunk which compiles `calc' grammar with |
471 |
[# We use integers to avoid dependencies upon the precision of doubles. |
[# We use integers to avoid dependencies upon the precision of doubles. |
472 |
AT_SETUP([Calculator $1]) |
AT_SETUP([Calculator $1]) |
473 |
|
|
474 |
|
AT_CHECK_PUSHDEFS($[1], $[2], [$1]) |
475 |
|
|
476 |
AT_DATA_CALC_Y([$1]) |
AT_DATA_CALC_Y([$1]) |
477 |
|
|
478 |
# Specify the output files to avoid problems on different file systems. |
# Specify the output files to avoid problems on different file systems. |
524 |
1.15-1.16: parse error, unexpected "number" |
1.15-1.16: parse error, unexpected "number" |
525 |
calc: error: 0 != 1]) |
calc: error: 0 != 1]) |
526 |
|
|
527 |
|
AT_CHECK_POPDEFS |
528 |
|
|
529 |
AT_CLEANUP |
AT_CLEANUP |
530 |
])# AT_CHECK_CALC |
])# AT_CHECK_CALC |
531 |
|
|
561 |
AT_CHECK_CALC_LALR([%debug]) |
AT_CHECK_CALC_LALR([%debug]) |
562 |
AT_CHECK_CALC_LALR([%error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) |
AT_CHECK_CALC_LALR([%error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) |
563 |
|
|
564 |
# AT_CHECK_CALC_LALR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) |
AT_CHECK_CALC_LALR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) |
565 |
|
|
566 |
|
AT_CHECK_CALC_LALR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc %parse-param "value_t *result", "result" %parse-param "int *count", "count"]) |
567 |
|
|
568 |
|
|
569 |
# ----------------------- # |
# ----------------------- # |
596 |
AT_CHECK_CALC_GLR([%debug]) |
AT_CHECK_CALC_GLR([%debug]) |
597 |
AT_CHECK_CALC_GLR([%error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) |
AT_CHECK_CALC_GLR([%error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) |
598 |
|
|
599 |
# AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) |
AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) |
600 |
|
|
601 |
|
AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc %parse-param "value_t *result", "result" %parse-param "int *count", "count"]) |