]> git.saurik.com Git - bison.git/blame_incremental - tests/calc.at
Really add m4sugar to the repo.
[bison.git] / tests / calc.at
... / ...
CommitLineData
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
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
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%%
87input:
88 line
89| input line
90;
91
92line:
93 '\n'
94| exp '\n' {}
95;
96
97exp:
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. */
115FILE *yyin;
116
117static void
118yyerror (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
130static YYLTYPE last_yylloc;
131#endif
132static int
133yygetc (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
150static void
151yyungetc (int c)
152{
153#if YYLSP_NEEDED
154 /* Wrong when C == `\n'. */
155 yylloc = last_yylloc;
156#endif
157 ungetc (c, yyin);
158}
159
160static int
161read_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
192static int
193yylex (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
227static int
228power (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
238int
239main (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'.
271m4_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.
284m4_define([_AT_CHECK_CALC],
285[AT_DATA([[input]],
286[[$2
287]])
288AT_CHECK([./calc input], 0, [], [stderr])dnl
289AT_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.
313m4_define([_AT_CHECK_CALC_ERROR],
314[m4_bmatch([$2], [^/],
315 [AT_CHECK([./calc $2], 0, [], [stderr])],
316 [AT_DATA([[input]],
317[[$2
318]])
319AT_CHECK([./calc input], 0, [], [stderr])])
320
321
322AT_CHECK([wc -l <stderr | sed 's/[[^0-9]]//g'], 0,
323 [m4_bmatch([$1], [--debug],
324 [$3], [1])
325])
326
327egrep -v '^((Start|Enter|Read|Reduc|Shift)ing|state|Error:) ' stderr >at-stderr
328mv at-stderr stderr
329
330AT_CHECK([cat stderr], 0,
331[m4_bmatch([$1], [--location], [$4: ])[]dnl
332parse error[]dnl
333m4_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.
344m4_define([AT_CHECK_CALC],
345[# We use integers to avoid dependencies upon the precision of doubles.
346AT_SETUP([Calculator $1])
347
348AT_DATA_CALC_Y([$1])
349
350# Specify the output files to avoid problems on different file systems.
351AT_CHECK([bison calc.y -o calc.c m4_bpatsubst([$1], [--yyerror-verbose])],
352 [0], [], [])
353
354AT_CHECK([$CC $CFLAGS $CPPFLAGS calc.c -o calc], 0, [], [ignore])
355
356# Test the priorities.
357_AT_CHECK_CALC([$1],
358[1 + 2 * 3 = 7
3591 + 2 * -3 = -5
360
361-1^2 = -1
362(-1)^2 = 1
363
364---1 = -1
365
3661 - 2 - 3 = -4
3671 - (2 - 3) = 2
368
3692^2^3 = 256
370(2^2)^3 = 64], [486])
371
372# Some parse errors.
373_AT_CHECK_CALC_ERROR([$1], [0 0], [10],
374 [1.2:1.3],
375 [unexpected "number"])
376_AT_CHECK_CALC_ERROR([$1], [1//2], [13],
377 [1.2:1.3],
378 [unexpected '/', expecting "number" or '-' or '('])
379_AT_CHECK_CALC_ERROR([$1], [error], [4],
380 [1.0:1.1],
381 [unexpected $undefined., expecting "number" or '-' or '\n' or '('])
382_AT_CHECK_CALC_ERROR([$1], [1 = 2 = 3], [19],
383 [1.6:1.7],
384 [unexpected '='])
385_AT_CHECK_CALC_ERROR([$1],
386 [
387+1],
388 [13],
389 [2.0:2.1],
390 [unexpected '+'])
391# Exercise error messages with EOF: work on an empty file.
392_AT_CHECK_CALC_ERROR([$1],
393 [/dev/null],
394 [4],
395 [1.0:1.1],
396 [unexpected "end of file", expecting "number" or '-' or '\n' or '('])
397
398AT_CLEANUP
399])# AT_CHECK_CALC
400
401
402
403
404# ------------------ #
405# Test the parsers. #
406# ------------------ #
407
408AT_CHECK_CALC()
409
410AT_CHECK_CALC([--defines])
411AT_CHECK_CALC([--locations])
412AT_CHECK_CALC([--name-prefix=calc])
413AT_CHECK_CALC([--verbose])
414AT_CHECK_CALC([--yacc])
415AT_CHECK_CALC([--yyerror-verbose])
416
417AT_CHECK_CALC([--locations --yyerror-verbose])
418
419AT_CHECK_CALC([--defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])
420
421AT_CHECK_CALC([--debug])
422AT_CHECK_CALC([--debug --defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])