]> git.saurik.com Git - bison.git/blame_incremental - tests/calc.at
* src/symlist.h, src/symlist.c (symbol_list_length): New.
[bison.git] / tests / calc.at
... / ...
CommitLineData
1# Checking the output filenames. -*- Autotest -*-
2# Copyright (C) 2000, 2001, 2002 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
19AT_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.
37m4_define([_AT_DATA_CALC_Y],
38[m4_if([$1$2$3], $[1]$[2]$[3], [],
39 [m4_fatal([$0: Invalid arguments: $@])])dnl
40AT_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
53char *strcat(char *dest, const char *src);
54#endif
55#include <ctype.h>
56
57static int power (int base, int exponent);
58static void yyerror (const char *s);
59static int yylex (void);
60static int yygetc (void);
61static void yyungetc (int c);
62
63extern void perror (const char *s);
64
65/* Exercise pre-prologue dependency to %union. */
66typedef int value_t;
67
68%}
69
70/* Exercise M4 quoting: '@:>@@:>@', 0. */
71
72/* Also exercise %union. */
73%union
74{
75 value_t ival; /* A comment to exercise an old bug. */
76};
77
78/* Exercise post-prologue dependency to %union. */
79%{
80static void id (YYSTYPE *lval);
81
82/* Exercise quotes in declarations. */
83char quote[] = "@:>@@:>@,";
84%}
85
86/* Bison Declarations */
87%token CALC_EOF 0 "end of file"
88%token <ival> NUM "number"
89%type <ival> exp
90
91/* Exercise quotes in strings. */
92%token FAKE "fake @>:@@>:@,"
93
94%nonassoc '=' /* comparison */
95%left '-' '+'
96%left '*' '/'
97%left NEG /* negation--unary minus */
98%right '^' /* exponentiation */
99
100]$4[
101
102/* Grammar follows */
103%%
104input:
105 line
106| input line
107;
108
109line:
110 '\n'
111| exp '\n'
112 {
113 /* Exercise quotes in braces. */
114 char tmp[] = "@>:@@:>@,";
115 }
116;
117
118/* Exercise M4 quoting: '@:>@@:>@', 1. */
119exp:
120 NUM { $$ = $1; }
121| exp '=' exp
122 {
123 if ($1 != $3)
124 fprintf (stderr, "calc: error: %d != %d\n", $1, $3);
125 $$ = $1 == $3;
126 }
127| exp '+' exp { $$ = $1 + $3; }
128| exp '-' exp { $$ = $1 - $3; }
129| exp '*' exp { $$ = $1 * $3; }
130| exp '/' exp { $$ = $1 / $3; }
131| '-' exp %prec NEG { $$ = -$2; }
132| exp '^' exp { $$ = power ($1, $3); }
133| '(' exp ')' { $$ = $2; }
134| '(' error ')' { $$ = 0; }
135;
136%%
137/* The input. */
138FILE *yyin;
139
140/* Exercise M4 quoting: '@:>@@:>@', 2. */
141static void
142yyerror (const char *s)
143{
144#if YYLSP_NEEDED
145 fprintf (stderr, "%d.%d-%d.%d: ",
146 yylloc.first_line, yylloc.first_column,
147 yylloc.last_line, yylloc.last_column);
148#endif
149 fprintf (stderr, "%s\n", s);
150}
151
152
153#if YYLSP_NEEDED
154static YYLTYPE last_yylloc;
155#endif
156static int
157yygetc (void)
158{
159 int res = getc (yyin);
160#if YYLSP_NEEDED
161 last_yylloc = yylloc;
162 if (res == '\n')
163 {
164 yylloc.last_line++;
165 yylloc.last_column = 1;
166 }
167 else
168 yylloc.last_column++;
169#endif
170 return res;
171}
172
173
174static void
175yyungetc (int c)
176{
177#if YYLSP_NEEDED
178 /* Wrong when C == `\n'. */
179 yylloc = last_yylloc;
180#endif
181 ungetc (c, yyin);
182}
183
184static int
185read_signed_integer (void)
186{
187 int c = yygetc ();
188 int sign = 1;
189 int n = 0;
190
191 if (c == '-')
192 {
193 c = yygetc ();
194 sign = -1;
195 }
196
197 while (isdigit (c))
198 {
199 n = 10 * n + (c - '0');
200 c = yygetc ();
201 }
202
203 yyungetc (c);
204
205 return sign * n;
206}
207
208
209
210/*---------------------------------------------------------------.
211| Lexical analyzer returns an integer on the stack and the token |
212| NUM, or the ASCII character read if not a number. Skips all |
213| blanks and tabs, returns 0 for EOF. |
214`---------------------------------------------------------------*/
215
216static int
217yylex (void)
218{
219 int c;
220
221#if YYLSP_NEEDED
222 yylloc.first_column = yylloc.last_column;
223 yylloc.first_line = yylloc.last_line;
224#endif
225
226 /* Skip white space. */
227 while ((c = yygetc ()) == ' ' || c == '\t')
228 {
229#if YYLSP_NEEDED
230 yylloc.first_column = yylloc.last_column;
231 yylloc.first_line = yylloc.last_line;
232#endif
233 }
234
235 /* process numbers */
236 if (c == '.' || isdigit (c))
237 {
238 yyungetc (c);
239 yylval.ival = read_signed_integer ();
240 return NUM;
241 }
242
243 /* Return end-of-file. */
244 if (c == EOF)
245 return CALC_EOF;
246
247 /* Return single chars. */
248 return c;
249}
250
251static int
252power (int base, int exponent)
253{
254 int res = 1;
255 if (exponent < 0)
256 exit (1);
257 for (/* Niente */; exponent; --exponent)
258 res *= base;
259 return res;
260}
261
262void
263id (YYSTYPE* lval)
264{
265}
266
267int
268main (int argc, const char **argv)
269{
270 yyin = NULL;
271
272 if (argc == 2)
273 yyin = fopen (argv[1], "r");
274 else
275 yyin = stdin;
276
277 if (!yyin)
278 {
279 perror (argv[1]);
280 exit (1);
281 }
282
283#if YYDEBUG
284 yydebug = 1;
285#endif
286#if YYLSP_NEEDED
287 yylloc.last_column = 1;
288 yylloc.last_line = 1;
289#endif
290 yyparse ();
291 return 0;
292}
293]])
294])# _AT_DATA_CALC_Y
295
296
297# AT_DATA_CALC_Y([BISON-OPTIONS])
298# -------------------------------
299# Produce `calc.y'.
300m4_define([AT_DATA_CALC_Y],
301[_AT_DATA_CALC_Y($[1], $[2], $[3],
302 [m4_bmatch([$1], [--yyerror-verbose],
303 [[%error-verbose]])])])
304
305
306
307# _AT_CHECK_CALC(BISON-OPTIONS, INPUT, [NUM-STDERR-LINES = 0])
308# ------------------------------------------------------------
309# Run `calc' on INPUT and expect no STDOUT nor STDERR.
310#
311# If BISON-OPTIONS contains `--debug', then NUM-STDERR-LINES is the number
312# of expected lines on stderr.
313m4_define([_AT_CHECK_CALC],
314[AT_DATA([[input]],
315[[$2
316]])
317AT_CHECK([./calc input], 0, [], [stderr])dnl
318AT_CHECK([wc -l <stderr | sed 's/[[^0-9]]//g'], 0,
319 [m4_bmatch([$1], [--debug],
320 [$3], [0])
321])
322])
323
324
325# _AT_CHECK_CALC_ERROR(BISON-OPTIONS, INPUT, [NUM-DEBUG-LINES],
326# [ERROR-LOCATION], [IF-YYERROR-VERBOSE])
327# ------------------------------------------------------------
328# Run `calc' on INPUT, and expect a `parse error' message.
329#
330# If INPUT starts with a slash, it is used as absolute input file name,
331# otherwise as contents.
332#
333# If BISON-OPTIONS contains `--location', then make sure the ERROR-LOCATION
334# is correctly output on stderr.
335#
336# If BISON-OPTIONS contains `--yyerror-verbose', then make sure the
337# IF-YYERROR-VERBOSE message is properly output after `parse error, '
338# on STDERR.
339#
340# If BISON-OPTIONS contains `--debug', then NUM-STDERR-LINES is the number
341# of expected lines on stderr.
342m4_define([_AT_CHECK_CALC_ERROR],
343[m4_bmatch([$2], [^/],
344 [AT_CHECK([./calc $2], 0, [], [stderr])],
345 [AT_DATA([[input]],
346[[$2
347]])
348AT_CHECK([./calc input], 0, [], [stderr])])
349
350m4_bmatch([$1], [--debug],
351[AT_CHECK([wc -l <stderr | sed 's/[[^0-9]]//g'], 0, [$3
352])])
353
354# Normalize the observed and expected error messages, depending upon the
355# options.
356# 1. Remove the traces from observed.
357egrep -v '^((Start|Enter|Read|Reduc|Shift)ing|state|Error:|Next|Discarding) ' stderr >at-stderr
358mv at-stderr stderr
359# 2. Create the reference error message.
360AT_DATA([[expout]],
361[$4
362])
363# 3. If locations are not used, remove them.
364m4_bmatch([$1], [--location], [],
365[[sed 's/^[-0-9.]*: //' expout >at-expout
366mv at-expout expout]])
367# 4. If error-verbose is not used, strip the`, unexpected....' part.
368m4_bmatch([$1], [--yyerror-verbose], [],
369[[sed 's/parse error, .*$/parse error/' expout >at-expout
370mv at-expout expout]])
371# 5. Check
372AT_CHECK([cat stderr], 0, [expout])
373])
374
375
376# AT_CHECK_CALC([BISON-OPTIONS], [PARSER-EXPECTED-STDERR])
377# --------------------------------------------------------
378# Start a testing chunk which compiles `calc' grammar with
379# BISON-OPTIONS, and performs several tests over the parser.
380m4_define([AT_CHECK_CALC],
381[# We use integers to avoid dependencies upon the precision of doubles.
382AT_SETUP([Calculator $1])
383
384AT_DATA_CALC_Y([$1])
385
386# Specify the output files to avoid problems on different file systems.
387AT_CHECK([bison calc.y -o calc.c m4_bpatsubst([$1], [--yyerror-verbose])],
388 [0], [], [])
389
390AT_CHECK([$CC $CFLAGS $CPPFLAGS calc.c -o calc], 0, [], [ignore])
391
392# Test the priorities.
393_AT_CHECK_CALC([$1],
394[1 + 2 * 3 = 7
3951 + 2 * -3 = -5
396
397-1^2 = -1
398(-1)^2 = 1
399
400---1 = -1
401
4021 - 2 - 3 = -4
4031 - (2 - 3) = 2
404
4052^2^3 = 256
406(2^2)^3 = 64], [486])
407
408# Some parse errors.
409_AT_CHECK_CALC_ERROR([$1], [0 0], [11],
410 [1.3-1.4: parse error, unexpected "number"])
411_AT_CHECK_CALC_ERROR([$1], [1//2], [15],
412 [1.3-1.4: parse error, unexpected '/', expecting "number" or '-' or '('])
413_AT_CHECK_CALC_ERROR([$1], [error], [4],
414 [1.1-1.2: parse error, unexpected $undefined., expecting "number" or '-' or '\n' or '('])
415_AT_CHECK_CALC_ERROR([$1], [1 = 2 = 3], [22],
416 [1.7-1.8: parse error, unexpected '='])
417_AT_CHECK_CALC_ERROR([$1],
418 [
419+1],
420 [14],
421 [2.1-2.2: parse error, unexpected '+'])
422# Exercise error messages with EOF: work on an empty file.
423_AT_CHECK_CALC_ERROR([$1],
424 [/dev/null],
425 [4],
426 [1.1-1.2: parse error, unexpected "end of file", expecting "number" or '-' or '\n' or '('])
427
428# Exercise the error token: without it, we die at the first error,
429# hence be sure i. to have several errors, ii. to test the action
430# associated to `error'.
431_AT_CHECK_CALC_ERROR([$1],
432 [(1 ++ 2) + (0 0) = 1],
433 [82],
434[1.5-1.6: parse error, unexpected '+', expecting "number" or '-' or '('
4351.15-1.16: parse error, unexpected "number"
436calc: error: 0 != 1])
437
438# Add a studid example demonstrating that Bison can further improve the
439# error message. FIXME: Fix this ridiculous message.
440_AT_CHECK_CALC_ERROR([$1],
441 [()],
442 [21],
443[1.2-1.3: parse error, unexpected ')', expecting error or "number" or '-' or '('])
444
445AT_CLEANUP
446])# AT_CHECK_CALC
447
448
449
450
451# ------------------ #
452# Test the parsers. #
453# ------------------ #
454
455AT_CHECK_CALC()
456
457AT_CHECK_CALC([--defines])
458AT_CHECK_CALC([--locations])
459AT_CHECK_CALC([--name-prefix=calc])
460AT_CHECK_CALC([--verbose])
461AT_CHECK_CALC([--yacc])
462AT_CHECK_CALC([--yyerror-verbose])
463
464AT_CHECK_CALC([--locations --yyerror-verbose])
465
466AT_CHECK_CALC([--defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])
467
468AT_CHECK_CALC([--debug])
469AT_CHECK_CALC([--debug --defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])