xref: /netbsd-src/external/bsd/pcc/dist/pcc/cc/cpp/cpc.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
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