]> git.saurik.com Git - bison.git/blame - tests/calc.at
* src/system.h: Provide default declarations for stpcpy, strndup,
[bison.git] / tests / calc.at
CommitLineData
bfb07874
AD
1# -*- Autoconf -*-
2
3cat <<EOF
4
5Simple Calculator.
6
7EOF
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.
26AT_DEFINE([_AT_DATA_CALC_Y],
27[ifelse([$1$2$3],
28 $[1]$[2]$[3], [],
29 [errprint([$0: Invalid arguments: $@
30])m4exit(1)])dnl
31AT_DATA([calc.y],
32[[/* Infix notation calculator--calc */
33
34%{
2ce10144 35#include <config.h>
bfb07874 36#include <stdio.h>
2ce10144
AD
37
38#if STDC_HEADERS
39# include <stdlib.h>
40# include <string.h>
41#else
42char *strcat(char *dest, const char *src);
43#endif
bfb07874
AD
44#include <ctype.h>
45]$4[
46
47static int power (int base, int exponent);
48static void yyerror (const char *s);
49static int yylex (void);
2ce10144
AD
50static int yygetc (void);
51static void yyungetc (int c);
52
bfb07874
AD
53extern 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%%
67input:
68 /* empty string */
69| input line
70;
71
72line:
73 '\n'
74| exp '\n'
75;
76
77exp:
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. */
95FILE *yyin;
96
97static void
98yyerror (const char *s)
99{
19c50364 100#if YYLSP_NEEDED
bfb07874
AD
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
108static int
2ce10144 109yygetc (void)
bfb07874
AD
110{
111 int res = getc (yyin);
19c50364 112#if YYLSP_NEEDED
bfb07874
AD
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
125static void
126yyungetc (int c)
127{
19c50364 128#if YYLSP_NEEDED
bfb07874
AD
129 /* Wrong when C == `\n'. */
130 yylloc.last_column--;
131#endif
132 ungetc (c, yyin);
133}
134
135static int
136read_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
167static int
168yylex (void)
169{
170 int c;
171
19c50364 172#if YYLSP_NEEDED
bfb07874
AD
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 {
19c50364 180#if YYLSP_NEEDED
bfb07874
AD
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
202static int
203power (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
213int
214main (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
19c50364 230#if YYLSP_NEEDED
bfb07874
AD
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'.
244AT_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.
258AT_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.
271AT_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
276parse error[]dnl
277ifelse(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.
287AT_DEFINE([AT_CHECK_CALC],
288[# We use integers to avoid dependencies upon the precision of doubles.
289AT_SETUP([Calculator $1])
290
291AT_DATA_CALC_Y([$1])
292
293# Specify the output files to avoid problems on different file systems.
294AT_CHECK([bison calc.y -o calc.c patsubst([$1], [--yyerror-verbose])],
295 [0], [], [])
8303fc42 296AT_CHECK([$CC $CFLAGS $CPPFLAGS calc.c -o calc], 0, [], [])
bfb07874
AD
297
298# Test the priorities.
299_AT_CHECK_CALC([$1],
300[1 + 2 * 3 = 7
3011 + 2 * -3 = -5
302
303-1^2 = -1
304(-1)^2 = 1
305
306---1 = -1
307
3081 - 2 - 3 = -4
3091 - (2 - 3) = 2
310
3112^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
333AT_CLEANUP(calc calc.c calc.h calc.output)
334])# AT_CHECK_CALC
335
336
337
338
339# ------------------ #
340# Test the parsers. #
341# ------------------ #
342
343AT_CHECK_CALC()
bfb07874
AD
344
345AT_CHECK_CALC([--defines])
346AT_CHECK_CALC([--locations])
347AT_CHECK_CALC([--name-prefix=calc])
348AT_CHECK_CALC([--verbose])
349AT_CHECK_CALC([--yacc])
350AT_CHECK_CALC([--yyerror-verbose])
351
352AT_CHECK_CALC([--locations --yyerror-verbose])
353
354AT_CHECK_CALC([--defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])
355
356AT_CHECK_CALC([--debug])
357AT_CHECK_CALC([--debug --defines --locations --name-prefix=calc --verbose --yacc --yyerror-verbose])