]> git.saurik.com Git - bison.git/blob - tests/calc.at
* src/gram.h, src/gram.c (symbols): New, similar to state_table
[bison.git] / tests / calc.at
1 # Checking the output filenames. -*- Autotest -*-
2 # Copyright 2000, 2001 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., 59 Temple Place - Suite 330, Boston, MA
17 # 02111-1307, USA.
18
19 AT_BANNER([[Simple Calculator.]])
20
21 ## ---------------------------------------------------- ##
22 ## Compile the grammar described in the documentation. ##
23 ## ---------------------------------------------------- ##
24
25
26 # ------------------------- #
27 # Helping Autotest macros. #
28 # ------------------------- #
29
30
31 # _AT_DATA_CALC_Y($1, $2, $3, [CPP-DIRECTIVES])
32 # ---------------------------------------------
33 # Produce `calc.y'. Don't call this macro directly, because it contains
34 # some occurrences of `$1' etc. which will be interpreted by m4. So
35 # you should call it with $1, $2, and $3 as arguments, which is what
36 # AT_DATA_CALC_Y does.
37 m4_define([_AT_DATA_CALC_Y],
38 [m4_if([$1$2$3], $[1]$[2]$[3], [],
39 [m4_fatal([$0: Invalid arguments: $@])])dnl
40 AT_DATA([calc.y],
41 [[/* Infix notation calculator--calc */
42
43 %{
44 #include <config.h>
45 /* We don't need a perfect malloc for these tests. */
46 #undef malloc
47 #include <stdio.h>
48
49 #if STDC_HEADERS
50 # include <stdlib.h>
51 # include <string.h>
52 #else
53 char *strcat(char *dest, const char *src);
54 #endif
55 #include <ctype.h>
56
57 static int power (int base, int exponent);
58 static void yyerror (const char *s);
59 static int yylex (void);
60 static int yygetc (void);
61 static void yyungetc (int c);
62
63 extern void perror (const char *s);
64 %}
65
66 /* Also exercise %union. */
67 %union
68 {
69 int ival; /* A comment to exercise an old bug. */
70 };
71
72 /* Bison Declarations */
73 %token CALC_EOF 0 "end of file"
74 %token <ival> NUM "number"
75 %type <ival> exp
76
77 %nonassoc '=' /* comparison */
78 %left '-' '+'
79 %left '*' '/'
80 %left NEG /* negation--unary minus */
81 %right '^' /* exponentiation */
82
83 ]$4[
84
85 /* Grammar follows */
86 %%
87 input:
88 line
89 | input line
90 ;
91
92 line:
93 '\n'
94 | exp '\n' {}
95 ;
96
97 exp:
98 NUM { $$ = $1; }
99 | exp '=' exp
100 {
101 if ($1 != $3)
102 printf ("calc: error: %d != %d\n", $1, $3);
103 $$ = $1 == $3;
104 }
105 | exp '+' exp { $$ = $1 + $3; }
106 | exp '-' exp { $$ = $1 - $3; }
107 | exp '*' exp { $$ = $1 * $3; }
108 | exp '/' exp { $$ = $1 / $3; }
109 | '-' exp %prec NEG { $$ = -$2; }
110 | exp '^' exp { $$ = power ($1, $3); }
111 | '(' exp ')' { $$ = $2; }
112 ;
113 %%
114 /* The input. */
115 FILE *yyin;
116
117 static void
118 yyerror (const char *s)
119 {
120 #if YYLSP_NEEDED
121 fprintf (stderr, "%d.%d:%d.%d: ",
122 yylloc.first_line, yylloc.first_column,
123 yylloc.last_line, yylloc.last_column);
124 #endif
125 fprintf (stderr, "%s\n", s);
126 }
127
128
129 #if YYLSP_NEEDED
130 static YYLTYPE last_yylloc;
131 #endif
132 static int
133 yygetc (void)
134 {
135 int res = getc (yyin);
136 #if YYLSP_NEEDED
137 last_yylloc = yylloc;
138 if (res == '\n')
139 {
140 yylloc.last_line++;
141 yylloc.last_column = 0;
142 }
143 else
144 yylloc.last_column++;
145 #endif
146 return res;
147 }
148
149
150 static void
151 yyungetc (int c)
152 {
153 #if YYLSP_NEEDED
154 /* Wrong when C == `\n'. */
155 yylloc = last_yylloc;
156 #endif
157 ungetc (c, yyin);
158 }
159
160 static int
161 read_signed_integer (void)
162 {
163 int c = yygetc ();
164 int sign = 1;
165 int n = 0;
166
167 if (c == '-')
168 {
169 c = yygetc ();
170 sign = -1;
171 }
172
173 while (isdigit (c))
174 {
175 n = 10 * n + (c - '0');
176 c = yygetc ();
177 }
178
179 yyungetc (c);
180
181 return sign * n;
182 }
183
184
185
186 /*---------------------------------------------------------------.
187 | Lexical analyzer returns an integer on the stack and the token |
188 | NUM, or the ASCII character read if not a number. Skips all |
189 | blanks and tabs, returns 0 for EOF. |
190 `---------------------------------------------------------------*/
191
192 static int
193 yylex (void)
194 {
195 int c;
196
197 #if YYLSP_NEEDED
198 yylloc.first_column = yylloc.last_column;
199 yylloc.first_line = yylloc.last_line;
200 #endif
201
202 /* Skip white space. */
203 while ((c = yygetc ()) == ' ' || c == '\t')
204 {
205 #if YYLSP_NEEDED
206 yylloc.first_column = yylloc.last_column;
207 yylloc.first_line = yylloc.last_line;
208 #endif
209 }
210
211 /* process numbers */
212 if (c == '.' || isdigit (c))
213 {
214 yyungetc (c);
215 yylval.ival = read_signed_integer ();
216 return NUM;
217 }
218
219 /* Return end-of-file. */
220 if (c == EOF)
221 return CALC_EOF;
222
223 /* Return single chars. */
224 return c;
225 }
226
227 static int
228 power (int base, int exponent)
229 {
230 int res = 1;
231 if (exponent < 0)
232 exit (1);
233 for (/* Niente */; exponent; --exponent)
234 res *= base;
235 return res;
236 }
237
238 int
239 main (int argc, const char **argv)
240 {
241 yyin = NULL;
242
243 if (argc == 2)
244 yyin = fopen (argv[1], "r");
245 else
246 yyin = stdin;
247
248 if (!yyin)
249 {
250 perror (argv[1]);
251 exit (1);
252 }
253
254 #if YYDEBUG
255 yydebug = 1;
256 #endif
257 #if YYLSP_NEEDED
258 yylloc.last_column = 0;
259 yylloc.last_line = 1;
260 #endif
261 yyparse ();
262 return 0;
263 }
264 ]])
265 ])# _AT_DATA_CALC_Y
266
267
268 # AT_DATA_CALC_Y([BISON-OPTIONS])
269 # -------------------------------
270 # Produce `calc.y'.
271 m4_define([AT_DATA_CALC_Y],
272 [_AT_DATA_CALC_Y($[1], $[2], $[3],
273 [m4_bmatch([$1], [--yyerror-verbose],
274 [[%error-verbose]])])])
275
276
277
278 # _AT_CHECK_CALC(BISON-OPTIONS, INPUT, [NUM-STDERR-LINES = 0])
279 # ------------------------------------------------------------
280 # Run `calc' on INPUT and expect no STDOUT nor STDERR.
281 #
282 # If BISON-OPTIONS contains `--debug', then NUM-STDERR-LINES is the number
283 # of expected lines on stderr.
284 m4_define([_AT_CHECK_CALC],
285 [AT_DATA([[input]],
286 [[$2
287 ]])
288 AT_CHECK([calc input], 0, [], [stderr])dnl
289 AT_CHECK([wc -l <stderr | sed 's/[[^0-9]]//g'], 0,
290 [m4_bmatch([$1], [--debug],
291 [$3], [0])
292 ])
293 ])
294
295
296 # _AT_CHECK_CALC_ERROR(BISON-OPTIONS, INPUT, [NUM-DEBUG-LINES],
297 # [ERROR-LOCATION], [IF-YYERROR-VERBOSE])
298 # ------------------------------------------------------------
299 # Run `calc' on INPUT, and expect a `parse error' message.
300 #
301 # If INPUT starts with a slash, it is used as absolute input file name,
302 # otherwise as contents.
303 #
304 # If BISON-OPTIONS contains `--location', then make sure the ERROR-LOCATION
305 # is correctly output on stderr.
306 #
307 # If BISON-OPTIONS contains `--yyerror-verbose', then make sure the
308 # IF-YYERROR-VERBOSE message is properly output after `parse error, '
309 # on STDERR.
310 #
311 # If BISON-OPTIONS contains `--debug', then NUM-STDERR-LINES is the number
312 # of expected lines on stderr.
313 m4_define([_AT_CHECK_CALC_ERROR],
314 [m4_bmatch([$2], [^/],
315 [AT_CHECK([calc $2], 0, [], [stderr])],
316 [AT_DATA([[input]],
317 [[$2
318 ]])
319 AT_CHECK([calc input], 0, [], [stderr])])
320
321
322 AT_CHECK([wc -l <stderr | sed 's/[[^0-9]]//g'], 0,
323 [m4_bmatch([$1], [--debug],
324 [$3], [1])
325 ])
326
327 egrep -v '^((Start|Enter|Read|Reduc|Shift)ing|state|Error:) ' stderr >at-stderr
328 mv at-stderr stderr
329
330 AT_CHECK([cat stderr], 0,
331 [m4_bmatch([$1], [--location], [$4: ])[]dnl
332 parse error[]dnl
333 m4_bmatch([$1], [--yyerror-verbose], [, $5])[]dnl
334
335 ])
336
337 ])
338
339
340 # AT_CHECK_CALC([BISON-OPTIONS], [PARSER-EXPECTED-STDERR])
341 # --------------------------------------------------------
342 # Start a testing chunk which compiles `calc' grammar with
343 # BISON-OPTIONS, and performs several tests over the parser.
344 m4_define([AT_CHECK_CALC],
345 [# We use integers to avoid dependencies upon the precision of doubles.
346 AT_SETUP([Calculator $1])
347
348 AT_DATA_CALC_Y([$1])
349
350 # Specify the output files to avoid problems on different file systems.
351 AT_CHECK([bison calc.y -o calc.c m4_bpatsubst([$1], [--yyerror-verbose])],
352 [0], [], [])
353
354 # Some compilers issue warnings we don't want to hear about.
355 # Maybe some day we will have proper Autoconf macros to disable these
356 # warnings, but this place is not the right one for that.
357 # So let's keep only GCC warnings, which we know are sane.
358 # Well, that's only part of the story: some assemblers issue warnings
359 # which can be totally useless, and actually polluting. It seems that
360 # the best bet be to completely ignore stderr, but to pass -Werror
361 # to GCC.
362 if test "$GCC" = yes; then
363 CFLAGS="$CFLAGS -Werror"
364 fi
365 AT_CHECK([$CC $CFLAGS $CPPFLAGS calc.c -o calc], 0, [], [ignore])
366
367 # Test the priorities.
368 _AT_CHECK_CALC([$1],
369 [1 + 2 * 3 = 7
370 1 + 2 * -3 = -5
371
372 -1^2 = -1
373 (-1)^2 = 1
374
375 ---1 = -1
376
377 1 - 2 - 3 = -4
378 1 - (2 - 3) = 2
379
380 2^2^3 = 256
381 (2^2)^3 = 64], [486])
382
383 # Some parse errors.
384 _AT_CHECK_CALC_ERROR([$1], [0 0], [10],
385 [1.2:1.3],
386 [unexpected "number"])
387 _AT_CHECK_CALC_ERROR([$1], [1//2], [13],
388 [1.2:1.3],
389 [unexpected '/', expecting "number" or '-' or '('])
390 _AT_CHECK_CALC_ERROR([$1], [error], [4],
391 [1.0:1.1],
392 [unexpected $undefined., expecting "number" or '-' or '\n' or '('])
393 _AT_CHECK_CALC_ERROR([$1], [1 = 2 = 3], [19],
394 [1.6:1.7],
395 [unexpected '='])
396 _AT_CHECK_CALC_ERROR([$1],
397 [
398 +1],
399 [13],
400 [2.0:2.1],
401 [unexpected '+'])
402 # Exercise error messages with EOF: work on an empty file.
403 _AT_CHECK_CALC_ERROR([$1],
404 [/dev/null],
405 [4],
406 [1.0:1.1],
407 [unexpected "end of file", expecting "number" or '-' or '\n' or '('])
408
409 AT_CLEANUP
410 ])# AT_CHECK_CALC
411
412
413
414
415 # ------------------ #
416 # Test the parsers. #
417 # ------------------ #
418
419 AT_CHECK_CALC()
420
421 AT_CHECK_CALC([--defines])
422 AT_CHECK_CALC([--locations])
423 AT_CHECK_CALC([--name-prefix=calc])
424 AT_CHECK_CALC([--verbose])
425 AT_CHECK_CALC([--yacc])
426 AT_CHECK_CALC([--yyerror-verbose])
427
428 AT_CHECK_CALC([--locations --yyerror-verbose])
429
430 AT_CHECK_CALC([--defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])
431
432 AT_CHECK_CALC([--debug])
433 AT_CHECK_CALC([--debug --defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])