]>
Commit | Line | Data |
---|---|---|
616915dd | 1 | /* |
11db3170 | 2 | ** Splint - annotation-assisted static program checker |
28bf4b0b | 3 | ** Copyright (C) 1994-2001 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 | ** | |
20 | ** For information on lclint: lclint-request@cs.virginia.edu | |
21 | ** To report a bug: lclint-bug@cs.virginia.edu | |
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 | ||
34 | # include "lclintMacros.nf" | |
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 | ||
556 | if (n->pointers > 0) | |
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 | { | |
589 | int len = cstring_length (text) - 2; | |
590 | char *val = mstring_create (len); | |
591 | ||
592 | llassert (cstring_lastChar (text) == '\"'); | |
593 | strncpy (val, cstring_toCharsSafe (text) + 1, size_fromInt (len)); | |
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 | { | |
658 | ue = uentry_makeConstantAux (s, ct, loc, priv, | |
659 | literalValue (ct, i->value->literal)); | |
660 | } | |
661 | else | |
662 | { | |
663 | ue = uentry_makeConstantAux (s, ct, loc, priv, multiVal_unknown ()); | |
664 | } | |
665 | ||
666 | uentry_reflectQualifiers (ue, qtype_getQuals (qt)); | |
667 | ||
668 | ||
669 | if (context_inLCLLib () && !priv) | |
670 | { | |
671 | uentry_setDefined (ue, loc); | |
672 | } | |
673 | ||
674 | usymtab_supGlobalEntry (ue); | |
675 | } | |
676 | } end_initDeclNodeList_elements; | |
677 | ||
678 | qtype_free (qt); | |
679 | } | |
680 | ||
681 | static cstring | |
682 | getVarName (/*@null@*/ typeExpr x) | |
683 | { | |
684 | cstring s = cstring_undefined; | |
685 | ||
686 | if (x != (typeExpr) 0) | |
687 | { | |
688 | switch (x->kind) | |
689 | { | |
690 | case TEXPR_BASE: | |
691 | s = ltoken_getRawString (x->content.base); | |
692 | break; | |
693 | case TEXPR_PTR: | |
694 | s = getVarName (x->content.pointer); | |
695 | break; | |
696 | case TEXPR_ARRAY: | |
697 | s = getVarName (x->content.array.elementtype); | |
698 | break; | |
699 | case TEXPR_FCN: | |
700 | s = getVarName (x->content.function.returntype); | |
701 | break; | |
702 | default: | |
703 | llfatalbug (message ("getVarName: unknown typeExprKind: %d", (int) x->kind)); | |
704 | } | |
705 | } | |
706 | ||
707 | return s; | |
708 | } | |
709 | ||
710 | void | |
711 | doDeclareVar (varDeclarationNode v, bool priv) | |
712 | { | |
713 | lclTypeSpecNode t; | |
714 | qtype c; | |
715 | ||
716 | if (v == (varDeclarationNode) 0) | |
717 | { | |
718 | return; | |
719 | } | |
720 | ||
721 | t = v->type; | |
722 | c = convertLclTypeSpecNode (t); | |
723 | ||
724 | initDeclNodeList_elements (v->decls, i) | |
725 | { | |
726 | ctype ct = convertTypeExpr (qtype_getType (c), i->declarator->type); | |
727 | cstring s = getVarName (i->declarator->type); | |
728 | ||
729 | qtype_setType (c, ct); | |
730 | ||
731 | if (ctype_isFunction (ct)) | |
732 | { | |
733 | fcnNode fcn; | |
734 | ||
735 | ||
736 | fcn = fcnNode_fromDeclarator (lclTypeSpecNode_copy (t), | |
737 | declaratorNode_copy (i->declarator)); | |
738 | ||
739 | /* FALSE == unspecified function, only a declaration */ | |
740 | declareFcnAux (fcn, qtype_unknown (), ct, | |
741 | typeId_invalid, priv, FALSE); | |
742 | fcnNode_free (fcn); | |
743 | } | |
744 | else | |
745 | { | |
746 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
747 | uentry le = uentry_makeVariable (s, ct, loc, priv); | |
748 | ||
749 | uentry_reflectQualifiers (le, qtype_getQuals (c)); | |
750 | ||
751 | if (uentry_isCheckedUnknown (le)) | |
752 | { | |
753 | if (context_getFlag (FLG_IMPCHECKEDSTRICTSPECGLOBALS)) | |
754 | { | |
755 | uentry_setCheckedStrict (le); | |
756 | } | |
757 | else if (context_getFlag (FLG_IMPCHECKEDSPECGLOBALS)) | |
758 | { | |
759 | uentry_setChecked (le); | |
760 | } | |
761 | else if (context_getFlag (FLG_IMPCHECKMODSPECGLOBALS)) | |
762 | { | |
763 | uentry_setCheckMod (le); | |
764 | } | |
765 | else | |
766 | { | |
767 | ; /* okay */ | |
768 | } | |
769 | } | |
770 | ||
771 | if (context_inLCLLib () && !priv) | |
772 | { | |
773 | uentry_setDefined (le, loc); | |
774 | } | |
775 | ||
776 | if (initDeclNode_isRedeclaration (i)) | |
777 | { | |
778 | usymtab_replaceEntry (le); | |
779 | } | |
780 | else | |
781 | { | |
782 | le = usymtab_supEntrySrefReturn (le); | |
783 | } | |
784 | } | |
785 | } end_initDeclNodeList_elements; | |
786 | ||
787 | qtype_free (c); | |
788 | } | |
789 | ||
790 | static globSet | |
791 | processGlob (/*@returned@*/ globSet globs, varDeclarationNode v) | |
792 | { | |
793 | if (v == (varDeclarationNode) 0) | |
794 | { | |
795 | return globs; | |
796 | } | |
797 | ||
798 | if (v->isSpecial) | |
799 | { | |
800 | globs = globSet_insert (globs, v->sref); | |
801 | } | |
802 | else | |
803 | { | |
804 | lclTypeSpecNode t = v->type; | |
805 | qtype qt = convertLclTypeSpecNode (t); | |
806 | ctype c = qtype_getType (qt); | |
807 | cstring s; | |
808 | ||
809 | initDeclNodeList_elements (v->decls, i) | |
810 | { | |
811 | ctype ct; | |
812 | uentry ue; | |
813 | qualList quals = qtype_getQuals (qt); | |
814 | ||
815 | s = getVarName (i->declarator->type); | |
816 | ue = usymtab_lookupGlobSafe (s); | |
817 | ||
818 | if (uentry_isInvalid (ue)) | |
819 | { | |
820 | ; /* error already reported */ | |
821 | } | |
822 | else | |
823 | { | |
824 | if (uentry_isPriv (ue)) | |
825 | { | |
826 | globs = globSet_insert (globs, sRef_makeSpecState ()); | |
827 | } | |
828 | else | |
829 | { | |
830 | uentry ce = uentry_copy (ue); | |
831 | ctype lt = uentry_getType (ce); | |
832 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
833 | ||
834 | ct = convertTypeExpr (c, i->declarator->type); | |
835 | ||
836 | if (!ctype_match (lt, ct)) | |
837 | { | |
838 | (void) gentypeerror | |
839 | (lt, exprNode_undefined, | |
840 | ct, exprNode_undefined, | |
841 | message ("Global type mismatch %s (%t, %t)", | |
842 | s, lt, ct), | |
843 | loc); | |
844 | } | |
845 | ||
846 | uentry_reflectQualifiers (ce, quals); | |
847 | globs = globSet_insert (globs, | |
848 | sRef_copy (uentry_getSref (ce))); | |
849 | fileloc_free (loc); | |
850 | uentry_free (ce); | |
851 | } | |
852 | } | |
853 | } end_initDeclNodeList_elements; | |
854 | ||
855 | qtype_free (qt); | |
856 | } | |
857 | ||
858 | return globs; | |
859 | } | |
860 | ||
861 | static void | |
862 | declareAbstractType (abstractNode n, bool priv) | |
863 | { | |
864 | cstring tn; | |
865 | fileloc loc; | |
866 | uentry ue; | |
867 | usymId uid; | |
868 | abstBodyNode ab; | |
869 | ||
870 | if (n == (abstractNode) 0) | |
871 | { | |
872 | return; | |
873 | } | |
874 | ||
875 | ||
876 | tn = ltoken_getRawString (n->name); | |
877 | ||
878 | loc = fileloc_fromTok (n->tok); | |
879 | ||
880 | ue = uentry_makeDatatypeAux (tn, ctype_unknown, | |
881 | ynm_fromBool (n->isMutable), YES, loc, priv); | |
882 | ||
883 | if (n->isRefCounted) | |
884 | { | |
885 | uentry_setRefCounted (ue); | |
886 | } | |
887 | ||
888 | if (context_inLCLLib () && !priv) | |
889 | { | |
890 | uentry_setDefined (ue, loc); | |
891 | } | |
892 | ||
893 | uid = usymtab_supAbstractTypeEntry (ue, context_inLCLLib() && !priv); | |
894 | ||
895 | ||
896 | if (!priv && (ab = n->body) != (abstBodyNode) 0) | |
897 | { | |
898 | fcnNodeList ops = ab->fcns; | |
899 | ||
900 | if (!fcnNodeList_isEmpty (ops)) | |
901 | { | |
902 | fcnNodeList_elements (ops, i) | |
903 | { | |
904 | if (i->typespec == (lclTypeSpecNode) 0) | |
905 | { | |
906 | cstring fname = ltoken_getRawString (i->name); | |
907 | ||
908 | if (usymtab_exists (fname)) | |
909 | { | |
910 | uentry e = usymtab_lookup (fname); | |
911 | fileloc floc = fileloc_fromTok (i->declarator->id); | |
912 | ||
913 | if (uentry_isForward (e)) | |
914 | { | |
915 | usymtab_supEntry | |
916 | (uentry_makeTypeListFunction | |
917 | (fname, typeIdSet_insert (uentry_accessType (e), uid), | |
918 | floc)); | |
919 | } | |
920 | else | |
921 | { | |
922 | usymtab_supEntry | |
923 | (uentry_makeSpecFunction | |
924 | (fname, uentry_getType (e), | |
925 | typeIdSet_insert (uentry_accessType (e), uid), | |
926 | globSet_undefined, | |
927 | sRefSet_undefined, | |
928 | floc)); | |
929 | ||
930 | if (context_inLCLLib ()) | |
931 | { | |
932 | llbuglit ("Jolly jeepers Wilma, it ain't dead after all!"); | |
933 | } | |
934 | } | |
935 | } | |
936 | else | |
937 | { | |
938 | usymtab_supEntry | |
939 | (uentry_makeForwardFunction (fname, uid, loc)); | |
940 | } | |
941 | } | |
942 | else | |
943 | { | |
944 | declareFcn (i, uid); | |
945 | } | |
946 | } end_fcnNodeList_elements; | |
947 | } | |
948 | } | |
949 | } | |
950 | ||
951 | static void | |
952 | declareExposedType (exposedNode n, bool priv) | |
953 | { | |
954 | usymId uid; | |
955 | qtype c; | |
956 | cstring s; | |
957 | ||
958 | ||
959 | if (n == (exposedNode) 0) | |
960 | { | |
961 | return; | |
962 | } | |
963 | ||
964 | c = convertLclTypeSpecNode (n->type); | |
965 | ||
966 | declaratorInvNodeList_elements (n->decls, i) | |
967 | { | |
968 | ctype realType = convertTypeExpr (qtype_getType (c), i->declarator->type); | |
969 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
970 | uentry ue; | |
971 | ||
972 | s = getVarName (i->declarator->type); | |
973 | ||
974 | ue = uentry_makeDatatypeAux (s, realType, MAYBE, NO, loc, priv); | |
975 | ||
976 | uentry_reflectQualifiers (ue, qtype_getQuals (c)); | |
977 | ||
978 | if (context_inLCLLib () && !priv) | |
979 | { | |
980 | uentry_setDefined (ue, loc); | |
981 | } | |
982 | ||
983 | uid = usymtab_supExposedTypeEntry (ue, context_inLCLLib () && !priv); | |
984 | } end_declaratorInvNodeList_elements; | |
985 | ||
986 | qtype_free (c); | |
987 | } | |
988 | ||
989 | /* | |
990 | ** ah...remember ye old days... | |
991 | ** | |
992 | ** wow...same thing in THREE symbol tables! talk about space efficiency | |
993 | ** (or as Joe Theory once said, its only a constant factor) | |
994 | */ | |
995 | ||
996 | void | |
997 | doDeclareType (typeNode t, bool priv) | |
998 | { | |
999 | ||
1000 | if (t != (typeNode) 0) | |
1001 | { | |
1002 | switch (t->kind) | |
1003 | { | |
1004 | case TK_ABSTRACT: | |
1005 | declareAbstractType (t->content.abstract, priv); | |
1006 | break; | |
1007 | ||
1008 | case TK_EXPOSED: | |
1009 | declareExposedType (t->content.exposed, priv); | |
1010 | break; | |
1011 | ||
1012 | case TK_UNION: | |
1013 | default: | |
1014 | { | |
1015 | llfatalbug (message ("declareType ERROR: unknown kind: %q", | |
1016 | cstring_fromCharsO (FormatInt ((int)t->kind)))); | |
1017 | } | |
1018 | } | |
1019 | } | |
1020 | ||
1021 | } | |
1022 | ||
1023 | extern void | |
1024 | declareIter (iterNode iter) | |
1025 | { | |
1026 | fileloc loc = fileloc_fromTok (iter->name); | |
1027 | uentry ue = | |
1028 | uentry_makeIter (ltoken_unparse (iter->name), | |
1029 | ctype_makeFunction | |
1030 | (ctype_void, | |
1031 | paramNodeList_toUentryList (iter->params)), | |
1032 | fileloc_copy (loc)); | |
1033 | ||
1034 | usymtab_supEntry (ue); | |
1035 | usymtab_supEntry | |
1036 | (uentry_makeEndIter (ltoken_unparse (iter->name), loc)); | |
1037 | } | |
1038 | ||
1039 | /* | |
1040 | ** declareFcn | |
1041 | */ | |
1042 | ||
1043 | static void | |
1044 | declareFcnAux (fcnNode f, /*@only@*/ qtype qt, ctype ct, | |
1045 | typeId tn, bool priv, bool spec) | |
1046 | { | |
1047 | globalList globals; | |
1048 | typeIdSet acct; | |
1049 | sRefSet sl = sRefSet_undefined; | |
1050 | globSet globlist = globSet_undefined; | |
1051 | cstring s = getVarName (f->declarator->type); | |
1052 | fileloc loc = fileloc_fromTok (f->declarator->id); | |
1053 | uentryList args; | |
1054 | ||
1055 | /* | |
1056 | ** type conversion generates args | |
1057 | */ | |
1058 | ||
1059 | if (ctype_isFunction (ct)) | |
1060 | { | |
1061 | args = ctype_argsFunction (ct); | |
1062 | } | |
1063 | else | |
1064 | { | |
1065 | llcontbug (message ("Not function: %s", ctype_unparse (ct))); | |
1066 | args = uentryList_undefined; | |
1067 | } | |
1068 | ||
1069 | ||
1070 | fileloc_setColumnUndefined (loc); | |
1071 | ||
1072 | if (spec) | |
1073 | { | |
1074 | globals = f->globals; | |
1075 | ||
28bf4b0b | 1076 | sl = fixModifies (f, args); |
616915dd | 1077 | |
1078 | /* | |
1079 | ** Bind let declarations in modifies list | |
1080 | */ | |
1081 | ||
1082 | varDeclarationNodeList_elements (globals, glob) | |
1083 | { | |
1084 | globlist = processGlob (globlist, glob); | |
1085 | } end_varDeclarationNodeList_elements; | |
1086 | ||
1087 | ||
1088 | if (f->checks != (lclPredicateNode) 0) | |
1089 | /* push stderr on globalList */ | |
1090 | /* modifies *stderr^ */ | |
1091 | { | |
1092 | uentry ue; | |
1093 | ||
1094 | if (!(usymtab_existsVar (cstring_makeLiteralTemp ("stderr")))) | |
1095 | { | |
1096 | ctype tfile; | |
1097 | ||
1098 | llmsglit ("Global stderr implied by checks clause, " | |
1099 | "not declared in initializations."); | |
1100 | ||
1101 | tfile = usymtab_lookupType (cstring_makeLiteralTemp ("FILE")); | |
1102 | ||
1103 | if (ctype_isUndefined (tfile)) | |
1104 | { | |
1105 | llmsglit ("FILE datatype implied by checks clause not defined."); | |
1106 | tfile = ctype_unknown; | |
1107 | } | |
1108 | ||
1109 | usymtab_supGlobalEntry | |
1110 | (uentry_makeVariable (cstring_makeLiteralTemp ("stderr"), | |
1111 | tfile, fileloc_getBuiltin (), FALSE)); | |
1112 | } | |
1113 | ||
1114 | ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stderr")); | |
1115 | ||
28bf4b0b | 1116 | globlist = globSet_insert (globlist, sRef_copy (uentry_getSref (ue))); |
616915dd | 1117 | sl = sRefSet_insert (sl, sRef_buildPointer (uentry_getSref (ue))); |
616915dd | 1118 | } |
1119 | } | |
1120 | ||
1121 | if (usymId_isInvalid (tn)) | |
1122 | { | |
1123 | acct = context_fileAccessTypes (); | |
1124 | } | |
1125 | else | |
1126 | { | |
1127 | acct = typeIdSet_single (tn); | |
1128 | } | |
28bf4b0b | 1129 | |
616915dd | 1130 | if (usymtab_exists (s)) |
1131 | { | |
1132 | uentry l = usymtab_lookup (s); | |
1133 | uentry ue; | |
1134 | ||
1135 | if (uentry_isForward (l) || (fileloc_isLib (uentry_whereSpecified (l)))) | |
1136 | { | |
1137 | typeIdSet accessType; | |
1138 | ||
1139 | if (uentry_isFunction (l)) | |
1140 | { | |
1141 | accessType = typeIdSet_union (uentry_accessType (l), | |
1142 | context_fileAccessTypes ()); | |
1143 | } | |
1144 | else | |
1145 | { | |
1146 | accessType = context_fileAccessTypes (); | |
1147 | } | |
1148 | ||
1149 | if (spec) | |
1150 | { | |
1151 | ue = uentry_makeSpecFunction (s, ct, accessType, globlist, sl, loc); | |
1152 | } | |
1153 | else | |
1154 | { | |
1155 | sRefSet_free (sl); | |
1156 | globSet_free (globlist); | |
1157 | ||
1158 | ue = uentry_makeUnspecFunction (s, ct, accessType, loc); | |
1159 | } | |
1160 | ||
1161 | uentry_reflectQualifiers (ue, qtype_getQuals (qt)); | |
616915dd | 1162 | usymtab_supEntry (ue); |
1163 | } | |
1164 | else | |
1165 | { | |
1166 | /* | |
1167 | ** error reported by symtable already | |
1168 | ** | |
1169 | ** llgenerror (message ("Function redeclared: %s (previous declaration: %s)", s, | |
1170 | ** fileloc_unparse (uentry_whereSpecified (l))), | |
1171 | ** loc); | |
1172 | */ | |
1173 | ||
616915dd | 1174 | fileloc_free (loc); |
1175 | sRefSet_free (sl); | |
1176 | globSet_free (globlist); | |
1177 | } | |
1178 | } | |
1179 | else | |
1180 | { | |
1181 | uentry le; | |
1182 | ||
1183 | if (spec) | |
1184 | { | |
1185 | if (priv) | |
1186 | { | |
1187 | le = uentry_makePrivFunction2 (s, ct, acct, globlist, sl, loc); | |
1188 | } | |
1189 | else | |
1190 | { | |
1191 | le = uentry_makeSpecFunction (s, ct, acct, globlist, sl, loc); | |
1192 | } | |
1193 | } | |
1194 | else | |
1195 | { | |
1196 | le = uentry_makeUnspecFunction (s, ct, acct, loc); | |
1197 | ||
1198 | sRefSet_free (sl); | |
1199 | globSet_free (globlist); | |
1200 | } | |
1201 | ||
1202 | if (context_inLCLLib () && !priv) | |
1203 | { | |
1204 | uentry_setDefined (le, loc); | |
1205 | } | |
1206 | ||
1207 | uentry_reflectQualifiers (le, qtype_getQuals (qt)); | |
1208 | ||
28bf4b0b | 1209 | if (qual_isUnknown (f->special)) { |
1210 | ; | |
1211 | } else if (qual_isPrintfLike (f->special)) { | |
1212 | uentry_setPrintfLike (le); | |
1213 | } else if (qual_isScanfLike (f->special)) { | |
1214 | uentry_setScanfLike (le); | |
1215 | } else if (qual_isMessageLike (f->special)) { | |
1216 | uentry_setMessageLike (le); | |
1217 | } else { | |
1218 | BADBRANCH; | |
1219 | } | |
616915dd | 1220 | |
1221 | usymtab_supEntry (le); | |
1222 | } | |
1223 | ||
1224 | qtype_free (qt); | |
1225 | } | |
1226 | ||
1227 | extern void | |
1228 | doDeclareFcn (fcnNode f, typeId tn, bool priv, bool spec) | |
1229 | { | |
1230 | qtype qt = convertLclTypeSpecNode (f->typespec); | |
1231 | ctype ct = convertTypeExpr (qtype_getType (qt), f->declarator->type); | |
1232 | ||
28bf4b0b | 1233 | declareFcnAux (f, qt, ct, tn, priv, spec); |
616915dd | 1234 | } |
1235 | ||
1236 | /* | |
1237 | ** is s is an argument to f, return its arg no. | |
1238 | ** otherwise, return 0 | |
1239 | */ | |
1240 | ||
1241 | static int | |
1242 | getParamNo (cstring s, fcnNode f) | |
1243 | { | |
1244 | /* gasp, maybe should do run-time checks here */ | |
1245 | paramNodeList params; | |
1246 | typeExpr fd = f->declarator->type; | |
1247 | ||
1248 | /* is this a bug in the LCL grammar? */ | |
1249 | ||
1250 | while (fd != NULL && (fd->kind == TEXPR_PTR || fd->kind == TEXPR_ARRAY)) | |
1251 | { | |
1252 | if (fd->kind == TEXPR_PTR) | |
1253 | { | |
1254 | fd = fd->content.pointer; | |
1255 | } | |
1256 | else | |
1257 | { | |
1258 | /*@-null@*/ fd = fd->content.array.elementtype; /*@=null@*/ | |
1259 | ||
1260 | /* | |
1261 | ** This is a bug in checking, that I should eventually fix. | |
1262 | ** Need some way of deleting the guard from the true branch, | |
1263 | ** but adding it back in the false branch... | |
1264 | */ | |
1265 | } | |
1266 | } | |
1267 | ||
1268 | llassert (fd != NULL); | |
1269 | ||
1270 | if (fd->kind != TEXPR_FCN) | |
1271 | { | |
1272 | llfatalbug (message ("getParamNo: not a function: %q (%d)", | |
1273 | typeExpr_unparse (fd), (int) fd->kind)); | |
1274 | } | |
1275 | ||
1276 | params = fd->content.function.args; | |
1277 | ||
1278 | if (paramNodeList_empty (params)) | |
1279 | { | |
1280 | return -1; | |
1281 | } | |
1282 | else | |
1283 | { | |
1284 | int pno = 0; | |
1285 | ||
1286 | paramNodeList_elements (params, i) | |
1287 | { | |
1288 | if (i->paramdecl != (typeExpr) 0) /* handle (void) */ | |
1289 | { | |
1290 | if (cstring_equal (s, getVarName (i->paramdecl))) | |
1291 | { | |
1292 | return pno; | |
1293 | } | |
1294 | } | |
1295 | pno++; | |
1296 | } end_paramNodeList_elements; | |
1297 | return -1; | |
1298 | } | |
1299 | } | |
1300 | ||
1301 | static /*@null@*/ /*@observer@*/ termNode | |
1302 | getLetDecl (cstring s, fcnNode f) | |
1303 | { | |
1304 | letDeclNodeList x = f->lets; | |
1305 | ||
1306 | letDeclNodeList_elements (x, i) | |
1307 | { | |
1308 | if (cstring_equal (s, ltoken_getRawString (i->varid))) | |
1309 | { | |
1310 | if (i->sortspec != NULL) | |
1311 | { | |
1312 | llbuglit ("getLetDecl: cannot return sort!"); | |
1313 | } | |
1314 | else | |
1315 | { /* is a termNode */ | |
1316 | return i->term; | |
1317 | } | |
1318 | } | |
1319 | } end_letDeclNodeList_elements; | |
1320 | ||
1321 | return (termNode) 0; | |
1322 | } | |
1323 | ||
1324 | /* | |
1325 | ** processTermNode --- based on printTermNode2 | |
1326 | */ | |
1327 | ||
1328 | static /*@exposed@*/ sRef | |
1329 | processTermNode (/*@null@*/ opFormNode op, termNodeList args, | |
1330 | fcnNode f, uentryList cl) | |
1331 | { | |
1332 | if (op != (opFormNode) 0) | |
1333 | { | |
1334 | switch (op->kind) | |
1335 | { | |
1336 | case OPF_IF: | |
1337 | llcontbuglit ("processTermNode: OPF_IF: not handled"); | |
1338 | break; | |
1339 | case OPF_ANYOP: | |
1340 | llcontbuglit ("processTermNode: OPF_ANYOP: not handled"); | |
1341 | break; | |
1342 | case OPF_MANYOP: | |
1343 | { | |
1344 | int size = termNodeList_size (args); | |
1345 | ||
1346 | if (size == 1 | |
1347 | && (cstring_equalLit (ltoken_getRawString (op->content.anyop), "'") || | |
1348 | cstring_equalLit (ltoken_getRawString (op->content.anyop), "^"))) | |
1349 | { | |
1350 | return (fixTermNode (termNodeList_head (args), f, cl)); | |
1351 | } | |
1352 | else | |
1353 | { | |
1354 | ; | |
1355 | } | |
1356 | break; | |
1357 | } | |
1358 | case OPF_ANYOPM: | |
1359 | { | |
1360 | int size = termNodeList_size (args); | |
1361 | ||
1362 | if (size == 1 | |
1363 | && (cstring_equalLit (ltoken_getRawString (op->content.anyop), "*"))) | |
1364 | { | |
1365 | sRef ft; | |
1366 | sRef res; | |
1367 | ||
1368 | ft = fixTermNode (termNodeList_head (args), f, cl); | |
1369 | res = sRef_buildPointer (ft); | |
1370 | return (res); | |
1371 | } | |
1372 | else | |
1373 | { | |
1374 | ; | |
1375 | } | |
1376 | break; | |
1377 | } | |
1378 | case OPF_MANYOPM: | |
1379 | llcontbuglit ("OPF_MANYOPM: not handled\n"); | |
1380 | break; | |
1381 | case OPF_MIDDLE: | |
1382 | llcontbuglit ("OPF_MIDDLE: not handled\n"); | |
1383 | break; | |
1384 | case OPF_MMIDDLE: | |
1385 | llcontbuglit ("OPF_MMIDDLE: not handled\n"); | |
1386 | break; | |
1387 | case OPF_MIDDLEM: | |
1388 | llcontbuglit ("OPF_MIDDLEM: not handled\n"); | |
1389 | break; | |
1390 | case OPF_MMIDDLEM: | |
1391 | llcontbuglit ("OPF_MMIDDLEM: not handled\n"); | |
1392 | break; | |
1393 | case OPF_BMIDDLE: | |
1394 | if (op->content.middle == 1) | |
1395 | llbug (message ("array fetch: [%q]", | |
1396 | termNodeList_unparse (args))); | |
1397 | else | |
1398 | llcontbuglit ("OPF_BMIDDLE: bad\n"); | |
1399 | break; | |
1400 | ||
1401 | case OPF_BMMIDDLE: | |
1402 | if (op->content.middle <= 1) | |
1403 | { | |
1404 | sRef arr = fixTermNode (termNodeList_head (args), f, cl); | |
1405 | sRef ret; | |
1406 | ||
1407 | if (op->content.middle == 1) | |
1408 | { | |
1409 | termNode t = (termNodeList_reset (args), | |
1410 | termNodeList_advance (args), | |
1411 | termNodeList_current (args)); | |
1412 | ||
1413 | if (t->kind == TRM_LITERAL) | |
1414 | { | |
1415 | int i; | |
1416 | ||
1417 | if (sscanf | |
1418 | (cstring_toCharsSafe | |
1419 | (ltoken_getRawString (t->literal)), | |
1420 | "%d", &i) == 1) | |
1421 | { | |
1422 | ret = sRef_buildArrayFetchKnown (arr, i); | |
1423 | } | |
1424 | else | |
1425 | { | |
1426 | ret = sRef_buildArrayFetch (arr); | |
1427 | } | |
1428 | ||
1429 | return (ret); | |
1430 | } | |
1431 | } | |
1432 | ||
1433 | /* unknown index */ | |
1434 | ||
1435 | ret = sRef_buildArrayFetch (arr); | |
1436 | ||
1437 | return (ret); | |
1438 | } | |
1439 | else | |
1440 | { | |
1441 | llcontbug (message ("op->content.middle = %d", | |
1442 | op->content.middle)); | |
1443 | break; | |
1444 | } | |
1445 | ||
1446 | case OPF_BMIDDLEM: | |
1447 | llcontbuglit ("OPF_BMIDDLEM not handled"); | |
1448 | break; | |
1449 | ||
1450 | case OPF_BMMIDDLEM: | |
1451 | llcontbuglit ("OPF_BMMIDDLEM not handled"); | |
1452 | break; | |
1453 | ||
1454 | case OPF_SELECT: | |
1455 | llcontbug (message ("select: .%s", | |
1456 | ltoken_getRawString (op->content.id))); | |
1457 | break; | |
1458 | ||
1459 | case OPF_MAP: | |
1460 | llcontbug (message ("map: .%s", | |
1461 | ltoken_getRawString (op->content.id))); | |
1462 | break; | |
1463 | ||
1464 | case OPF_MSELECT: | |
1465 | { | |
1466 | sRef rec = fixTermNode (termNodeList_head (args), f, cl); | |
1467 | sRef ret; | |
1468 | ctype ct = ctype_realType (sRef_deriveType (rec, cl)); | |
1469 | cstring fieldname = ltoken_getRawString (op->content.id); | |
1470 | ||
1471 | ct = ctype_realType (ct); | |
1472 | ||
1473 | /* | |
1474 | ** does it correspond to a typedef struct field | |
1475 | ** | |
1476 | ** (kind of kludgey, but there is no direct way to | |
1477 | ** tell if it is an lsl operator instead) | |
1478 | */ | |
1479 | ||
1480 | if (ctype_isStructorUnion (ct) && | |
1481 | uentry_isValid | |
1482 | (uentryList_lookupField (ctype_getFields (ct), fieldname))) | |
1483 | { | |
1484 | cstring fname = cstring_copy (fieldname); | |
1485 | ||
1486 | ret = sRef_buildField (rec, fname); | |
1487 | cstring_markOwned (fname); | |
1488 | } | |
1489 | else | |
1490 | { | |
1491 | ret = sRef_undefined; | |
1492 | } | |
1493 | ||
1494 | return ret; | |
1495 | } | |
1496 | case OPF_MMAP: | |
1497 | { | |
1498 | sRef rec = fixTermNode (termNodeList_head (args), f, cl); | |
1499 | sRef ret = sRef_undefined; | |
1500 | ctype ct = ctype_realType (sRef_deriveType (rec, cl)); | |
1501 | cstring fieldname = ltoken_getRawString (op->content.id); | |
1502 | ||
1503 | /* | |
1504 | ** does it correspond to a typedef struct field | |
1505 | */ | |
1506 | ||
1507 | if (ctype_isPointer (ct)) | |
1508 | { | |
1509 | ctype ctb = ctype_realType (ctype_baseArrayPtr (ct)); | |
1510 | ||
1511 | if (ctype_isStructorUnion (ctb) && | |
1512 | uentry_isValid (uentryList_lookupField | |
1513 | (ctype_getFields (ctb), fieldname))) | |
1514 | { | |
1515 | cstring fname = cstring_copy (fieldname); | |
1516 | ||
1517 | ret = sRef_buildArrow (rec, fname); | |
1518 | cstring_markOwned (fname); | |
1519 | } | |
1520 | } | |
1521 | ||
1522 | return ret; | |
1523 | } | |
1524 | } | |
1525 | } | |
1526 | ||
1527 | return sRef_undefined; | |
1528 | } | |
1529 | ||
1530 | /* | |
1531 | ** fixModifies | |
1532 | ** | |
1533 | ** o replace anything in modifies that is bound with let with value | |
1534 | ** o replace spec variables with internal state | |
1535 | ** o replace paramaters with paramno identifiers | |
1536 | ** o replace globals with their usymid's | |
1537 | ** o make everything sRefs | |
1538 | */ | |
1539 | ||
1540 | static /*@exposed@*/ sRef fixTermNode (termNode n, fcnNode f, uentryList cl) | |
1541 | { | |
1542 | if (n != (termNode) 0) | |
1543 | { | |
1544 | switch (n->kind) | |
1545 | { | |
1546 | case TRM_LITERAL: | |
1547 | break; | |
1548 | case TRM_CONST: | |
1549 | case TRM_VAR: | |
1550 | case TRM_ZEROARY: | |
1551 | { | |
1552 | cstring s = ltoken_getRawString (n->literal); | |
1553 | termNode tl = getLetDecl (s, f); | |
1554 | ||
1555 | if (tl != (termNode) 0) | |
1556 | { | |
1557 | return (fixTermNode (tl, f, cl)); | |
1558 | } | |
1559 | else | |
1560 | { | |
1561 | int i = getParamNo (s, f); | |
1562 | ||
1563 | if (i < 0) | |
1564 | { | |
1565 | usymId usym = usymtab_getId (s); | |
1566 | ||
1567 | if (usymId_isInvalid (usym)) | |
1568 | { | |
1569 | if (usymtab_existsEither (s)) | |
1570 | { | |
1571 | return sRef_makeSpecState (); | |
1572 | } | |
1573 | else | |
1574 | { | |
1575 | llcontbuglit ("Invalid symbol in modifies list"); | |
1576 | return sRef_undefined; | |
1577 | } | |
1578 | } | |
1579 | else | |
6970c11b | 1580 | return (sRef_makeGlobal (usym, ctype_unknown, stateInfo_currentLoc ())); |
616915dd | 1581 | } |
1582 | ||
1583 | else | |
1584 | { | |
6970c11b | 1585 | sRef p = sRef_makeParam (i, ctype_unknown, stateInfo_currentLoc ()); |
1586 | return (p); | |
616915dd | 1587 | } |
1588 | } | |
1589 | } | |
1590 | case TRM_APPLICATION: | |
1591 | { | |
1592 | nameNode nn = n->name; | |
1593 | ||
1594 | if (nn != (nameNode) 0) | |
1595 | { | |
1596 | if (nn->isOpId) | |
1597 | { | |
1598 | /* must we handle n->given ? skip for now */ | |
1599 | ||
1600 | llfatalbug | |
1601 | (message ("fixTermNode: expect non-empty nameNode: " | |
1602 | "TRM_APPLICATION: %q", | |
1603 | nameNode_unparse (nn))); | |
1604 | } | |
1605 | else | |
1606 | { | |
1607 | sRef sr; | |
1608 | ||
1609 | sr = processTermNode (nn->content.opform, n->args, f, cl); | |
1610 | return (sr); | |
1611 | } | |
1612 | } | |
1613 | ||
1614 | return sRef_undefined; | |
1615 | } | |
1616 | case TRM_UNCHANGEDALL: | |
1617 | case TRM_UNCHANGEDOTHERS: | |
1618 | case TRM_SIZEOF: | |
1619 | case TRM_QUANTIFIER: | |
1620 | return sRef_undefined; | |
1621 | } | |
1622 | } | |
1623 | ||
1624 | return sRef_undefined; | |
1625 | } | |
1626 | ||
1627 | static | |
1628 | /*@only@*/ sRefSet fixModifies (fcnNode f, uentryList cl) | |
1629 | { | |
1630 | static bool shownWarning = FALSE; | |
1631 | modifyNode m = f->modify; | |
1632 | sRefSet sl = sRefSet_new (); | |
1633 | ||
1634 | if (m != (modifyNode) 0) | |
1635 | { | |
1636 | if (m->hasStoreRefList) | |
1637 | { | |
1638 | storeRefNodeList srefs = m->list; | |
1639 | ||
1640 | storeRefNodeList_elements (srefs, i) | |
1641 | { | |
1642 | if (storeRefNode_isObj (i) || storeRefNode_isType (i)) | |
1643 | { | |
1644 | if (!shownWarning) | |
1645 | { | |
1646 | fileloc loc = fileloc_fromTok (f->name); | |
1647 | ||
1648 | llmsg (message | |
1649 | ("%q: Warning: object and type modifications " | |
11db3170 | 1650 | "not understood by Splint", |
616915dd | 1651 | fileloc_unparse (loc))); |
1652 | fileloc_free (loc); | |
1653 | shownWarning = TRUE; | |
1654 | } | |
1655 | } | |
1656 | else if (storeRefNode_isSpecial (i)) | |
1657 | { | |
1658 | sl = sRefSet_insert (sl, i->content.ref); | |
1659 | } | |
1660 | else if (storeRefNode_isTerm (i)) | |
1661 | { | |
1662 | sRef s = fixTermNode (i->content.term, f, cl); | |
1663 | ||
1664 | if (sRef_isKnown (s)) | |
1665 | { | |
1666 | sl = sRefSet_insert (sl, s); | |
1667 | } | |
1668 | } | |
1669 | else | |
1670 | { | |
1671 | BADEXIT; | |
1672 | } | |
1673 | } end_storeRefNodeList_elements; | |
1674 | ||
1675 | } | |
1676 | } | |
1677 | ||
1678 | return sl; | |
1679 | } | |
1680 | ||
1681 | static /*@only@*/ cstring | |
1682 | paramNode_name (paramNode x) | |
1683 | { | |
1684 | return (typeExpr_name (x->paramdecl)); | |
1685 | } | |
1686 | ||
1687 | static /*@only@*/ uentry | |
1688 | paramNode_toUentry (paramNode p) | |
1689 | { | |
1690 | if (p != (paramNode) 0) | |
1691 | { | |
1692 | if (p->kind == PELIPSIS) | |
1693 | { | |
1694 | return uentry_makeElipsisMarker (); | |
1695 | } | |
1696 | else | |
1697 | { | |
1698 | qtype ct = convertLclTypeSpecNode (p->type); | |
1699 | ctype cr = convertTypeExpr (qtype_getType (ct), p->paramdecl); | |
1700 | cstring pname = (p->paramdecl == (typeExpr)0) ? cstring_undefined | |
1701 | : paramNode_name (p); | |
6970c11b | 1702 | uentry ue = uentry_makeVariableParam (pname, cr, g_currentloc); |
616915dd | 1703 | |
1704 | uentry_reflectQualifiers (ue, qtype_getQuals (ct)); | |
1705 | qtype_free (ct); | |
1706 | return (ue); | |
1707 | } | |
1708 | } | |
1709 | else | |
1710 | { | |
1711 | llcontbuglit ("paramNode_toUentry: NULL"); | |
1712 | return uentry_undefined; | |
1713 | } | |
1714 | BADEXIT; | |
1715 | } | |
1716 | ||
1717 | static uentryList | |
1718 | paramNodeList_toUentryList (paramNodeList p) | |
1719 | { | |
1720 | uentryList cl = uentryList_new (); | |
1721 | ||
1722 | if (paramNodeList_isNull (p)) return (cl); | |
1723 | ||
1724 | paramNodeList_elements (p, current) | |
1725 | { | |
1726 | cl = uentryList_add (cl, paramNode_toUentry (current)); | |
1727 | } end_paramNodeList_elements; | |
1728 | ||
1729 | return cl; | |
1730 | } | |
1731 | ||
1732 |