]> git.saurik.com Git - bison.git/blob - tests/calc.m4
9b57a85d994d4285e78ad8972dd14973f38d32fd
[bison.git] / tests / calc.m4
1 # -*- Autoconf -*-
2
3 cat <<EOF
4
5 Simple Calculator.
6
7 EOF
8
9 ## ---------------------------------------------------- ##
10 ## Compile the grammar described in the documentation. ##
11 ## ---------------------------------------------------- ##
12
13 # We use integers to avoid dependencies upon the precision of doubles.
14 AT_SETUP(Compiling a grammar)
15
16 AT_DATA([calc.y],
17 [[/* Infix notation calculator--calc */
18
19 %{
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #define YYSTYPE int
24
25 static int power (int base, int exponent);
26 static int read_signed_integer (FILE *stream);
27 extern void perror (const char *s);
28 %}
29
30 /* BISON Declarations */
31 %token NUM
32 %left '-' '+'
33 %left '*' '/'
34 %left NEG /* negation--unary minus */
35 %right '^' /* exponentiation */
36
37 /* Grammar follows */
38 %%
39 input: /* empty string */
40 | input line
41 ;
42
43 line: '\n'
44 | exp '\n' { printf ("%d", $1); }
45 ;
46
47 exp: NUM { $$ = $1; }
48 | exp '+' exp { $$ = $1 + $3; }
49 | exp '-' exp { $$ = $1 - $3; }
50 | exp '*' exp { $$ = $1 * $3; }
51 | exp '/' exp { $$ = $1 / $3; }
52 | '-' exp %prec NEG { $$ = -$2; }
53 | exp '^' exp { $$ = power ($1, $3); }
54 | '(' exp ')' { $$ = $2; }
55 ;
56 %%
57 int
58 main (int argn, const char **argv)
59 {
60 if (argn == 2)
61 stdin = fopen (argv[1], "r");
62 if (!stdin)
63 {
64 perror (argv[1]);
65 exit (1);
66 }
67 yyparse ();
68 return 0;
69 }
70
71 int
72 yyerror (const char *s)
73 {
74 fprintf (stderr, "%s\n", s);
75 }
76
77 static int
78 read_signed_integer (FILE *stream)
79 {
80 int c = getc (stream);
81 int sign = 1;
82 int n = 0;
83
84 if (c == '-')
85 {
86 c = getc (stream);
87 sign = -1;
88 }
89
90 while (isdigit (c))
91 {
92 n = 10 * n + (c - '0');
93 c = getc (stream);
94 }
95
96 ungetc (c, stream);
97
98 return sign * n;
99 }
100
101 /*---------------------------------------------------------------.
102 | Lexical analyzer returns an integer on the stack and the token |
103 | NUM, or the ASCII character read if not a number. Skips all |
104 | blanks and tabs, returns 0 for EOF. |
105 `---------------------------------------------------------------*/
106
107 int
108 yylex ()
109 {
110 int c;
111
112 /* Skip white space. */
113 while ((c = getchar ()) == ' ' || c == '\t')
114 ;
115 /* process numbers */
116 if (c == '.' || isdigit (c))
117 {
118 ungetc (c, stdin);
119 yylval = read_signed_integer (stdin);
120 return NUM;
121 }
122 /* Return end-of-file. */
123 if (c == EOF)
124 return 0;
125 /* Return single chars. */
126 return c;
127 }
128
129 static int
130 power (int base, int exponent)
131 {
132 int res = 1;
133 if (exponent < 0)
134 exit (1);
135 for (/* Niente */; exponent; --exponent)
136 res *= base;
137 return res;
138 }
139 ]])
140
141 # Specify the output files to avoid problems on different file systems.
142 AT_CHECK([bison calc.y -o calc.c], 0, [], [])
143 AT_CHECK([$CC $CFLAGS calc.c -o calc], 0, [], [])
144
145 # AT_CHECK_CALC(INPUT, OUTPUT)
146 # ----------------------------
147 # Run `calc' on INPUT, and expect OUTPUT.
148 AT_DEFINE([AT_CHECK_CALC],
149 [AT_CHECK([echo "$1" | calc], 0, [$2], [])])
150
151 # Test the priorities.
152 AT_CHECK_CALC([1 + 2 * 3], [7])
153 AT_CHECK_CALC([1 + 2 * -3], [-5])
154
155 AT_CHECK_CALC([-1^2], [-1])
156 AT_CHECK_CALC([(-1)^2], [1])
157
158 AT_CHECK_CALC([---1], [-1])
159
160 AT_CHECK_CALC([1 - 2 - 3], [-4])
161 AT_CHECK_CALC([1 - (2 - 3)], [2])
162
163 AT_CHECK_CALC([2^2^3], [256])
164 AT_CHECK_CALC([(2^2)^3], [64])
165
166 AT_CLEANUP(calc calc.c)