Line data Source code
1 : /*
2 : * (c) Thomas Pornin 1999 - 2002
3 : *
4 : * Redistribution and use in source and binary forms, with or without
5 : * modification, are permitted provided that the following conditions
6 : * are met:
7 : * 1. Redistributions of source code must retain the above copyright
8 : * notice, this list of conditions and the following disclaimer.
9 : * 2. Redistributions in binary form must reproduce the above copyright
10 : * notice, this list of conditions and the following disclaimer in the
11 : * documentation and/or other materials provided with the distribution.
12 : * 4. The name of the authors may not be used to endorse or promote
13 : * products derived from this software without specific prior written
14 : * permission.
15 : *
16 : * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
20 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22 : * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 : * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 : * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 : * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : *
28 : */
29 :
30 : #include "tune.h"
31 : #include <stdio.h>
32 : #include <string.h>
33 : #include <stddef.h>
34 : #include <limits.h>
35 : #include <time.h>
36 : #include "ucppi.h"
37 : #include "mem.h"
38 : #include "nhash.h"
39 :
40 : /*
41 : * Assertion support. Each assertion is indexed by its predicate, and
42 : * the list of 'questions' which yield a true answer.
43 : */
44 :
45 : static HTT assertions;
46 : static int assertions_init_done = 0;
47 :
48 0 : static struct assert *new_assertion(void)
49 : {
50 0 : struct assert *a = getmem(sizeof(struct assert));
51 :
52 0 : a->nbval = 0;
53 0 : return a;
54 : }
55 :
56 0 : static void del_token_fifo(struct token_fifo *tf)
57 : {
58 : size_t i;
59 :
60 0 : for (i = 0; i < tf->nt; i ++)
61 0 : if (S_TOKEN(tf->t[i].type)) freemem(tf->t[i].name);
62 0 : if (tf->nt) freemem(tf->t);
63 0 : }
64 :
65 0 : static void del_assertion(void *va)
66 : {
67 0 : struct assert *a = va;
68 : size_t i;
69 :
70 0 : for (i = 0; i < a->nbval; i ++) del_token_fifo(a->val + i);
71 0 : if (a->nbval) freemem(a->val);
72 0 : freemem(a);
73 0 : }
74 :
75 : /*
76 : * print the contents of a token list
77 : */
78 0 : static void print_token_fifo(struct token_fifo *tf)
79 : {
80 : size_t i;
81 :
82 0 : for (i = 0; i < tf->nt; i ++)
83 0 : if (ttMWS(tf->t[i].type)) fputc(' ', emit_output);
84 0 : else fputs(token_name(tf->t + i), emit_output);
85 0 : }
86 :
87 : /*
88 : * print all assertions related to a given name
89 : */
90 0 : static void print_assert(void *va)
91 : {
92 0 : struct assert *a = va;
93 : size_t i;
94 :
95 0 : for (i = 0; i < a->nbval; i ++) {
96 0 : fprintf(emit_output, "#assert %s(", HASH_ITEM_NAME(a));
97 0 : print_token_fifo(a->val + i);
98 0 : fprintf(emit_output, ")\n");
99 : }
100 0 : }
101 :
102 : /*
103 : * compare two token_fifo, return 0 if they are identical, 1 otherwise.
104 : * All whitespace tokens are considered identical, but sequences of
105 : * whitespace are not shrinked.
106 : */
107 0 : int cmp_token_list(struct token_fifo *f1, struct token_fifo *f2)
108 : {
109 : size_t i;
110 :
111 0 : if (f1->nt != f2->nt) return 1;
112 0 : for (i = 0; i < f1->nt; i ++) {
113 0 : if (ttMWS(f1->t[i].type) && ttMWS(f2->t[i].type)) continue;
114 0 : if (f1->t[i].type != f2->t[i].type) return 1;
115 0 : if (f1->t[i].type == MACROARG
116 0 : && f1->t[i].line != f2->t[i].line) return 1;
117 0 : if (S_TOKEN(f1->t[i].type)
118 0 : && strcmp(f1->t[i].name, f2->t[i].name)) return 1;
119 : }
120 0 : return 0;
121 : }
122 :
123 : /*
124 : * for #assert
125 : * Assertions are not part of the ISO-C89 standard, but they are sometimes
126 : * encountered, for instance in Solaris standard include files.
127 : */
128 0 : int handle_assert(struct lexer_state *ls)
129 : {
130 0 : int ina = 0, ltww;
131 : struct token t;
132 0 : struct token_fifo *atl = 0;
133 : struct assert *a;
134 : char *aname;
135 0 : int ret = -1;
136 0 : long l = ls->line;
137 : int nnp;
138 : size_t i;
139 :
140 0 : while (!next_token(ls)) {
141 0 : if (ls->ctok->type == NEWLINE) break;
142 0 : if (ttMWS(ls->ctok->type)) continue;
143 0 : if (ls->ctok->type == NAME) {
144 0 : if (!(a = HTT_get(&assertions, ls->ctok->name))) {
145 0 : a = new_assertion();
146 0 : aname = sdup(ls->ctok->name);
147 0 : ina = 1;
148 : }
149 0 : goto handle_assert_next;
150 : }
151 0 : error(l, "illegal assertion name for #assert");
152 0 : goto handle_assert_warp_ign;
153 : }
154 0 : goto handle_assert_trunc;
155 :
156 : handle_assert_next:
157 0 : while (!next_token(ls)) {
158 0 : if (ls->ctok->type == NEWLINE) break;
159 0 : if (ttMWS(ls->ctok->type)) continue;
160 0 : if (ls->ctok->type != LPAR) {
161 0 : error(l, "syntax error in #assert");
162 0 : goto handle_assert_warp_ign;
163 : }
164 0 : goto handle_assert_next2;
165 : }
166 0 : goto handle_assert_trunc;
167 :
168 : handle_assert_next2:
169 0 : atl = getmem(sizeof(struct token_fifo));
170 0 : atl->art = atl->nt = 0;
171 0 : for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
172 0 : if (ls->ctok->type == NEWLINE) break;
173 0 : if (ltww && ttMWS(ls->ctok->type)) continue;
174 0 : ltww = ttMWS(ls->ctok->type);
175 0 : if (ls->ctok->type == LPAR) nnp ++;
176 0 : else if (ls->ctok->type == RPAR) {
177 0 : if (!(-- nnp)) goto handle_assert_next3;
178 : }
179 0 : t.type = ls->ctok->type;
180 0 : if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
181 0 : aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG);
182 : }
183 0 : goto handle_assert_trunc;
184 :
185 : handle_assert_next3:
186 0 : while (!next_token(ls) && ls->ctok->type != NEWLINE) {
187 0 : if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
188 0 : warning(l, "trailing garbage in #assert");
189 : }
190 : }
191 0 : if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0)
192 0 : freemem(atl->t);
193 0 : if (atl->nt == 0) {
194 0 : error(l, "void assertion in #assert");
195 0 : goto handle_assert_error;
196 : }
197 0 : for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++);
198 0 : if (i != a->nbval) {
199 : /* we already have it */
200 0 : ret = 0;
201 0 : goto handle_assert_error;
202 : }
203 :
204 : /* This is a new assertion. Let's keep it. */
205 0 : aol(a->val, a->nbval, *atl, TOKEN_LIST_MEMG);
206 0 : if (ina) {
207 0 : HTT_put(&assertions, a, aname);
208 0 : freemem(aname);
209 : }
210 0 : if (emit_assertions) {
211 0 : fprintf(emit_output, "#assert %s(", HASH_ITEM_NAME(a));
212 0 : print_token_fifo(atl);
213 0 : fputs(")\n", emit_output);
214 : }
215 0 : freemem(atl);
216 0 : return 0;
217 :
218 : handle_assert_trunc:
219 0 : error(l, "unfinished #assert");
220 : handle_assert_error:
221 0 : if (atl) {
222 0 : del_token_fifo(atl);
223 0 : freemem(atl);
224 : }
225 0 : if (ina) {
226 0 : freemem(aname);
227 0 : freemem(a);
228 : }
229 0 : return ret;
230 : handle_assert_warp_ign:
231 0 : while (!next_token(ls) && ls->ctok->type != NEWLINE);
232 0 : if (ina) {
233 0 : freemem(aname);
234 0 : freemem(a);
235 : }
236 0 : return ret;
237 : }
238 :
239 : /*
240 : * for #unassert
241 : */
242 0 : int handle_unassert(struct lexer_state *ls)
243 : {
244 : int ltww;
245 : struct token t;
246 : struct token_fifo atl;
247 : struct assert *a;
248 0 : int ret = -1;
249 0 : long l = ls->line;
250 : int nnp;
251 : size_t i;
252 :
253 0 : atl.art = atl.nt = 0;
254 0 : while (!next_token(ls)) {
255 0 : if (ls->ctok->type == NEWLINE) break;
256 0 : if (ttMWS(ls->ctok->type)) continue;
257 0 : if (ls->ctok->type == NAME) {
258 0 : if (!(a = HTT_get(&assertions, ls->ctok->name))) {
259 0 : ret = 0;
260 0 : goto handle_unassert_warp;
261 : }
262 0 : goto handle_unassert_next;
263 : }
264 0 : error(l, "illegal assertion name for #unassert");
265 0 : goto handle_unassert_warp;
266 : }
267 0 : goto handle_unassert_trunc;
268 :
269 : handle_unassert_next:
270 0 : while (!next_token(ls)) {
271 0 : if (ls->ctok->type == NEWLINE) break;
272 0 : if (ttMWS(ls->ctok->type)) continue;
273 0 : if (ls->ctok->type != LPAR) {
274 0 : error(l, "syntax error in #unassert");
275 0 : goto handle_unassert_warp;
276 : }
277 0 : goto handle_unassert_next2;
278 : }
279 0 : if (emit_assertions)
280 0 : fprintf(emit_output, "#unassert %s\n", HASH_ITEM_NAME(a));
281 0 : HTT_del(&assertions, HASH_ITEM_NAME(a));
282 0 : return 0;
283 :
284 : handle_unassert_next2:
285 0 : for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
286 0 : if (ls->ctok->type == NEWLINE) break;
287 0 : if (ltww && ttMWS(ls->ctok->type)) continue;
288 0 : ltww = ttMWS(ls->ctok->type);
289 0 : if (ls->ctok->type == LPAR) nnp ++;
290 0 : else if (ls->ctok->type == RPAR) {
291 0 : if (!(-- nnp)) goto handle_unassert_next3;
292 : }
293 0 : t.type = ls->ctok->type;
294 0 : if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
295 0 : aol(atl.t, atl.nt, t, TOKEN_LIST_MEMG);
296 : }
297 0 : goto handle_unassert_trunc;
298 :
299 : handle_unassert_next3:
300 0 : while (!next_token(ls) && ls->ctok->type != NEWLINE) {
301 0 : if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
302 0 : warning(l, "trailing garbage in #unassert");
303 : }
304 : }
305 0 : if (atl.nt && ttMWS(atl.t[atl.nt - 1].type) && (-- atl.nt) == 0)
306 0 : freemem(atl.t);
307 0 : if (atl.nt == 0) {
308 0 : error(l, "void assertion in #unassert");
309 0 : return ret;
310 : }
311 0 : for (i = 0; i < a->nbval && cmp_token_list(&atl, a->val + i); i ++);
312 0 : if (i != a->nbval) {
313 : /* we have it, undefine it */
314 0 : del_token_fifo(a->val + i);
315 0 : if (i < (a->nbval - 1))
316 0 : mmvwo(a->val + i, a->val + i + 1, (a->nbval - i - 1)
317 : * sizeof(struct token_fifo));
318 0 : if ((-- a->nbval) == 0) freemem(a->val);
319 0 : if (emit_assertions) {
320 0 : fprintf(emit_output, "#unassert %s(",
321 0 : HASH_ITEM_NAME(a));
322 0 : print_token_fifo(&atl);
323 0 : fputs(")\n", emit_output);
324 : }
325 : }
326 0 : ret = 0;
327 0 : goto handle_unassert_finish;
328 :
329 : handle_unassert_trunc:
330 0 : error(l, "unfinished #unassert");
331 : handle_unassert_finish:
332 0 : if (atl.nt) del_token_fifo(&atl);
333 0 : return ret;
334 : handle_unassert_warp:
335 0 : while (!next_token(ls) && ls->ctok->type != NEWLINE);
336 0 : return ret;
337 : }
338 :
339 : /*
340 : * Add the given assertion (as string).
341 : */
342 0 : int make_assertion(char *aval)
343 : {
344 : struct lexer_state lls;
345 0 : size_t n = strlen(aval) + 1;
346 0 : char *c = sdup(aval);
347 : int ret;
348 :
349 0 : *(c + n - 1) = '\n';
350 0 : init_buf_lexer_state(&lls, 0);
351 0 : lls.flags = DEFAULT_LEXER_FLAGS;
352 0 : lls.input = 0;
353 0 : lls.input_string = (unsigned char *)c;
354 0 : lls.pbuf = 0;
355 0 : lls.ebuf = n;
356 0 : lls.line = -1;
357 0 : ret = handle_assert(&lls);
358 0 : freemem(c);
359 0 : free_lexer_state(&lls);
360 0 : return ret;
361 : }
362 :
363 : /*
364 : * Remove the given assertion (as string).
365 : */
366 0 : int destroy_assertion(char *aval)
367 : {
368 : struct lexer_state lls;
369 0 : size_t n = strlen(aval) + 1;
370 0 : char *c = sdup(aval);
371 : int ret;
372 :
373 0 : *(c + n - 1) = '\n';
374 0 : init_buf_lexer_state(&lls, 0);
375 0 : lls.flags = DEFAULT_LEXER_FLAGS;
376 0 : lls.input = 0;
377 0 : lls.input_string = (unsigned char *)c;
378 0 : lls.pbuf = 0;
379 0 : lls.ebuf = n;
380 0 : lls.line = -1;
381 0 : ret = handle_unassert(&lls);
382 0 : freemem(c);
383 0 : free_lexer_state(&lls);
384 0 : return ret;
385 : }
386 :
387 : /*
388 : * erase the assertion table
389 : */
390 0 : void wipe_assertions(void)
391 : {
392 0 : if (assertions_init_done) HTT_kill(&assertions);
393 0 : assertions_init_done = 0;
394 0 : }
395 :
396 : /*
397 : * initialize the assertion table
398 : */
399 0 : void init_assertions(void)
400 : {
401 0 : wipe_assertions();
402 0 : HTT_init(&assertions, del_assertion);
403 0 : assertions_init_done = 1;
404 0 : }
405 :
406 : /*
407 : * retrieve an assertion from the hash table
408 : */
409 0 : struct assert *get_assertion(char *name)
410 : {
411 0 : return HTT_get(&assertions, name);
412 : }
413 :
414 : /*
415 : * print already defined assertions
416 : */
417 0 : void print_assertions(void)
418 : {
419 0 : HTT_scan(&assertions, print_assert);
420 0 : }
|