1 /* Id: cpc.c,v 1.7 2016/01/10 16:17:45 ragge Exp */
2 /* $NetBSD: cpc.c,v 1.1.1.1 2016/02/09 20:28:42 plunky Exp $ */
3
4 /*
5 * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * Small recursive parser for #if statements.
31 */
32
33 #include "cpp.h"
34
35 static int ctok;
36
37 typedef struct nd ND;
38 struct nd yynode;
39
40 void qloop(void (*fun)(ND *), ND *n1, int a0, int a1, int a2, int a3);
41 void shft(void);
42 int yyparse(void);
43 void expr(ND *n1);
44 void eqcol(ND *n1);
45 void eoror(ND *n1);
46 void eandand(ND *n1);
47 void exor(ND *n1);
48 void eand(ND *n1);
49 void eqne(ND *n1);
50 void eget(ND *n1);
51 void elrs(ND *n1);
52 void eplmin(ND *n1);
53 void emdv(ND *n1);
54 void eterm(ND *n1);
55 void eval(int op, ND *n1, ND *n2);
56
57
58 void
shft(void)59 shft(void)
60 {
61 ctok = yylex();
62 }
63
64 int
yyparse(void)65 yyparse(void)
66 {
67 ND n1;
68
69 shft();
70 expr(&n1);
71 if (n1.op == 0)
72 error("division by zero");
73 if (ctok != WARN)
74 error("junk after expression");
75 return (int)n1.nd_val;
76 }
77
78 /*
79 * evaluate a complete preprocessor #if expression.
80 */
81 void
expr(ND * n1)82 expr(ND *n1)
83 {
84 for (;;) {
85 eqcol(n1);
86 if (ctok != ',')
87 return;
88 shft();
89 }
90 }
91
92 /*
93 * evaluate ?: conditionals.
94 */
95 void
eqcol(ND * n1)96 eqcol(ND *n1)
97 {
98 ND n2, n3;
99
100 eoror(n1);
101 if (ctok != '?')
102 return;
103
104 shft();
105 expr(&n2);
106 if (ctok != ':')
107 error("no : found");
108 shft();
109 eqcol(&n3);
110 if (n1->nd_val)
111 n1->nd_val = n2.nd_val, n1->op = n2.op;
112 else
113 n1->nd_val = n3.nd_val, n1->op = n3.op;
114 }
115
116 void
eoror(ND * n1)117 eoror(ND *n1)
118 {
119 qloop(eandand, n1, OROR, 0, 0, 0);
120 }
121
122 void
eandand(ND * n1)123 eandand(ND *n1)
124 {
125 qloop(exor, n1, ANDAND, 0, 0, 0);
126 }
127
128 void
exor(ND * n1)129 exor(ND *n1)
130 {
131 qloop(eand, n1, '|', '^', 0, 0);
132 }
133
134 void
eand(ND * n1)135 eand(ND *n1)
136 {
137 qloop(eqne, n1, '&', 0, 0, 0);
138 }
139
140 void
eqne(ND * n1)141 eqne(ND *n1)
142 {
143 qloop(eget, n1, EQ, NE, 0, 0);
144 }
145
146 void
eget(ND * n1)147 eget(ND *n1)
148 {
149 qloop(elrs, n1, '<', '>', LE, GE);
150 }
151
152 void
elrs(ND * n1)153 elrs(ND *n1)
154 {
155 qloop(eplmin, n1, LS, RS, 0, 0);
156 }
157
158 void
eplmin(ND * n1)159 eplmin(ND *n1)
160 {
161 qloop(emdv, n1, '+', '-', 0, 0);
162 }
163
164 void
emdv(ND * n1)165 emdv(ND *n1)
166 {
167 qloop(eterm, n1, '*', '/', '%', 0);
168 }
169
170 /*
171 * Loop to evaluate all operators on the same precedence level.
172 */
173 void
qloop(void (* fun)(ND *),ND * n1,int a0,int a1,int a2,int a3)174 qloop(void (*fun)(ND *), ND *n1, int a0, int a1, int a2, int a3)
175 {
176 ND n2;
177 int op;
178
179 fun(n1);
180 while (ctok == a0 || ctok == a1 || ctok == a2 || ctok == a3) {
181 op = ctok;
182 shft();
183 fun(&n2);
184 eval(op, n1, &n2);
185 }
186 }
187
188 static void
gnum(int o,ND * n1)189 gnum(int o, ND *n1)
190 {
191 n1->op = yynode.op;
192 n1->nd_val = yynode.nd_val;
193 shft();
194 }
195
196 /*
197 * Highest precedence operators + numeric terminals.
198 */
199 void
eterm(ND * n1)200 eterm(ND *n1)
201 {
202 int o = ctok;
203
204 switch (o) {
205 case '~':
206 case '!':
207 case '+':
208 case '-':
209 shft();
210 eterm(n1);
211 eval(o, n1, 0);
212 break;
213
214 case NUMBER:
215 case UNUMBER:
216 gnum(o, n1);
217 break;
218
219 case '(':
220 shft();
221 expr(n1);
222 if (ctok == ')') {
223 shft();
224 break;
225 }
226 /* FALLTHROUGH */
227 default:
228 error("bad terminal (%d)", o);
229 break;
230 }
231 }
232
233 /*
234 * keep all numeric evaluation here.
235 * evaluated value returned in n1.
236 */
237 void
eval(int op,ND * n1,ND * n2)238 eval(int op, ND *n1, ND *n2)
239 {
240
241 if ((op == '/' || op == '%') && n2->nd_val == 0)
242 n1->op = 0;
243
244 if (n1->op == 0)
245 return; /* div by zero involved */
246
247 /* unary ops */
248 if (n2 == 0) {
249 switch (op) {
250 case '+': break;
251 case '-': n1->nd_val = -n1->nd_val; break;
252 case '~': n1->nd_val = ~n1->nd_val; break;
253 case '!': n1->nd_val = !n1->nd_val; n1->op = NUMBER; break;
254 }
255 return;
256 }
257
258 if (op == OROR && n1->nd_val) {
259 n1->nd_val = 1, n1->op = NUMBER;
260 return;
261 }
262 if (op == ANDAND && n1->nd_val == 0) {
263 n1->op = NUMBER;
264 return;
265 }
266
267 if (n2->op == 0) {
268 n1->op = 0;
269 return;
270 }
271
272 if (n2->op == UNUMBER)
273 n1->op = UNUMBER;
274
275 switch (op) {
276 case OROR:
277 if (n2->nd_val)
278 n1->nd_val = 1;
279 n1->op = NUMBER;
280 break;
281 case ANDAND:
282 n1->nd_val = n2->nd_val != 0;
283 n1->op = NUMBER;
284 break;
285 case '+': n1->nd_val += n2->nd_val; break;
286 case '-': n1->nd_val -= n2->nd_val; break;
287 case '|': n1->nd_val |= n2->nd_val; break;
288 case '^': n1->nd_val ^= n2->nd_val; break;
289 case '&': n1->nd_val &= n2->nd_val; break;
290 case LS: n1->nd_val <<= n2->nd_val; break;
291 case EQ: n1->nd_val = n1->nd_val == n2->nd_val; n1->op = NUMBER; break;
292 case NE: n1->nd_val = n1->nd_val != n2->nd_val; n1->op = NUMBER; break;
293 }
294
295 if (n1->op == NUMBER) {
296 switch (op) {
297 case '*': n1->nd_val *= n2->nd_val; break;
298 case '/': n1->nd_val /= n2->nd_val; break;
299 case '%': n1->nd_val %= n2->nd_val; break;
300 case '<': n1->nd_val = n1->nd_val < n2->nd_val; break;
301 case '>': n1->nd_val = n1->nd_val > n2->nd_val; break;
302 case LE: n1->nd_val = n1->nd_val <= n2->nd_val; break;
303 case GE: n1->nd_val = n1->nd_val >= n2->nd_val; break;
304 case RS: n1->nd_val >>= n2->nd_val; break;
305 }
306 return;
307 } else /* op == UNUMBER */ {
308 switch (op) {
309 case '*': n1->nd_uval *= n2->nd_uval; break;
310 case '/': n1->nd_uval /= n2->nd_uval; break;
311 case '%': n1->nd_uval %= n2->nd_uval; break;
312 case '<': n1->nd_uval = n1->nd_uval < n2->nd_uval; break;
313 case '>': n1->nd_uval = n1->nd_uval > n2->nd_uval; break;
314 case LE: n1->nd_uval = n1->nd_uval <= n2->nd_uval; break;
315 case GE: n1->nd_uval = n1->nd_uval >= n2->nd_uval; break;
316 case RS: n1->nd_uval >>= n2->nd_uval; break;
317 }
318 return;
319 }
320 error("unexpected arithmetic");
321 }
322