]>
Commit | Line | Data |
---|---|---|
0d533154 AD |
1 | # -*- Autoconf -*- |
2 | ||
3 | cat <<EOF | |
4 | ||
5 | Simple Calculator. | |
6 | ||
7 | EOF | |
8 | ||
db5b3a89 | 9 | |
0d533154 AD |
10 | ## ---------------------------------------------------- ## |
11 | ## Compile the grammar described in the documentation. ## | |
12 | ## ---------------------------------------------------- ## | |
13 | ||
0d533154 | 14 | |
db5b3a89 AD |
15 | # ------------------------- # |
16 | # Helping Autotest macros. # | |
17 | # ------------------------- # | |
18 | ||
19 | ||
20 | # _AT_DATA_CALC_Y($1, $2, $3) | |
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 | [AT_DATA([calc.y], | |
0d533154 AD |
28 | [[/* Infix notation calculator--calc */ |
29 | ||
30 | %{ | |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <ctype.h> | |
34 | #define YYSTYPE int | |
35 | ||
36 | static int power (int base, int exponent); | |
37 | static int read_signed_integer (FILE *stream); | |
ceed8467 | 38 | static void yyerror (const char *s); |
0d533154 AD |
39 | extern void perror (const char *s); |
40 | %} | |
41 | ||
42 | /* BISON Declarations */ | |
43 | %token NUM | |
44 | %left '-' '+' | |
45 | %left '*' '/' | |
46 | %left NEG /* negation--unary minus */ | |
47 | %right '^' /* exponentiation */ | |
48 | ||
49 | /* Grammar follows */ | |
50 | %% | |
51 | input: /* empty string */ | |
52 | | input line | |
53 | ; | |
54 | ||
55 | line: '\n' | |
56 | | exp '\n' { printf ("%d", $1); } | |
57 | ; | |
58 | ||
59 | exp: NUM { $$ = $1; } | |
60 | | exp '+' exp { $$ = $1 + $3; } | |
61 | | exp '-' exp { $$ = $1 - $3; } | |
62 | | exp '*' exp { $$ = $1 * $3; } | |
63 | | exp '/' exp { $$ = $1 / $3; } | |
64 | | '-' exp %prec NEG { $$ = -$2; } | |
65 | | exp '^' exp { $$ = power ($1, $3); } | |
66 | | '(' exp ')' { $$ = $2; } | |
67 | ; | |
68 | %% | |
ceed8467 AD |
69 | /* The input. */ |
70 | FILE *yyin; | |
05a1d24b | 71 | |
ceed8467 | 72 | static void |
0d533154 AD |
73 | yyerror (const char *s) |
74 | { | |
75 | fprintf (stderr, "%s\n", s); | |
76 | } | |
77 | ||
78 | static int | |
79 | read_signed_integer (FILE *stream) | |
80 | { | |
81 | int c = getc (stream); | |
82 | int sign = 1; | |
83 | int n = 0; | |
84 | ||
85 | if (c == '-') | |
86 | { | |
87 | c = getc (stream); | |
88 | sign = -1; | |
89 | } | |
90 | ||
91 | while (isdigit (c)) | |
92 | { | |
93 | n = 10 * n + (c - '0'); | |
94 | c = getc (stream); | |
95 | } | |
96 | ||
97 | ungetc (c, stream); | |
98 | ||
99 | return sign * n; | |
100 | } | |
101 | ||
102 | /*---------------------------------------------------------------. | |
103 | | Lexical analyzer returns an integer on the stack and the token | | |
104 | | NUM, or the ASCII character read if not a number. Skips all | | |
105 | | blanks and tabs, returns 0 for EOF. | | |
106 | `---------------------------------------------------------------*/ | |
107 | ||
108 | int | |
109 | yylex () | |
110 | { | |
111 | int c; | |
112 | ||
113 | /* Skip white space. */ | |
05a1d24b | 114 | while ((c = getc (yyin)) == ' ' || c == '\t') |
0d533154 AD |
115 | ; |
116 | /* process numbers */ | |
117 | if (c == '.' || isdigit (c)) | |
118 | { | |
05a1d24b AD |
119 | ungetc (c, yyin); |
120 | yylval = read_signed_integer (yyin); | |
0d533154 AD |
121 | return NUM; |
122 | } | |
123 | /* Return end-of-file. */ | |
124 | if (c == EOF) | |
125 | return 0; | |
126 | /* Return single chars. */ | |
127 | return c; | |
128 | } | |
129 | ||
130 | static int | |
131 | power (int base, int exponent) | |
132 | { | |
133 | int res = 1; | |
134 | if (exponent < 0) | |
135 | exit (1); | |
136 | for (/* Niente */; exponent; --exponent) | |
137 | res *= base; | |
138 | return res; | |
139 | } | |
ceed8467 AD |
140 | |
141 | int | |
142 | main (int argn, const char **argv) | |
143 | { | |
144 | if (argn == 2) | |
145 | yyin = fopen (argv[1], "r"); | |
146 | else | |
147 | yyin = stdin; | |
148 | ||
149 | if (!stdin) | |
150 | { | |
151 | perror (argv[1]); | |
152 | exit (1); | |
153 | } | |
db5b3a89 AD |
154 | |
155 | #if YYDEBUG | |
156 | yydebug = 1; | |
157 | #endif | |
ceed8467 AD |
158 | yyparse (); |
159 | return 0; | |
160 | } | |
0d533154 | 161 | ]]) |
db5b3a89 | 162 | ])# _AT_DATA_CALC_Y |
0d533154 | 163 | |
0d533154 | 164 | |
db5b3a89 AD |
165 | # AT_DATA_CALC_Y |
166 | # -------------- | |
167 | # Produce `calc.y'. | |
168 | AT_DEFINE([AT_DATA_CALC_Y], | |
169 | [_AT_DATA_CALC_Y($[1], $[2], $[3])]) | |
170 | ||
171 | ||
172 | # _AT_CHECK_CALC(INPUT, OUTPUT, [STDERR]) | |
173 | # --------------------------------------- | |
174 | # Run `calc' on INPUT, and expect OUTPUT and STDERR. | |
175 | AT_DEFINE([_AT_CHECK_CALC], | |
176 | [AT_CHECK([echo "$1" | calc], 0, [$2], [$3])]) | |
177 | ||
178 | ||
179 | # AT_CHECK_CALC(TITLE, [BISON-OPTIONS], [PARSER-EXPECTED-STDERR]) | |
180 | # --------------------------------------------------------------- | |
181 | # Start a testing chunk named TITLE which compiles `calc' grammar with | |
182 | # BISON-OPTIONS, and performs several tests over the parser. | |
0d533154 | 183 | AT_DEFINE([AT_CHECK_CALC], |
db5b3a89 AD |
184 | [# We use integers to avoid dependencies upon the precision of doubles. |
185 | AT_SETUP([$1]) | |
186 | ||
187 | AT_DATA_CALC_Y | |
188 | ||
189 | # Specify the output files to avoid problems on different file systems. | |
190 | AT_CHECK([bison calc.y -o calc.c $2], 0, [], []) | |
191 | AT_CHECK([$CC $CFLAGS calc.c -o calc], 0, [], []) | |
0d533154 AD |
192 | |
193 | # Test the priorities. | |
db5b3a89 AD |
194 | _AT_CHECK_CALC([1 + 2 * 3], [7], [$3]) |
195 | _AT_CHECK_CALC([1 + 2 * -3], [-5], [$3]) | |
0d533154 | 196 | |
db5b3a89 AD |
197 | _AT_CHECK_CALC([-1^2], [-1], [$3]) |
198 | _AT_CHECK_CALC([(-1)^2], [1], [$3]) | |
0d533154 | 199 | |
db5b3a89 | 200 | _AT_CHECK_CALC([---1], [-1], [$3]) |
0d533154 | 201 | |
db5b3a89 AD |
202 | _AT_CHECK_CALC([1 - 2 - 3], [-4], [$3]) |
203 | _AT_CHECK_CALC([1 - (2 - 3)], [2], [$3]) | |
0d533154 | 204 | |
db5b3a89 AD |
205 | _AT_CHECK_CALC([2^2^3], [256], [$3]) |
206 | _AT_CHECK_CALC([(2^2)^3], [64], [$3]) | |
0d533154 AD |
207 | |
208 | AT_CLEANUP(calc calc.c) | |
db5b3a89 AD |
209 | ])# AT_CHECK_CALC |
210 | ||
211 | ||
212 | # -------------- # | |
213 | # Actual tests. # | |
214 | # -------------- # | |
215 | ||
216 | ||
217 | AT_CHECK_CALC([Simple calculator]) | |
218 | ||
219 | AT_CHECK_CALC([Simple Yacc compatible calculator], | |
220 | [--yacc]) | |
221 | ||
222 | AT_CHECK_CALC([Simple calculator whose tokens are numbered from 3], | |
223 | [--raw]) | |
224 | ||
225 | AT_CHECK_CALC([Simple debugging calculator], | |
226 | [--debug], ignore) | |
227 | ||
228 | AT_CHECK_CALC([Simple Yacc compatible debugging calculator], | |
229 | [--debug --yacc], ignore) |