]> git.saurik.com Git - bison.git/blob - tests/calc.at
* tests/Makefile.am (check-local): Ship testsuite.
[bison.git] / tests / calc.at
1 # -*- Autoconf -*-
2
3 cat <<EOF
4
5 Simple Calculator.
6
7 EOF
8
9
10 ## ---------------------------------------------------- ##
11 ## Compile the grammar described in the documentation. ##
12 ## ---------------------------------------------------- ##
13
14
15 # ------------------------- #
16 # Helping Autotest macros. #
17 # ------------------------- #
18
19
20 # _AT_DATA_CALC_Y($1, $2, $3, [CPP-DIRECTIVES])
21 # ---------------------------------------------
22 # Produce `calc.y'. Don't call this macro directly, because it contains
23 # some occurrences of `$1' etc. which will be interpreted by m4. So
24 # you should call it with $1, $2, and $3 as arguments, which is what
25 # AT_DATA_CALC_Y does.
26 AT_DEFINE([_AT_DATA_CALC_Y],
27 [ifelse([$1$2$3],
28 $[1]$[2]$[3], [],
29 [errprint([$0: Invalid arguments: $@
30 ])m4exit(1)])dnl
31 AT_DATA([calc.y],
32 [[/* Infix notation calculator--calc */
33
34 %{
35 #include <config.h>
36 #include <stdio.h>
37
38 #if STDC_HEADERS
39 # include <stdlib.h>
40 # include <string.h>
41 #else
42 char *strcat(char *dest, const char *src);
43 #endif
44 #include <ctype.h>
45 ]$4[
46
47 static int power (int base, int exponent);
48 static void yyerror (const char *s);
49 static int yylex (void);
50 static int yygetc (void);
51 static void yyungetc (int c);
52
53 extern void perror (const char *s);
54 %}
55
56 /* BISON Declarations */
57 %token NUM
58
59 %nonassoc '=' /* comparison */
60 %left '-' '+'
61 %left '*' '/'
62 %left NEG /* negation--unary minus */
63 %right '^' /* exponentiation */
64
65 /* Grammar follows */
66 %%
67 input:
68 /* empty string */
69 | input line
70 ;
71
72 line:
73 '\n'
74 | exp '\n'
75 ;
76
77 exp:
78 NUM { $$ = $1; }
79 | exp '=' exp
80 {
81 if ($1 != $3)
82 printf ("calc: error: %d != %d\n", $1, $3);
83 $$ = $1 == $3;
84 }
85 | exp '+' exp { $$ = $1 + $3; }
86 | exp '-' exp { $$ = $1 - $3; }
87 | exp '*' exp { $$ = $1 * $3; }
88 | exp '/' exp { $$ = $1 / $3; }
89 | '-' exp %prec NEG { $$ = -$2; }
90 | exp '^' exp { $$ = power ($1, $3); }
91 | '(' exp ')' { $$ = $2; }
92 ;
93 %%
94 /* The input. */
95 FILE *yyin;
96
97 static void
98 yyerror (const char *s)
99 {
100 #if YYLSP_NEEDED
101 fprintf (stderr, "%d.%d:%d.%d: ",
102 yylloc.first_line, yylloc.first_column,
103 yylloc.last_line, yylloc.last_column);
104 #endif
105 fprintf (stderr, "%s\n", s);
106 }
107
108 static int
109 yygetc (void)
110 {
111 int res = getc (yyin);
112 #if YYLSP_NEEDED
113 if (res == '\n')
114 {
115 yylloc.last_line++;
116 yylloc.last_column = 0;
117 }
118 else
119 yylloc.last_column++;
120 #endif
121 return res;
122 }
123
124
125 static void
126 yyungetc (int c)
127 {
128 #if YYLSP_NEEDED
129 /* Wrong when C == `\n'. */
130 yylloc.last_column--;
131 #endif
132 ungetc (c, yyin);
133 }
134
135 static int
136 read_signed_integer (void)
137 {
138 int c = yygetc ();
139 int sign = 1;
140 int n = 0;
141
142 if (c == '-')
143 {
144 c = yygetc ();
145 sign = -1;
146 }
147
148 while (isdigit (c))
149 {
150 n = 10 * n + (c - '0');
151 c = yygetc ();
152 }
153
154 yyungetc (c);
155
156 return sign * n;
157 }
158
159
160
161 /*---------------------------------------------------------------.
162 | Lexical analyzer returns an integer on the stack and the token |
163 | NUM, or the ASCII character read if not a number. Skips all |
164 | blanks and tabs, returns 0 for EOF. |
165 `---------------------------------------------------------------*/
166
167 static int
168 yylex (void)
169 {
170 int c;
171
172 #if YYLSP_NEEDED
173 yylloc.first_column = yylloc.last_column;
174 yylloc.first_line = yylloc.last_line;
175 #endif
176
177 /* Skip white space. */
178 while ((c = yygetc ()) == ' ' || c == '\t')
179 {
180 #if YYLSP_NEEDED
181 yylloc.first_column = yylloc.last_column;
182 yylloc.first_line = yylloc.last_line;
183 #endif
184 }
185
186 /* process numbers */
187 if (c == '.' || isdigit (c))
188 {
189 yyungetc (c);
190 yylval = read_signed_integer ();
191 return NUM;
192 }
193
194 /* Return end-of-file. */
195 if (c == EOF)
196 return 0;
197
198 /* Return single chars. */
199 return c;
200 }
201
202 static int
203 power (int base, int exponent)
204 {
205 int res = 1;
206 if (exponent < 0)
207 exit (1);
208 for (/* Niente */; exponent; --exponent)
209 res *= base;
210 return res;
211 }
212
213 int
214 main (int argn, const char **argv)
215 {
216 if (argn == 2)
217 yyin = fopen (argv[1], "r");
218 else
219 yyin = stdin;
220
221 if (!stdin)
222 {
223 perror (argv[1]);
224 exit (1);
225 }
226
227 #if YYDEBUG
228 yydebug = 1;
229 #endif
230 #if YYLSP_NEEDED
231 yylloc.last_column = 0;
232 yylloc.last_line = 1;
233 #endif
234 yyparse ();
235 return 0;
236 }
237 ]])
238 ])# _AT_DATA_CALC_Y
239
240
241 # AT_DATA_CALC_Y([BISON-OPTIONS])
242 # -------------------------------
243 # Produce `calc.y'.
244 AT_DEFINE([AT_DATA_CALC_Y],
245 [_AT_DATA_CALC_Y($[1], $[2], $[3],
246 [ifelse(regexp([$1], [--yyerror-verbose]),
247 [-1], [],
248 [[#define YYERROR_VERBOSE]])])])
249
250
251
252 # _AT_CHECK_CALC(BISON-OPTIONS, INPUT)
253 # ------------------------------------
254 # Run `calc' on INPUT and expect no STDOUT nor STDERR.
255 # If `--debug' is passed to bison, discard all the debugging traces
256 # preserving only the `parse errors'. Note that since there should be
257 # none, the `grep' will fail with exit status 1.
258 AT_DEFINE([_AT_CHECK_CALC],
259 [ifelse(regexp([$1], [--debug]),
260 [-1],
261 [AT_CHECK([echo "$2" | calc],
262 [0], [], [])],
263 [AT_CHECK([echo "$2" | calc 2>&1 >/dev/null | grep 'parse error' >&2],
264 [1], [], [])])])
265
266
267 # _AT_CHECK_CALC_ERROR(BISON-OPTIONS, INPUT,
268 # [ERROR-LOCATION], [IF-YYERROR-VERBOSE])
269 # ------------------------------------------------------------
270 # Run `calc' on INPUT, and expect STDERR.
271 AT_DEFINE([_AT_CHECK_CALC_ERROR],
272 [AT_CHECK([echo "$2" | calc 2>&1 >/dev/null | grep 'parse error' >&2], 0,
273 [],
274 [ifelse(regexp([$1], [--location]),
275 [-1], [], [$3: ])[]dnl
276 parse error[]dnl
277 ifelse(regexp([$1], [--yyerror-verbose]),
278 [-1], [], [$4])[]dnl
279
280 ])])
281
282
283 # AT_CHECK_CALC([BISON-OPTIONS], [PARSER-EXPECTED-STDERR])
284 # --------------------------------------------------------
285 # Start a testing chunk which compiles `calc' grammar with
286 # BISON-OPTIONS, and performs several tests over the parser.
287 AT_DEFINE([AT_CHECK_CALC],
288 [# We use integers to avoid dependencies upon the precision of doubles.
289 AT_SETUP([Calculator $1])
290
291 AT_DATA_CALC_Y([$1])
292
293 # Specify the output files to avoid problems on different file systems.
294 AT_CHECK([bison calc.y -o calc.c patsubst([$1], [--yyerror-verbose])],
295 [0], [], [])
296 AT_CHECK([$CC $CFLAGS calc.c -o calc], 0, [], [])
297
298 # Test the priorities.
299 _AT_CHECK_CALC([$1],
300 [1 + 2 * 3 = 7
301 1 + 2 * -3 = -5
302
303 -1^2 = -1
304 (-1)^2 = 1
305
306 ---1 = -1
307
308 1 - 2 - 3 = -4
309 1 - (2 - 3) = 2
310
311 2^2^3 = 256
312 (2^2)^3 = 64], [$2])
313
314 # Some parse errors.
315 _AT_CHECK_CALC_ERROR([$1], [+1],
316 [1.0:1.1],
317 [, unexpected `'+''])
318 _AT_CHECK_CALC_ERROR([$1], [1//2],
319 [1.2:1.3],
320 [, unexpected `'/'', expecting `NUM' or `'-'' or `'(''])
321 _AT_CHECK_CALC_ERROR([$1], [error],
322 [1.0:1.1],
323 [, unexpected `$undefined.'])
324 _AT_CHECK_CALC_ERROR([$1], [1 = 2 = 3],
325 [1.6:1.7],
326 [, unexpected `'=''])
327 _AT_CHECK_CALC_ERROR([$1],
328 [
329 +1],
330 [2.0:2.1],
331 [, unexpected `'+''])
332
333 AT_CLEANUP(calc calc.c calc.h calc.output)
334 ])# AT_CHECK_CALC
335
336
337
338
339 # ------------------ #
340 # Test the parsers. #
341 # ------------------ #
342
343 AT_CHECK_CALC()
344
345 AT_CHECK_CALC([--defines])
346 AT_CHECK_CALC([--locations])
347 AT_CHECK_CALC([--name-prefix=calc])
348 AT_CHECK_CALC([--verbose])
349 AT_CHECK_CALC([--yacc])
350 AT_CHECK_CALC([--yyerror-verbose])
351
352 AT_CHECK_CALC([--locations --yyerror-verbose])
353
354 AT_CHECK_CALC([--defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])
355
356 AT_CHECK_CALC([--debug])
357 AT_CHECK_CALC([--debug --defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])