]>
Commit | Line | Data |
---|---|---|
616915dd | 1 | /* |
11db3170 | 2 | ** Splint - annotation-assisted static program checker |
77d37419 | 3 | ** Copyright (C) 1994-2002 University of Virginia, |
616915dd | 4 | ** Massachusetts Institute of Technology |
5 | ** | |
6 | ** This program is free software; you can redistribute it and/or modify it | |
7 | ** under the terms of the GNU General Public License as published by the | |
8 | ** Free Software Foundation; either version 2 of the License, or (at your | |
9 | ** option) any later version. | |
10 | ** | |
11 | ** This program is distributed in the hope that it will be useful, but | |
12 | ** WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | ** General Public License for more details. | |
15 | ** | |
16 | ** The GNU General Public License is available from http://www.gnu.org/ or | |
17 | ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
18 | ** MA 02111-1307, USA. | |
19 | ** | |
155af98d | 20 | ** For information on splint: info@splint.org |
21 | ** To report a bug: splint-bug@splint.org | |
11db3170 | 22 | ** For more information: http://www.splint.org |
616915dd | 23 | */ |
24 | /* | |
25 | ** usymtab_interface.c | |
26 | ** | |
27 | ** Grammar interface to symtab. | |
28 | ** | |
11db3170 | 29 | ** The Splint parser will build symbol tables for abstract types and |
616915dd | 30 | ** function declarations. |
31 | ** | |
32 | */ | |
33 | ||
1b8ae690 | 34 | # include "splintMacros.nf" |
616915dd | 35 | # include "llbasic.h" |
36 | # include "gram.h" | |
37 | # include "lclscan.h" | |
38 | # include "lclsyntable.h" | |
39 | # include "lslparse.h" | |
40 | # include "usymtab_interface.h" | |
41 | # include "structNames.h" | |
42 | ||
43 | static void | |
44 | declareFcnAux (fcnNode p_f, /*@only@*/ qtype p_qt, ctype p_ct, typeId p_tn, | |
45 | bool p_priv, bool p_spec); | |
46 | ||
47 | static uentryList paramNodeList_toUentryList (paramNodeList p_p); | |
48 | static /*@observer@*/ cstring getVarName (/*@null@*/ typeExpr p_x); | |
49 | static qtype convertLclTypeSpecNode (/*@null@*/ lclTypeSpecNode p_n); | |
50 | static ctype convertTypeExpr (ctype p_c, /*@null@*/ typeExpr p_x); | |
51 | static ctype convertCTypeExpr (ctype p_c, /*@null@*/ typeExpr p_x); | |
52 | static /*@exposed@*/ sRef fixTermNode (termNode p_n, fcnNode p_f, uentryList p_cl); | |
53 | static sRefSet fixModifies (fcnNode p_f, uentryList p_cl); | |
54 | ||
55 | static uentryList | |
56 | convertuentryList (stDeclNodeList x) | |
57 | { | |
58 | uentryList fl = uentryList_new (); | |
59 | ||
60 | ||
61 | stDeclNodeList_elements (x, i) | |
62 | { | |
63 | declaratorNodeList d = i->declarators; | |
64 | qtype q = convertLclTypeSpecNode (i->lcltypespec); | |
65 | ||
66 | declaratorNodeList_elements (d, j) | |
67 | { | |
68 | idDecl id; | |
69 | ||
70 | qtype_setType (q, convertTypeExpr (qtype_getType (q), j->type)); | |
71 | id = idDecl_create (cstring_copy (getVarName (j->type)), qtype_copy (q)); | |
72 | fl = uentryList_add (fl, uentry_makeIdVariable (id)); | |
73 | idDecl_free (id); | |
74 | } end_declaratorNodeList_elements; | |
75 | ||
76 | qtype_free (q); | |
77 | } end_stDeclNodeList_elements; | |
78 | ||
79 | ||
80 | return (fl); | |
81 | } | |
82 | ||
83 | static uentryList | |
84 | convert_uentryList (paramNodeList x) | |
85 | { | |
86 | uentryList p = uentryList_undefined; | |
87 | bool first_one = TRUE; | |
88 | ||
89 | ||
90 | paramNodeList_elements (x, i) | |
91 | { | |
92 | if (i != (paramNode) 0) | |
93 | { | |
94 | if (paramNode_isElipsis (i)) | |
95 | { | |
96 | first_one = FALSE; | |
97 | p = uentryList_add (p, uentry_makeElipsisMarker ()); | |
98 | } | |
99 | else | |
100 | { | |
101 | qtype q = convertLclTypeSpecNode (i->type); | |
102 | typeExpr t = i->paramdecl; | |
103 | ||
104 | qtype_setType (q, convertTypeExpr (qtype_getType (q), t)); | |
105 | ||
106 | /* note: has to be like this to hack around void ???? still */ | |
107 | ||
108 | if (first_one) | |
109 | { | |
110 | if (ctype_isVoid (qtype_getType (q))) | |
111 | { | |
112 | llassert (uentryList_isUndefined (p)); | |
113 | qtype_free (q); | |
114 | return (p); | |
115 | } | |
116 | ||
117 | first_one = FALSE; | |
118 | } | |
119 | ||
120 | /* | |
121 | ** don't do qualifiers here, will get errors later | |
122 | */ | |
123 | ||
124 | p = uentryList_add (p, uentry_makeUnnamedVariable (qtype_getType (q))); | |
125 | qtype_free (q); | |
126 | } | |
127 | } | |
128 | else | |
129 | { | |
130 | llbug (cstring_makeLiteral ("convertuentryList: null paramNode")); | |
131 | } | |
132 | } end_paramNodeList_elements; | |
133 | ||
134 | if (first_one) | |
135 | { | |
136 | llassert (uentryList_isUndefined (p)); | |
137 | ||
138 | p = uentryList_makeMissingParams (); | |
139 | } | |
140 | ||
141 | return p; | |
142 | } | |
143 | ||
144 | /* | |
145 | ** convertTypeExpr | |
146 | ** | |
147 | ** modify c with pointer, array, function | |
148 | ** | |
149 | ** (based on printTypeExpr2 from abstract.c) | |
150 | ** | |
151 | */ | |
152 | ||
153 | static ctype | |
154 | convertTypeExpr (ctype c, typeExpr x) | |
155 | { | |
156 | if (x == (typeExpr) 0) | |
157 | { | |
158 | return c; | |
159 | } | |
160 | ||
161 | switch (x->kind) | |
162 | { | |
163 | case TEXPR_BASE: | |
164 | return (c); | |
165 | case TEXPR_PTR: | |
166 | return (convertTypeExpr (ctype_makePointer (c), x->content.pointer)); | |
167 | case TEXPR_ARRAY: | |
168 | return (convertTypeExpr (ctype_makeArray (c), x->content.array.elementtype)); | |
169 | case TEXPR_FCN: | |
170 | { | |
171 | ctype rv = convertTypeExpr (c, x->content.function.returntype); | |
172 | uentryList p = paramNodeList_toUentryList (x->content.function.args); | |
173 | ||
174 | if (x->content.function.returntype != NULL | |
175 | && x->content.function.returntype->wrapped == 1 | |
176 | && ctype_isPointer (rv)) | |
177 | { | |
178 | rv = ctype_baseArrayPtr (rv); | |
179 | } | |
180 | ||
181 | return (ctype_makeParamsFunction (rv, p)); | |
182 | } | |
183 | default: | |
184 | { | |
185 | llfatalbug (message ("convertTypeExpr: unknown typeExprKind: %d", | |
186 | (int) x->kind)); | |
187 | } | |
188 | } | |
189 | ||
190 | BADEXIT; | |
191 | } | |
192 | ||
193 | static | |
194 | ctype convertCTypeExpr (ctype c, typeExpr x) | |
195 | { | |
196 | if (x == (typeExpr) 0) | |
197 | { | |
198 | return c; | |
199 | } | |
200 | ||
201 | switch (x->kind) | |
202 | { | |
203 | case TEXPR_BASE: return (c); | |
204 | case TEXPR_PTR: return (convertCTypeExpr (ctype_makePointer (c), | |
205 | x->content.pointer)); | |
206 | case TEXPR_ARRAY: return (convertCTypeExpr (ctype_makeArray (c), | |
207 | x->content.array.elementtype)); | |
208 | case TEXPR_FCN: | |
209 | { | |
210 | ctype rv = convertCTypeExpr (c, x->content.function.returntype); | |
211 | uentryList p = convert_uentryList (x->content.function.args); | |
212 | ||
213 | return (ctype_makeParamsFunction (rv, p)); | |
214 | } | |
215 | default: | |
216 | { | |
217 | llfatalbug (message ("convertCTypeExpr: unknown typeExprKind: %d", (int) x->kind)); | |
218 | } | |
219 | } | |
220 | BADEXIT; | |
221 | } | |
222 | ||
223 | /* | |
224 | ** convertLclTypeSpecNode | |
225 | ** | |
226 | ** LclTypeSpecNode --> ctype | |
227 | ** this is the base type only! | |
228 | */ | |
229 | ||
230 | /* | |
231 | ** convertLeaves | |
232 | ** | |
233 | ** for now, assume only last leaf is relevant. | |
234 | ** this should be a safe assumption in general??? | |
235 | */ | |
236 | ||
237 | static ctype | |
238 | convertLeaves (ltokenList f) | |
239 | { | |
240 | ctype c = ctype_unknown; | |
241 | ||
242 | ltokenList_reset (f); | |
243 | ||
244 | ltokenList_elements (f, current) | |
245 | { | |
246 | switch (ltoken_getCode (current)) | |
247 | { | |
248 | case LLT_TYPEDEF_NAME: | |
249 | { | |
250 | cstring tn = ltoken_getRawString (current); | |
251 | ||
252 | if (usymtab_existsTypeEither (tn)) | |
253 | { | |
254 | c = ctype_combine (uentry_getAbstractType | |
255 | (usymtab_lookupEither (tn)), c); | |
256 | } | |
257 | else if (cstring_equalLit (tn, "bool")) | |
258 | { | |
259 | /* | |
260 | ** Bogus...keep consistent with old lcl builtin. | |
261 | */ | |
262 | c = ctype_bool; | |
263 | } | |
264 | else | |
265 | { | |
266 | fileloc loc = fileloc_fromTok (current); | |
267 | ||
268 | voptgenerror (FLG_UNRECOG, | |
269 | message ("Unrecognized type: %s", tn), loc); | |
270 | fileloc_free (loc); | |
271 | ||
272 | usymtab_supEntry | |
273 | (uentry_makeDatatype | |
274 | (tn, ctype_unknown, MAYBE, NO, fileloc_getBuiltin ())); | |
275 | ||
276 | } | |
277 | /*@switchbreak@*/ break; | |
278 | } | |
279 | case LLT_CHAR: | |
280 | c = ctype_combine (ctype_char, c); | |
281 | /*@switchbreak@*/ break; | |
282 | ||
283 | case LLT_DOUBLE: | |
284 | c = ctype_combine (ctype_double, c); | |
285 | /*@switchbreak@*/ break; | |
286 | case LLT_FLOAT: | |
287 | c = ctype_combine (ctype_float, c); | |
288 | /*@switchbreak@*/ break; | |
289 | case LLT_CONST: | |
290 | case LLT_VOLATILE: | |
291 | /*@switchbreak@*/ break; | |
292 | case LLT_INT: | |
293 | c = ctype_combine (ctype_int, c); | |
294 | /*@switchbreak@*/ break; | |
295 | case LLT_LONG: | |
296 | c = ctype_combine (c, ctype_lint); | |
297 | /*@switchbreak@*/ break; | |
298 | case LLT_SHORT: | |
299 | c = ctype_combine (c, ctype_sint); | |
300 | /*@switchbreak@*/ break; | |
301 | case LLT_SIGNED: | |
302 | c = ctype_combine (c, ctype_int); | |
303 | /*@switchbreak@*/ break; | |
304 | case LLT_UNSIGNED: | |
305 | c = ctype_combine (c, ctype_uint); | |
306 | /*@switchbreak@*/ break; | |
307 | case LLT_UNKNOWN: | |
308 | c = ctype_combine (ctype_unknown, c); | |
309 | /*@switchbreak@*/ break; | |
310 | case LLT_VOID: | |
311 | c = ctype_combine (ctype_void, c); | |
312 | /*@switchbreak@*/ break; | |
313 | case LLT_ENUM: | |
314 | llcontbug (cstring_makeLiteral ("convertLeaves: enum")); | |
315 | c = ctype_int; | |
316 | /*@switchbreak@*/ break; | |
317 | default: | |
318 | llfatalbug (message ("convertLeaves: bad token: %q", | |
319 | ltoken_unparseCodeName (current))); | |
320 | } | |
321 | } end_ltokenList_elements; | |
322 | ||
323 | return c; | |
324 | } | |
325 | ||
326 | static enumNameList | |
327 | convertEnumList (ltokenList enums) | |
328 | { | |
329 | enumNameList el = enumNameList_new (); | |
330 | ||
331 | if (ltokenList_isDefined (enums)) | |
332 | { | |
333 | ltokenList_elements (enums, i) | |
334 | { | |
335 | enumNameList_addh | |
336 | (el, enumName_create (cstring_copy (ltoken_unparse (i)))); | |
337 | } end_ltokenList_elements; | |
338 | } | |
339 | ||
340 | return el; | |
341 | } | |
342 | ||
343 | static /*@only@*/ qtype | |
344 | convertLclTypeSpecNode (/*@null@*/ lclTypeSpecNode n) | |
345 | { | |
346 | ||
347 | if (n != (lclTypeSpecNode) 0) | |
348 | { | |
349 | qtype result; | |
350 | ||
351 | switch (n->kind) | |
352 | { | |
353 | case LTS_CONJ: | |
354 | { | |
355 | qtype c1 = convertLclTypeSpecNode (n->content.conj->a); | |
356 | qtype c2 = convertLclTypeSpecNode (n->content.conj->b); | |
357 | ||
358 | /* | |
359 | ** Is it explicit? | |
360 | */ | |
361 | ||
362 | if (fileloc_isLib (g_currentloc) | |
363 | || fileloc_isStandardLibrary (g_currentloc)) | |
364 | { | |
365 | result = qtype_mergeImplicitAlt (c1, c2); | |
366 | } | |
367 | else | |
368 | { | |
369 | result = qtype_mergeAlt (c1, c2); | |
370 | } | |
371 | ||
372 | break; | |
373 | } | |
374 | case LTS_TYPE: | |
375 | llassert (n->content.type != NULL); | |
376 | result = qtype_create (convertLeaves (n->content.type->ctypes)); | |
377 | break; | |
378 | case LTS_STRUCTUNION: | |
379 | { | |
380 | strOrUnionNode sn; | |
381 | cstring cn = cstring_undefined; | |
382 | ||
383 | sn = n->content.structorunion; | |
384 | ||
385 | llassert (sn != (strOrUnionNode) 0); | |
386 | ||
387 | if (!ltoken_isUndefined (sn->opttagid)) | |
388 | { | |
389 | cn = cstring_copy (ltoken_getRawString (sn->opttagid)); | |
390 | } | |
391 | else | |
392 | { | |
393 | cn = fakeTag (); | |
394 | } | |
395 | ||
396 | switch (sn->kind) | |
397 | { | |
398 | case SU_STRUCT: | |
399 | if (usymtab_existsStructTag (cn)) | |
400 | { | |
401 | ||
402 | result = qtype_create (uentry_getAbstractType | |
403 | (usymtab_lookupStructTag (cn))); | |
404 | cstring_free (cn); | |
405 | } | |
406 | else | |
407 | { | |
408 | uentryList fl = convertuentryList (sn->structdecls); | |
409 | ctype ct; | |
410 | ||
411 | ct = ctype_createStruct (cstring_copy (cn), fl); | |
412 | ||
413 | /* | |
414 | ** If it was a forward declaration, this could add it to | |
415 | ** the table. Need to check if it exists again... | |
416 | */ | |
417 | ||
418 | if (usymtab_existsStructTag (cn)) | |
419 | { | |
420 | result = qtype_create (uentry_getAbstractType | |
421 | (usymtab_lookupStructTag (cn))); | |
422 | } | |
423 | else | |
424 | { | |
425 | fileloc loc = fileloc_fromTok (n->content.structorunion->tok); | |
426 | uentry ue = uentry_makeStructTag (cn, ct, loc); | |
427 | ||
428 | result = qtype_create (usymtab_supTypeEntry (ue)); | |
429 | } | |
430 | ||
431 | cstring_free (cn); | |
432 | } | |
433 | /*@switchbreak@*/ break; | |
434 | case SU_UNION: | |
435 | if (usymtab_existsUnionTag (cn)) | |
436 | { | |
437 | ||
438 | result = qtype_create (uentry_getAbstractType | |
439 | (usymtab_lookupUnionTag (cn))); | |
440 | cstring_free (cn); | |
441 | } | |
442 | else | |
443 | { | |
444 | uentryList fl; | |
445 | ctype ct; | |
446 | ||
447 | fl = convertuentryList (sn->structdecls); | |
448 | ct = ctype_createUnion (cstring_copy (cn), fl); | |
449 | ||
450 | /* | |
451 | ** If it was a forward declaration, this could add it to | |
452 | ** the table. Need to check if it exists again... | |
453 | */ | |
454 | ||
455 | ||
456 | ||
457 | if (usymtab_existsUnionTag (cn)) | |
458 | { | |
459 | ||
460 | result = qtype_create (uentry_getAbstractType | |
461 | (usymtab_lookupUnionTag (cn))); | |
462 | } | |
463 | else | |
464 | { | |
465 | fileloc loc = fileloc_fromTok (n->content.structorunion->tok); | |
466 | uentry ue = uentry_makeUnionTag (cn, ct, loc); | |
467 | ||
468 | result = qtype_create (usymtab_supTypeEntry (ue)); | |
469 | } | |
470 | ||
471 | cstring_free (cn); | |
472 | } | |
473 | /*@switchbreak@*/ break; | |
474 | BADDEFAULT | |
475 | } | |
476 | break; | |
477 | } | |
478 | case LTS_ENUM: | |
479 | { | |
480 | enumSpecNode e = n->content.enumspec; | |
481 | enumNameList el; | |
482 | cstring ename; | |
483 | bool first = TRUE; | |
484 | ctype ta; | |
485 | ctype cet; | |
486 | ||
487 | llassert (e != NULL); | |
488 | el = convertEnumList (e->enums); | |
489 | ||
490 | if (!ltoken_isUndefined (e->opttagid)) /* named enumerator */ | |
491 | { | |
492 | ename = cstring_copy (ltoken_getRawString (e->opttagid)); | |
493 | } | |
494 | else | |
495 | { | |
496 | ename = fakeTag (); | |
497 | } | |
498 | ||
499 | cet = ctype_createEnum (ename, el); | |
500 | ||
501 | if (usymtab_existsEnumTag (ename)) | |
502 | { | |
503 | ta = uentry_getAbstractType (usymtab_lookupEnumTag (ename)); | |
504 | } | |
505 | else | |
506 | { | |
507 | fileloc loc = fileloc_fromTok (e->tok); | |
508 | uentry ue = uentry_makeEnumTag (ename, cet, loc); | |
509 | ||
510 | ta = usymtab_supTypeEntry (ue); | |
511 | } | |
512 | ||
513 | enumNameList_elements (el, en) | |
514 | { | |
515 | uentry ue; | |
516 | fileloc loc; | |
517 | ||
518 | if (first) | |
519 | { | |
520 | ltokenList_reset (e->enums); | |
521 | first = FALSE; | |
522 | } | |
523 | else | |
524 | { | |
525 | ltokenList_advance (e->enums); | |
526 | } | |
527 | ||
528 | loc = fileloc_fromTok (ltokenList_current (e->enums)); | |
529 | ue = uentry_makeSpecEnumConstant (en, cet, loc); | |
530 | ||
531 | /* | |
532 | ** Can't check name here, might not have | |
533 | ** type yet. Will check in .lh file? | |
534 | */ | |
535 | ||
536 | ue = usymtab_supGlobalEntryReturn (ue); | |
537 | ||
538 | if (context_inLCLLib ()) | |
539 | { | |
540 | uentry_setDefined (ue, loc); | |
541 | } | |
542 | } end_enumNameList_elements; | |
543 | ||
544 | result = qtype_create (ta); | |
545 | } | |
546 | break; | |
547 | default: | |
548 | { | |
549 | llfatalbug (message ("convertLclTypeSpecNode: unknown lclTypeSpec kind: %d", | |
550 | (int) n->kind)); | |
551 | } | |
552 | } | |
553 | ||
554 | result = qtype_addQualList (result, n->quals); | |
555 | ||
f9264521 | 556 | if (pointers_isDefined (n->pointers)) |
616915dd | 557 | { |
558 | qtype_adjustPointers (n->pointers, result); | |
559 | } | |
560 | ||
561 | return result; | |
562 | } | |
563 | else | |
564 | { | |
565 | llcontbug (cstring_makeLiteral ("convertLclTypeSpecNode: null")); | |
566 | return qtype_unknown (); | |
567 | } | |
568 | BADEXIT; | |
569 | } | |
570 | ||
571 | static /*@only@*/ multiVal | |
572 | literalValue (ctype ct, ltoken lit) | |
573 | { | |
574 | cstring text = cstring_fromChars (lsymbol_toChars (ltoken_getText (lit))); | |
575 | char first; | |
576 | ||
577 | if (cstring_length (text) > 0) | |
578 | { | |
579 | first = cstring_firstChar (text); | |
580 | } | |
581 | else | |
582 | { | |
583 | return multiVal_unknown (); | |
584 | } | |
585 | ||
586 | ||
587 | if /*@-usedef@*/ (first == '\"') /*@=usedef@*/ | |
588 | { | |
abd7f895 | 589 | size_t len = cstring_length (text) - 2; |
616915dd | 590 | char *val = mstring_create (len); |
591 | ||
592 | llassert (cstring_lastChar (text) == '\"'); | |
abd7f895 | 593 | strncpy (val, cstring_toCharsSafe (text) + 1, len); |
616915dd | 594 | return (multiVal_makeString (cstring_fromCharsO (val))); |
595 | } | |
596 | ||
597 | if (ctype_isDirectInt (ct) || ctype_isPointer (ct)) | |
598 | { | |
599 | long val = 0; | |
600 | ||
601 | if (sscanf (cstring_toCharsSafe (text), "%ld", &val) == 1) | |
602 | { | |
603 | return multiVal_makeInt (val); | |
604 | } | |
605 | } | |
606 | ||
607 | return multiVal_unknown (); | |
608 | } | |
609 | ||
610 | ||
611 | /* | |
612 | ** declareConstant | |
613 | ** | |
614 | ** unfortunately, because the abstract types are different, this | |
615 | ** cannot be easily subsumed into declareVar. | |
616 | */ | |
617 | ||
618 | void | |
619 | doDeclareConstant (constDeclarationNode c, bool priv) | |
620 | { | |
621 | lclTypeSpecNode t; | |
622 | ctype ctx; | |
623 | qtype qt; | |
624 | ||
625 | if (c == (constDeclarationNode) 0) | |
626 | { | |
627 | return; | |
628 | } | |
629 | ||
630 | t = c->type; | |
631 | qt = convertLclTypeSpecNode (t); | |
632 | ||
633 | ctx = qtype_getType (qt); | |
634 | ||
635 | initDeclNodeList_elements (c->decls, i) | |
636 | { | |
637 | ctype ct = convertTypeExpr (ctx, i->declarator->type); | |
638 | cstring s = getVarName (i->declarator->type); | |
639 | ||
640 | if (ctype_isFunction (ct)) | |
641 | { | |
642 | fcnNode fcn = fcnNode_fromDeclarator (lclTypeSpecNode_copy (t), | |
643 | declaratorNode_copy (i->declarator)); | |
644 | ||
645 | /* FALSE == unspecified function, only a declaration */ | |
646 | ||
647 | doDeclareFcn (fcn, typeId_invalid, priv, FALSE); | |
648 | fcnNode_free (fcn); | |
649 | } | |
650 | else | |
651 | { | |
652 | uentry ue; | |
653 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
654 | ||
655 | if (i->value != (termNode)0 && | |
656 | i->value->kind == TRM_LITERAL) | |
657 | { | |
5e211f69 | 658 | ue = uentry_makeConstantValue (s, ct, loc, priv, literalValue (ct, i->value->literal)); |
616915dd | 659 | } |
660 | else | |
661 | { | |
5e211f69 | 662 | ue = uentry_makeConstantValue (s, ct, loc, priv, multiVal_unknown ()); |
616915dd | 663 | } |
5e211f69 | 664 | |
665 | uentry_reflectQualifiers (ue, qtype_getQuals (qt)); | |
616915dd | 666 | |
667 | if (context_inLCLLib () && !priv) | |
668 | { | |
669 | uentry_setDefined (ue, loc); | |
670 | } | |
671 | ||
672 | usymtab_supGlobalEntry (ue); | |
673 | } | |
674 | } end_initDeclNodeList_elements; | |
675 | ||
676 | qtype_free (qt); | |
677 | } | |
678 | ||
679 | static cstring | |
680 | getVarName (/*@null@*/ typeExpr x) | |
681 | { | |
682 | cstring s = cstring_undefined; | |
683 | ||
684 | if (x != (typeExpr) 0) | |
685 | { | |
686 | switch (x->kind) | |
687 | { | |
688 | case TEXPR_BASE: | |
689 | s = ltoken_getRawString (x->content.base); | |
690 | break; | |
691 | case TEXPR_PTR: | |
692 | s = getVarName (x->content.pointer); | |
693 | break; | |
694 | case TEXPR_ARRAY: | |
695 | s = getVarName (x->content.array.elementtype); | |
696 | break; | |
697 | case TEXPR_FCN: | |
698 | s = getVarName (x->content.function.returntype); | |
699 | break; | |
700 | default: | |
701 | llfatalbug (message ("getVarName: unknown typeExprKind: %d", (int) x->kind)); | |
702 | } | |
703 | } | |
704 | ||
705 | return s; | |
706 | } | |
707 | ||
708 | void | |
709 | doDeclareVar (varDeclarationNode v, bool priv) | |
710 | { | |
711 | lclTypeSpecNode t; | |
712 | qtype c; | |
713 | ||
714 | if (v == (varDeclarationNode) 0) | |
715 | { | |
716 | return; | |
717 | } | |
718 | ||
719 | t = v->type; | |
720 | c = convertLclTypeSpecNode (t); | |
721 | ||
722 | initDeclNodeList_elements (v->decls, i) | |
723 | { | |
724 | ctype ct = convertTypeExpr (qtype_getType (c), i->declarator->type); | |
725 | cstring s = getVarName (i->declarator->type); | |
726 | ||
727 | qtype_setType (c, ct); | |
728 | ||
729 | if (ctype_isFunction (ct)) | |
730 | { | |
731 | fcnNode fcn; | |
732 | ||
733 | ||
734 | fcn = fcnNode_fromDeclarator (lclTypeSpecNode_copy (t), | |
735 | declaratorNode_copy (i->declarator)); | |
736 | ||
737 | /* FALSE == unspecified function, only a declaration */ | |
738 | declareFcnAux (fcn, qtype_unknown (), ct, | |
739 | typeId_invalid, priv, FALSE); | |
740 | fcnNode_free (fcn); | |
741 | } | |
742 | else | |
743 | { | |
744 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
745 | uentry le = uentry_makeVariable (s, ct, loc, priv); | |
746 | ||
747 | uentry_reflectQualifiers (le, qtype_getQuals (c)); | |
748 | ||
749 | if (uentry_isCheckedUnknown (le)) | |
750 | { | |
751 | if (context_getFlag (FLG_IMPCHECKEDSTRICTSPECGLOBALS)) | |
752 | { | |
753 | uentry_setCheckedStrict (le); | |
754 | } | |
755 | else if (context_getFlag (FLG_IMPCHECKEDSPECGLOBALS)) | |
756 | { | |
757 | uentry_setChecked (le); | |
758 | } | |
759 | else if (context_getFlag (FLG_IMPCHECKMODSPECGLOBALS)) | |
760 | { | |
761 | uentry_setCheckMod (le); | |
762 | } | |
763 | else | |
764 | { | |
765 | ; /* okay */ | |
766 | } | |
767 | } | |
768 | ||
769 | if (context_inLCLLib () && !priv) | |
770 | { | |
771 | uentry_setDefined (le, loc); | |
772 | } | |
773 | ||
774 | if (initDeclNode_isRedeclaration (i)) | |
775 | { | |
776 | usymtab_replaceEntry (le); | |
777 | } | |
778 | else | |
779 | { | |
780 | le = usymtab_supEntrySrefReturn (le); | |
781 | } | |
782 | } | |
783 | } end_initDeclNodeList_elements; | |
784 | ||
785 | qtype_free (c); | |
786 | } | |
787 | ||
788 | static globSet | |
789 | processGlob (/*@returned@*/ globSet globs, varDeclarationNode v) | |
790 | { | |
791 | if (v == (varDeclarationNode) 0) | |
792 | { | |
793 | return globs; | |
794 | } | |
795 | ||
796 | if (v->isSpecial) | |
797 | { | |
798 | globs = globSet_insert (globs, v->sref); | |
799 | } | |
800 | else | |
801 | { | |
802 | lclTypeSpecNode t = v->type; | |
803 | qtype qt = convertLclTypeSpecNode (t); | |
804 | ctype c = qtype_getType (qt); | |
805 | cstring s; | |
806 | ||
807 | initDeclNodeList_elements (v->decls, i) | |
808 | { | |
809 | ctype ct; | |
810 | uentry ue; | |
811 | qualList quals = qtype_getQuals (qt); | |
812 | ||
813 | s = getVarName (i->declarator->type); | |
814 | ue = usymtab_lookupGlobSafe (s); | |
815 | ||
816 | if (uentry_isInvalid (ue)) | |
817 | { | |
818 | ; /* error already reported */ | |
819 | } | |
820 | else | |
821 | { | |
822 | if (uentry_isPriv (ue)) | |
823 | { | |
824 | globs = globSet_insert (globs, sRef_makeSpecState ()); | |
825 | } | |
826 | else | |
827 | { | |
828 | uentry ce = uentry_copy (ue); | |
829 | ctype lt = uentry_getType (ce); | |
830 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
831 | ||
832 | ct = convertTypeExpr (c, i->declarator->type); | |
833 | ||
834 | if (!ctype_match (lt, ct)) | |
835 | { | |
836 | (void) gentypeerror | |
837 | (lt, exprNode_undefined, | |
838 | ct, exprNode_undefined, | |
839 | message ("Global type mismatch %s (%t, %t)", | |
840 | s, lt, ct), | |
841 | loc); | |
842 | } | |
843 | ||
844 | uentry_reflectQualifiers (ce, quals); | |
845 | globs = globSet_insert (globs, | |
846 | sRef_copy (uentry_getSref (ce))); | |
847 | fileloc_free (loc); | |
848 | uentry_free (ce); | |
849 | } | |
850 | } | |
851 | } end_initDeclNodeList_elements; | |
852 | ||
853 | qtype_free (qt); | |
854 | } | |
855 | ||
856 | return globs; | |
857 | } | |
858 | ||
859 | static void | |
860 | declareAbstractType (abstractNode n, bool priv) | |
861 | { | |
862 | cstring tn; | |
863 | fileloc loc; | |
864 | uentry ue; | |
865 | usymId uid; | |
866 | abstBodyNode ab; | |
867 | ||
868 | if (n == (abstractNode) 0) | |
869 | { | |
870 | return; | |
871 | } | |
872 | ||
873 | ||
874 | tn = ltoken_getRawString (n->name); | |
875 | ||
876 | loc = fileloc_fromTok (n->tok); | |
877 | ||
878 | ue = uentry_makeDatatypeAux (tn, ctype_unknown, | |
879 | ynm_fromBool (n->isMutable), YES, loc, priv); | |
880 | ||
881 | if (n->isRefCounted) | |
882 | { | |
883 | uentry_setRefCounted (ue); | |
884 | } | |
885 | ||
886 | if (context_inLCLLib () && !priv) | |
887 | { | |
888 | uentry_setDefined (ue, loc); | |
889 | } | |
890 | ||
891 | uid = usymtab_supAbstractTypeEntry (ue, context_inLCLLib() && !priv); | |
892 | ||
893 | ||
894 | if (!priv && (ab = n->body) != (abstBodyNode) 0) | |
895 | { | |
896 | fcnNodeList ops = ab->fcns; | |
897 | ||
898 | if (!fcnNodeList_isEmpty (ops)) | |
899 | { | |
900 | fcnNodeList_elements (ops, i) | |
901 | { | |
902 | if (i->typespec == (lclTypeSpecNode) 0) | |
903 | { | |
904 | cstring fname = ltoken_getRawString (i->name); | |
905 | ||
906 | if (usymtab_exists (fname)) | |
907 | { | |
908 | uentry e = usymtab_lookup (fname); | |
909 | fileloc floc = fileloc_fromTok (i->declarator->id); | |
910 | ||
911 | if (uentry_isForward (e)) | |
912 | { | |
913 | usymtab_supEntry | |
914 | (uentry_makeTypeListFunction | |
915 | (fname, typeIdSet_insert (uentry_accessType (e), uid), | |
916 | floc)); | |
917 | } | |
918 | else | |
919 | { | |
920 | usymtab_supEntry | |
921 | (uentry_makeSpecFunction | |
922 | (fname, uentry_getType (e), | |
923 | typeIdSet_insert (uentry_accessType (e), uid), | |
924 | globSet_undefined, | |
925 | sRefSet_undefined, | |
926 | floc)); | |
927 | ||
928 | if (context_inLCLLib ()) | |
929 | { | |
930 | llbuglit ("Jolly jeepers Wilma, it ain't dead after all!"); | |
931 | } | |
932 | } | |
933 | } | |
934 | else | |
935 | { | |
936 | usymtab_supEntry | |
937 | (uentry_makeForwardFunction (fname, uid, loc)); | |
938 | } | |
939 | } | |
940 | else | |
941 | { | |
942 | declareFcn (i, uid); | |
943 | } | |
944 | } end_fcnNodeList_elements; | |
945 | } | |
946 | } | |
947 | } | |
948 | ||
949 | static void | |
950 | declareExposedType (exposedNode n, bool priv) | |
951 | { | |
952 | usymId uid; | |
953 | qtype c; | |
954 | cstring s; | |
955 | ||
956 | ||
957 | if (n == (exposedNode) 0) | |
958 | { | |
959 | return; | |
960 | } | |
961 | ||
962 | c = convertLclTypeSpecNode (n->type); | |
963 | ||
964 | declaratorInvNodeList_elements (n->decls, i) | |
965 | { | |
966 | ctype realType = convertTypeExpr (qtype_getType (c), i->declarator->type); | |
967 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
968 | uentry ue; | |
969 | ||
970 | s = getVarName (i->declarator->type); | |
971 | ||
972 | ue = uentry_makeDatatypeAux (s, realType, MAYBE, NO, loc, priv); | |
973 | ||
974 | uentry_reflectQualifiers (ue, qtype_getQuals (c)); | |
975 | ||
976 | if (context_inLCLLib () && !priv) | |
977 | { | |
978 | uentry_setDefined (ue, loc); | |
979 | } | |
980 | ||
981 | uid = usymtab_supExposedTypeEntry (ue, context_inLCLLib () && !priv); | |
982 | } end_declaratorInvNodeList_elements; | |
983 | ||
984 | qtype_free (c); | |
985 | } | |
986 | ||
987 | /* | |
988 | ** ah...remember ye old days... | |
989 | ** | |
990 | ** wow...same thing in THREE symbol tables! talk about space efficiency | |
991 | ** (or as Joe Theory once said, its only a constant factor) | |
992 | */ | |
993 | ||
994 | void | |
995 | doDeclareType (typeNode t, bool priv) | |
996 | { | |
997 | ||
998 | if (t != (typeNode) 0) | |
999 | { | |
1000 | switch (t->kind) | |
1001 | { | |
1002 | case TK_ABSTRACT: | |
1003 | declareAbstractType (t->content.abstract, priv); | |
1004 | break; | |
1005 | ||
1006 | case TK_EXPOSED: | |
1007 | declareExposedType (t->content.exposed, priv); | |
1008 | break; | |
1009 | ||
1010 | case TK_UNION: | |
1011 | default: | |
1012 | { | |
1013 | llfatalbug (message ("declareType ERROR: unknown kind: %q", | |
1014 | cstring_fromCharsO (FormatInt ((int)t->kind)))); | |
1015 | } | |
1016 | } | |
1017 | } | |
1018 | ||
1019 | } | |
1020 | ||
1021 | extern void | |
1022 | declareIter (iterNode iter) | |
1023 | { | |
1024 | fileloc loc = fileloc_fromTok (iter->name); | |
1025 | uentry ue = | |
1026 | uentry_makeIter (ltoken_unparse (iter->name), | |
1027 | ctype_makeFunction | |
1028 | (ctype_void, | |
1029 | paramNodeList_toUentryList (iter->params)), | |
1030 | fileloc_copy (loc)); | |
1031 | ||
1032 | usymtab_supEntry (ue); | |
1033 | usymtab_supEntry | |
1034 | (uentry_makeEndIter (ltoken_unparse (iter->name), loc)); | |
1035 | } | |
1036 | ||
1037 | /* | |
1038 | ** declareFcn | |
1039 | */ | |
1040 | ||
1041 | static void | |
1042 | declareFcnAux (fcnNode f, /*@only@*/ qtype qt, ctype ct, | |
1043 | typeId tn, bool priv, bool spec) | |
1044 | { | |
1045 | globalList globals; | |
1046 | typeIdSet acct; | |
1047 | sRefSet sl = sRefSet_undefined; | |
1048 | globSet globlist = globSet_undefined; | |
1049 | cstring s = getVarName (f->declarator->type); | |
1050 | fileloc loc = fileloc_fromTok (f->declarator->id); | |
1051 | uentryList args; | |
1052 | ||
1053 | /* | |
1054 | ** type conversion generates args | |
1055 | */ | |
1056 | ||
1057 | if (ctype_isFunction (ct)) | |
1058 | { | |
1059 | args = ctype_argsFunction (ct); | |
1060 | } | |
1061 | else | |
1062 | { | |
1063 | llcontbug (message ("Not function: %s", ctype_unparse (ct))); | |
1064 | args = uentryList_undefined; | |
1065 | } | |
1066 | ||
1067 | ||
1068 | fileloc_setColumnUndefined (loc); | |
1069 | ||
1070 | if (spec) | |
1071 | { | |
1072 | globals = f->globals; | |
1073 | ||
28bf4b0b | 1074 | sl = fixModifies (f, args); |
616915dd | 1075 | |
1076 | /* | |
1077 | ** Bind let declarations in modifies list | |
1078 | */ | |
1079 | ||
1080 | varDeclarationNodeList_elements (globals, glob) | |
1081 | { | |
1082 | globlist = processGlob (globlist, glob); | |
1083 | } end_varDeclarationNodeList_elements; | |
1084 | ||
1085 | ||
1086 | if (f->checks != (lclPredicateNode) 0) | |
1087 | /* push stderr on globalList */ | |
1088 | /* modifies *stderr^ */ | |
1089 | { | |
1090 | uentry ue; | |
1091 | ||
1092 | if (!(usymtab_existsVar (cstring_makeLiteralTemp ("stderr")))) | |
1093 | { | |
1094 | ctype tfile; | |
1095 | ||
1096 | llmsglit ("Global stderr implied by checks clause, " | |
1097 | "not declared in initializations."); | |
1098 | ||
1099 | tfile = usymtab_lookupType (cstring_makeLiteralTemp ("FILE")); | |
1100 | ||
1101 | if (ctype_isUndefined (tfile)) | |
1102 | { | |
1103 | llmsglit ("FILE datatype implied by checks clause not defined."); | |
1104 | tfile = ctype_unknown; | |
1105 | } | |
1106 | ||
1107 | usymtab_supGlobalEntry | |
1108 | (uentry_makeVariable (cstring_makeLiteralTemp ("stderr"), | |
1109 | tfile, fileloc_getBuiltin (), FALSE)); | |
1110 | } | |
1111 | ||
1112 | ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stderr")); | |
1113 | ||
28bf4b0b | 1114 | globlist = globSet_insert (globlist, sRef_copy (uentry_getSref (ue))); |
616915dd | 1115 | sl = sRefSet_insert (sl, sRef_buildPointer (uentry_getSref (ue))); |
616915dd | 1116 | } |
1117 | } | |
1118 | ||
1119 | if (usymId_isInvalid (tn)) | |
1120 | { | |
1121 | acct = context_fileAccessTypes (); | |
1122 | } | |
1123 | else | |
1124 | { | |
1125 | acct = typeIdSet_single (tn); | |
1126 | } | |
28bf4b0b | 1127 | |
616915dd | 1128 | if (usymtab_exists (s)) |
1129 | { | |
1130 | uentry l = usymtab_lookup (s); | |
1131 | uentry ue; | |
1132 | ||
1133 | if (uentry_isForward (l) || (fileloc_isLib (uentry_whereSpecified (l)))) | |
1134 | { | |
1135 | typeIdSet accessType; | |
1136 | ||
1137 | if (uentry_isFunction (l)) | |
1138 | { | |
1139 | accessType = typeIdSet_union (uentry_accessType (l), | |
1140 | context_fileAccessTypes ()); | |
1141 | } | |
1142 | else | |
1143 | { | |
1144 | accessType = context_fileAccessTypes (); | |
1145 | } | |
1146 | ||
1147 | if (spec) | |
1148 | { | |
1149 | ue = uentry_makeSpecFunction (s, ct, accessType, globlist, sl, loc); | |
1150 | } | |
1151 | else | |
1152 | { | |
1153 | sRefSet_free (sl); | |
1154 | globSet_free (globlist); | |
1155 | ||
1156 | ue = uentry_makeUnspecFunction (s, ct, accessType, loc); | |
1157 | } | |
1158 | ||
1159 | uentry_reflectQualifiers (ue, qtype_getQuals (qt)); | |
616915dd | 1160 | usymtab_supEntry (ue); |
1161 | } | |
1162 | else | |
1163 | { | |
1164 | /* | |
1165 | ** error reported by symtable already | |
1166 | ** | |
1167 | ** llgenerror (message ("Function redeclared: %s (previous declaration: %s)", s, | |
1168 | ** fileloc_unparse (uentry_whereSpecified (l))), | |
1169 | ** loc); | |
1170 | */ | |
1171 | ||
616915dd | 1172 | fileloc_free (loc); |
1173 | sRefSet_free (sl); | |
1174 | globSet_free (globlist); | |
1175 | } | |
1176 | } | |
1177 | else | |
1178 | { | |
1179 | uentry le; | |
1180 | ||
1181 | if (spec) | |
1182 | { | |
1183 | if (priv) | |
1184 | { | |
1185 | le = uentry_makePrivFunction2 (s, ct, acct, globlist, sl, loc); | |
1186 | } | |
1187 | else | |
1188 | { | |
1189 | le = uentry_makeSpecFunction (s, ct, acct, globlist, sl, loc); | |
1190 | } | |
1191 | } | |
1192 | else | |
1193 | { | |
1194 | le = uentry_makeUnspecFunction (s, ct, acct, loc); | |
1195 | ||
1196 | sRefSet_free (sl); | |
1197 | globSet_free (globlist); | |
1198 | } | |
1199 | ||
1200 | if (context_inLCLLib () && !priv) | |
1201 | { | |
1202 | uentry_setDefined (le, loc); | |
1203 | } | |
1204 | ||
1205 | uentry_reflectQualifiers (le, qtype_getQuals (qt)); | |
1206 | ||
28bf4b0b | 1207 | if (qual_isUnknown (f->special)) { |
1208 | ; | |
1209 | } else if (qual_isPrintfLike (f->special)) { | |
1210 | uentry_setPrintfLike (le); | |
1211 | } else if (qual_isScanfLike (f->special)) { | |
1212 | uentry_setScanfLike (le); | |
1213 | } else if (qual_isMessageLike (f->special)) { | |
1214 | uentry_setMessageLike (le); | |
1215 | } else { | |
1216 | BADBRANCH; | |
1217 | } | |
616915dd | 1218 | |
1219 | usymtab_supEntry (le); | |
1220 | } | |
1221 | ||
1222 | qtype_free (qt); | |
1223 | } | |
1224 | ||
1225 | extern void | |
1226 | doDeclareFcn (fcnNode f, typeId tn, bool priv, bool spec) | |
1227 | { | |
1228 | qtype qt = convertLclTypeSpecNode (f->typespec); | |
1229 | ctype ct = convertTypeExpr (qtype_getType (qt), f->declarator->type); | |
1230 | ||
28bf4b0b | 1231 | declareFcnAux (f, qt, ct, tn, priv, spec); |
616915dd | 1232 | } |
1233 | ||
1234 | /* | |
1235 | ** is s is an argument to f, return its arg no. | |
1236 | ** otherwise, return 0 | |
1237 | */ | |
1238 | ||
1239 | static int | |
1240 | getParamNo (cstring s, fcnNode f) | |
1241 | { | |
1242 | /* gasp, maybe should do run-time checks here */ | |
1243 | paramNodeList params; | |
1244 | typeExpr fd = f->declarator->type; | |
1245 | ||
1246 | /* is this a bug in the LCL grammar? */ | |
1247 | ||
1248 | while (fd != NULL && (fd->kind == TEXPR_PTR || fd->kind == TEXPR_ARRAY)) | |
1249 | { | |
1250 | if (fd->kind == TEXPR_PTR) | |
1251 | { | |
1252 | fd = fd->content.pointer; | |
1253 | } | |
1254 | else | |
1255 | { | |
1256 | /*@-null@*/ fd = fd->content.array.elementtype; /*@=null@*/ | |
1257 | ||
1258 | /* | |
1259 | ** This is a bug in checking, that I should eventually fix. | |
1260 | ** Need some way of deleting the guard from the true branch, | |
1261 | ** but adding it back in the false branch... | |
1262 | */ | |
1263 | } | |
1264 | } | |
1265 | ||
1266 | llassert (fd != NULL); | |
1267 | ||
1268 | if (fd->kind != TEXPR_FCN) | |
1269 | { | |
1270 | llfatalbug (message ("getParamNo: not a function: %q (%d)", | |
1271 | typeExpr_unparse (fd), (int) fd->kind)); | |
1272 | } | |
1273 | ||
1274 | params = fd->content.function.args; | |
1275 | ||
1276 | if (paramNodeList_empty (params)) | |
1277 | { | |
1278 | return -1; | |
1279 | } | |
1280 | else | |
1281 | { | |
1282 | int pno = 0; | |
1283 | ||
1284 | paramNodeList_elements (params, i) | |
1285 | { | |
1286 | if (i->paramdecl != (typeExpr) 0) /* handle (void) */ | |
1287 | { | |
1288 | if (cstring_equal (s, getVarName (i->paramdecl))) | |
1289 | { | |
1290 | return pno; | |
1291 | } | |
1292 | } | |
1293 | pno++; | |
1294 | } end_paramNodeList_elements; | |
1295 | return -1; | |
1296 | } | |
1297 | } | |
1298 | ||
1299 | static /*@null@*/ /*@observer@*/ termNode | |
1300 | getLetDecl (cstring s, fcnNode f) | |
1301 | { | |
1302 | letDeclNodeList x = f->lets; | |
1303 | ||
1304 | letDeclNodeList_elements (x, i) | |
1305 | { | |
1306 | if (cstring_equal (s, ltoken_getRawString (i->varid))) | |
1307 | { | |
1308 | if (i->sortspec != NULL) | |
1309 | { | |
1310 | llbuglit ("getLetDecl: cannot return sort!"); | |
1311 | } | |
1312 | else | |
1313 | { /* is a termNode */ | |
1314 | return i->term; | |
1315 | } | |
1316 | } | |
1317 | } end_letDeclNodeList_elements; | |
1318 | ||
1319 | return (termNode) 0; | |
1320 | } | |
1321 | ||
1322 | /* | |
1323 | ** processTermNode --- based on printTermNode2 | |
1324 | */ | |
1325 | ||
1326 | static /*@exposed@*/ sRef | |
1327 | processTermNode (/*@null@*/ opFormNode op, termNodeList args, | |
1328 | fcnNode f, uentryList cl) | |
1329 | { | |
1330 | if (op != (opFormNode) 0) | |
1331 | { | |
1332 | switch (op->kind) | |
1333 | { | |
1334 | case OPF_IF: | |
1335 | llcontbuglit ("processTermNode: OPF_IF: not handled"); | |
1336 | break; | |
1337 | case OPF_ANYOP: | |
1338 | llcontbuglit ("processTermNode: OPF_ANYOP: not handled"); | |
1339 | break; | |
1340 | case OPF_MANYOP: | |
1341 | { | |
1342 | int size = termNodeList_size (args); | |
1343 | ||
1344 | if (size == 1 | |
1345 | && (cstring_equalLit (ltoken_getRawString (op->content.anyop), "'") || | |
1346 | cstring_equalLit (ltoken_getRawString (op->content.anyop), "^"))) | |
1347 | { | |
1348 | return (fixTermNode (termNodeList_head (args), f, cl)); | |
1349 | } | |
1350 | else | |
1351 | { | |
1352 | ; | |
1353 | } | |
1354 | break; | |
1355 | } | |
1356 | case OPF_ANYOPM: | |
1357 | { | |
1358 | int size = termNodeList_size (args); | |
1359 | ||
1360 | if (size == 1 | |
1361 | && (cstring_equalLit (ltoken_getRawString (op->content.anyop), "*"))) | |
1362 | { | |
1363 | sRef ft; | |
1364 | sRef res; | |
1365 | ||
1366 | ft = fixTermNode (termNodeList_head (args), f, cl); | |
1367 | res = sRef_buildPointer (ft); | |
1368 | return (res); | |
1369 | } | |
1370 | else | |
1371 | { | |
1372 | ; | |
1373 | } | |
1374 | break; | |
1375 | } | |
1376 | case OPF_MANYOPM: | |
1377 | llcontbuglit ("OPF_MANYOPM: not handled\n"); | |
1378 | break; | |
1379 | case OPF_MIDDLE: | |
1380 | llcontbuglit ("OPF_MIDDLE: not handled\n"); | |
1381 | break; | |
1382 | case OPF_MMIDDLE: | |
1383 | llcontbuglit ("OPF_MMIDDLE: not handled\n"); | |
1384 | break; | |
1385 | case OPF_MIDDLEM: | |
1386 | llcontbuglit ("OPF_MIDDLEM: not handled\n"); | |
1387 | break; | |
1388 | case OPF_MMIDDLEM: | |
1389 | llcontbuglit ("OPF_MMIDDLEM: not handled\n"); | |
1390 | break; | |
1391 | case OPF_BMIDDLE: | |
1392 | if (op->content.middle == 1) | |
1393 | llbug (message ("array fetch: [%q]", | |
1394 | termNodeList_unparse (args))); | |
1395 | else | |
1396 | llcontbuglit ("OPF_BMIDDLE: bad\n"); | |
1397 | break; | |
1398 | ||
1399 | case OPF_BMMIDDLE: | |
1400 | if (op->content.middle <= 1) | |
1401 | { | |
1402 | sRef arr = fixTermNode (termNodeList_head (args), f, cl); | |
1403 | sRef ret; | |
1404 | ||
1405 | if (op->content.middle == 1) | |
1406 | { | |
1407 | termNode t = (termNodeList_reset (args), | |
1408 | termNodeList_advance (args), | |
1409 | termNodeList_current (args)); | |
1410 | ||
1411 | if (t->kind == TRM_LITERAL) | |
1412 | { | |
1413 | int i; | |
1414 | ||
1415 | if (sscanf | |
1416 | (cstring_toCharsSafe | |
1417 | (ltoken_getRawString (t->literal)), | |
1418 | "%d", &i) == 1) | |
1419 | { | |
1420 | ret = sRef_buildArrayFetchKnown (arr, i); | |
1421 | } | |
1422 | else | |
1423 | { | |
1424 | ret = sRef_buildArrayFetch (arr); | |
1425 | } | |
1426 | ||
1427 | return (ret); | |
1428 | } | |
1429 | } | |
1430 | ||
1431 | /* unknown index */ | |
1432 | ||
1433 | ret = sRef_buildArrayFetch (arr); | |
1434 | ||
1435 | return (ret); | |
1436 | } | |
1437 | else | |
1438 | { | |
1439 | llcontbug (message ("op->content.middle = %d", | |
1440 | op->content.middle)); | |
1441 | break; | |
1442 | } | |
1443 | ||
1444 | case OPF_BMIDDLEM: | |
1445 | llcontbuglit ("OPF_BMIDDLEM not handled"); | |
1446 | break; | |
1447 | ||
1448 | case OPF_BMMIDDLEM: | |
1449 | llcontbuglit ("OPF_BMMIDDLEM not handled"); | |
1450 | break; | |
1451 | ||
1452 | case OPF_SELECT: | |
1453 | llcontbug (message ("select: .%s", | |
1454 | ltoken_getRawString (op->content.id))); | |
1455 | break; | |
1456 | ||
1457 | case OPF_MAP: | |
1458 | llcontbug (message ("map: .%s", | |
1459 | ltoken_getRawString (op->content.id))); | |
1460 | break; | |
1461 | ||
1462 | case OPF_MSELECT: | |
1463 | { | |
1464 | sRef rec = fixTermNode (termNodeList_head (args), f, cl); | |
1465 | sRef ret; | |
1466 | ctype ct = ctype_realType (sRef_deriveType (rec, cl)); | |
1467 | cstring fieldname = ltoken_getRawString (op->content.id); | |
1468 | ||
1469 | ct = ctype_realType (ct); | |
1470 | ||
1471 | /* | |
1472 | ** does it correspond to a typedef struct field | |
1473 | ** | |
1474 | ** (kind of kludgey, but there is no direct way to | |
1475 | ** tell if it is an lsl operator instead) | |
1476 | */ | |
1477 | ||
1478 | if (ctype_isStructorUnion (ct) && | |
1479 | uentry_isValid | |
1480 | (uentryList_lookupField (ctype_getFields (ct), fieldname))) | |
1481 | { | |
1482 | cstring fname = cstring_copy (fieldname); | |
1483 | ||
1484 | ret = sRef_buildField (rec, fname); | |
1485 | cstring_markOwned (fname); | |
1486 | } | |
1487 | else | |
1488 | { | |
1489 | ret = sRef_undefined; | |
1490 | } | |
1491 | ||
1492 | return ret; | |
1493 | } | |
1494 | case OPF_MMAP: | |
1495 | { | |
1496 | sRef rec = fixTermNode (termNodeList_head (args), f, cl); | |
1497 | sRef ret = sRef_undefined; | |
1498 | ctype ct = ctype_realType (sRef_deriveType (rec, cl)); | |
1499 | cstring fieldname = ltoken_getRawString (op->content.id); | |
1500 | ||
1501 | /* | |
1502 | ** does it correspond to a typedef struct field | |
1503 | */ | |
1504 | ||
1505 | if (ctype_isPointer (ct)) | |
1506 | { | |
1507 | ctype ctb = ctype_realType (ctype_baseArrayPtr (ct)); | |
1508 | ||
1509 | if (ctype_isStructorUnion (ctb) && | |
1510 | uentry_isValid (uentryList_lookupField | |
1511 | (ctype_getFields (ctb), fieldname))) | |
1512 | { | |
1513 | cstring fname = cstring_copy (fieldname); | |
1514 | ||
1515 | ret = sRef_buildArrow (rec, fname); | |
1516 | cstring_markOwned (fname); | |
1517 | } | |
1518 | } | |
1519 | ||
1520 | return ret; | |
1521 | } | |
1522 | } | |
1523 | } | |
1524 | ||
1525 | return sRef_undefined; | |
1526 | } | |
1527 | ||
1528 | /* | |
1529 | ** fixModifies | |
1530 | ** | |
1531 | ** o replace anything in modifies that is bound with let with value | |
1532 | ** o replace spec variables with internal state | |
1533 | ** o replace paramaters with paramno identifiers | |
1534 | ** o replace globals with their usymid's | |
1535 | ** o make everything sRefs | |
1536 | */ | |
1537 | ||
1538 | static /*@exposed@*/ sRef fixTermNode (termNode n, fcnNode f, uentryList cl) | |
1539 | { | |
1540 | if (n != (termNode) 0) | |
1541 | { | |
1542 | switch (n->kind) | |
1543 | { | |
1544 | case TRM_LITERAL: | |
1545 | break; | |
1546 | case TRM_CONST: | |
1547 | case TRM_VAR: | |
1548 | case TRM_ZEROARY: | |
1549 | { | |
1550 | cstring s = ltoken_getRawString (n->literal); | |
1551 | termNode tl = getLetDecl (s, f); | |
1552 | ||
1553 | if (tl != (termNode) 0) | |
1554 | { | |
1555 | return (fixTermNode (tl, f, cl)); | |
1556 | } | |
1557 | else | |
1558 | { | |
1559 | int i = getParamNo (s, f); | |
1560 | ||
1561 | if (i < 0) | |
1562 | { | |
1563 | usymId usym = usymtab_getId (s); | |
1564 | ||
1565 | if (usymId_isInvalid (usym)) | |
1566 | { | |
1567 | if (usymtab_existsEither (s)) | |
1568 | { | |
1569 | return sRef_makeSpecState (); | |
1570 | } | |
1571 | else | |
1572 | { | |
1573 | llcontbuglit ("Invalid symbol in modifies list"); | |
1574 | return sRef_undefined; | |
1575 | } | |
1576 | } | |
1577 | else | |
6970c11b | 1578 | return (sRef_makeGlobal (usym, ctype_unknown, stateInfo_currentLoc ())); |
616915dd | 1579 | } |
1580 | ||
1581 | else | |
1582 | { | |
6970c11b | 1583 | sRef p = sRef_makeParam (i, ctype_unknown, stateInfo_currentLoc ()); |
1584 | return (p); | |
616915dd | 1585 | } |
1586 | } | |
1587 | } | |
1588 | case TRM_APPLICATION: | |
1589 | { | |
1590 | nameNode nn = n->name; | |
1591 | ||
1592 | if (nn != (nameNode) 0) | |
1593 | { | |
1594 | if (nn->isOpId) | |
1595 | { | |
1596 | /* must we handle n->given ? skip for now */ | |
1597 | ||
1598 | llfatalbug | |
1599 | (message ("fixTermNode: expect non-empty nameNode: " | |
1600 | "TRM_APPLICATION: %q", | |
1601 | nameNode_unparse (nn))); | |
1602 | } | |
1603 | else | |
1604 | { | |
1605 | sRef sr; | |
1606 | ||
1607 | sr = processTermNode (nn->content.opform, n->args, f, cl); | |
1608 | return (sr); | |
1609 | } | |
1610 | } | |
1611 | ||
1612 | return sRef_undefined; | |
1613 | } | |
1614 | case TRM_UNCHANGEDALL: | |
1615 | case TRM_UNCHANGEDOTHERS: | |
1616 | case TRM_SIZEOF: | |
1617 | case TRM_QUANTIFIER: | |
1618 | return sRef_undefined; | |
1619 | } | |
1620 | } | |
1621 | ||
1622 | return sRef_undefined; | |
1623 | } | |
1624 | ||
1625 | static | |
1626 | /*@only@*/ sRefSet fixModifies (fcnNode f, uentryList cl) | |
1627 | { | |
1628 | static bool shownWarning = FALSE; | |
1629 | modifyNode m = f->modify; | |
1630 | sRefSet sl = sRefSet_new (); | |
1631 | ||
1632 | if (m != (modifyNode) 0) | |
1633 | { | |
1634 | if (m->hasStoreRefList) | |
1635 | { | |
1636 | storeRefNodeList srefs = m->list; | |
1637 | ||
1638 | storeRefNodeList_elements (srefs, i) | |
1639 | { | |
1640 | if (storeRefNode_isObj (i) || storeRefNode_isType (i)) | |
1641 | { | |
1642 | if (!shownWarning) | |
1643 | { | |
1644 | fileloc loc = fileloc_fromTok (f->name); | |
1645 | ||
1646 | llmsg (message | |
1647 | ("%q: Warning: object and type modifications " | |
11db3170 | 1648 | "not understood by Splint", |
616915dd | 1649 | fileloc_unparse (loc))); |
1650 | fileloc_free (loc); | |
1651 | shownWarning = TRUE; | |
1652 | } | |
1653 | } | |
1654 | else if (storeRefNode_isSpecial (i)) | |
1655 | { | |
1656 | sl = sRefSet_insert (sl, i->content.ref); | |
1657 | } | |
1658 | else if (storeRefNode_isTerm (i)) | |
1659 | { | |
1660 | sRef s = fixTermNode (i->content.term, f, cl); | |
1661 | ||
1662 | if (sRef_isKnown (s)) | |
1663 | { | |
1664 | sl = sRefSet_insert (sl, s); | |
1665 | } | |
1666 | } | |
1667 | else | |
1668 | { | |
1669 | BADEXIT; | |
1670 | } | |
1671 | } end_storeRefNodeList_elements; | |
1672 | ||
1673 | } | |
1674 | } | |
1675 | ||
1676 | return sl; | |
1677 | } | |
1678 | ||
1679 | static /*@only@*/ cstring | |
1680 | paramNode_name (paramNode x) | |
1681 | { | |
1682 | return (typeExpr_name (x->paramdecl)); | |
1683 | } | |
1684 | ||
1685 | static /*@only@*/ uentry | |
1686 | paramNode_toUentry (paramNode p) | |
1687 | { | |
1688 | if (p != (paramNode) 0) | |
1689 | { | |
1690 | if (p->kind == PELIPSIS) | |
1691 | { | |
1692 | return uentry_makeElipsisMarker (); | |
1693 | } | |
1694 | else | |
1695 | { | |
1696 | qtype ct = convertLclTypeSpecNode (p->type); | |
1697 | ctype cr = convertTypeExpr (qtype_getType (ct), p->paramdecl); | |
1698 | cstring pname = (p->paramdecl == (typeExpr)0) ? cstring_undefined | |
1699 | : paramNode_name (p); | |
6970c11b | 1700 | uentry ue = uentry_makeVariableParam (pname, cr, g_currentloc); |
616915dd | 1701 | |
1702 | uentry_reflectQualifiers (ue, qtype_getQuals (ct)); | |
1703 | qtype_free (ct); | |
1704 | return (ue); | |
1705 | } | |
1706 | } | |
1707 | else | |
1708 | { | |
1709 | llcontbuglit ("paramNode_toUentry: NULL"); | |
1710 | return uentry_undefined; | |
1711 | } | |
1712 | BADEXIT; | |
1713 | } | |
1714 | ||
1715 | static uentryList | |
1716 | paramNodeList_toUentryList (paramNodeList p) | |
1717 | { | |
1718 | uentryList cl = uentryList_new (); | |
1719 | ||
1720 | if (paramNodeList_isNull (p)) return (cl); | |
1721 | ||
1722 | paramNodeList_elements (p, current) | |
1723 | { | |
1724 | cl = uentryList_add (cl, paramNode_toUentry (current)); | |
1725 | } end_paramNodeList_elements; | |
1726 | ||
1727 | return cl; | |
1728 | } | |
1729 | ||
1730 |