]>
Commit | Line | Data |
---|---|---|
616915dd | 1 | /* |
11db3170 | 2 | ** Splint - annotation-assisted static program checker |
c59f5181 | 3 | ** Copyright (C) 1994-2003 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" |
b73d1009 | 35 | # include "basic.h" |
616915dd | 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 | |
e5081f8c | 274 | (tn, ctype_unknown, MAYBE, qual_createConcrete (), |
275 | fileloc_getBuiltin ())); | |
616915dd | 276 | |
277 | } | |
278 | /*@switchbreak@*/ break; | |
279 | } | |
280 | case LLT_CHAR: | |
281 | c = ctype_combine (ctype_char, c); | |
282 | /*@switchbreak@*/ break; | |
283 | ||
284 | case LLT_DOUBLE: | |
285 | c = ctype_combine (ctype_double, c); | |
286 | /*@switchbreak@*/ break; | |
287 | case LLT_FLOAT: | |
288 | c = ctype_combine (ctype_float, c); | |
289 | /*@switchbreak@*/ break; | |
290 | case LLT_CONST: | |
291 | case LLT_VOLATILE: | |
292 | /*@switchbreak@*/ break; | |
293 | case LLT_INT: | |
294 | c = ctype_combine (ctype_int, c); | |
295 | /*@switchbreak@*/ break; | |
296 | case LLT_LONG: | |
297 | c = ctype_combine (c, ctype_lint); | |
298 | /*@switchbreak@*/ break; | |
299 | case LLT_SHORT: | |
300 | c = ctype_combine (c, ctype_sint); | |
301 | /*@switchbreak@*/ break; | |
302 | case LLT_SIGNED: | |
303 | c = ctype_combine (c, ctype_int); | |
304 | /*@switchbreak@*/ break; | |
305 | case LLT_UNSIGNED: | |
306 | c = ctype_combine (c, ctype_uint); | |
307 | /*@switchbreak@*/ break; | |
308 | case LLT_UNKNOWN: | |
309 | c = ctype_combine (ctype_unknown, c); | |
310 | /*@switchbreak@*/ break; | |
311 | case LLT_VOID: | |
312 | c = ctype_combine (ctype_void, c); | |
313 | /*@switchbreak@*/ break; | |
314 | case LLT_ENUM: | |
315 | llcontbug (cstring_makeLiteral ("convertLeaves: enum")); | |
316 | c = ctype_int; | |
317 | /*@switchbreak@*/ break; | |
318 | default: | |
319 | llfatalbug (message ("convertLeaves: bad token: %q", | |
320 | ltoken_unparseCodeName (current))); | |
321 | } | |
322 | } end_ltokenList_elements; | |
323 | ||
324 | return c; | |
325 | } | |
326 | ||
327 | static enumNameList | |
328 | convertEnumList (ltokenList enums) | |
329 | { | |
330 | enumNameList el = enumNameList_new (); | |
331 | ||
332 | if (ltokenList_isDefined (enums)) | |
333 | { | |
334 | ltokenList_elements (enums, i) | |
335 | { | |
336 | enumNameList_addh | |
337 | (el, enumName_create (cstring_copy (ltoken_unparse (i)))); | |
338 | } end_ltokenList_elements; | |
339 | } | |
340 | ||
341 | return el; | |
342 | } | |
343 | ||
344 | static /*@only@*/ qtype | |
345 | convertLclTypeSpecNode (/*@null@*/ lclTypeSpecNode n) | |
346 | { | |
347 | ||
348 | if (n != (lclTypeSpecNode) 0) | |
349 | { | |
350 | qtype result; | |
351 | ||
352 | switch (n->kind) | |
353 | { | |
354 | case LTS_CONJ: | |
355 | { | |
356 | qtype c1 = convertLclTypeSpecNode (n->content.conj->a); | |
357 | qtype c2 = convertLclTypeSpecNode (n->content.conj->b); | |
358 | ||
359 | /* | |
360 | ** Is it explicit? | |
361 | */ | |
362 | ||
363 | if (fileloc_isLib (g_currentloc) | |
364 | || fileloc_isStandardLibrary (g_currentloc)) | |
365 | { | |
366 | result = qtype_mergeImplicitAlt (c1, c2); | |
367 | } | |
368 | else | |
369 | { | |
370 | result = qtype_mergeAlt (c1, c2); | |
371 | } | |
372 | ||
373 | break; | |
374 | } | |
375 | case LTS_TYPE: | |
376 | llassert (n->content.type != NULL); | |
377 | result = qtype_create (convertLeaves (n->content.type->ctypes)); | |
378 | break; | |
379 | case LTS_STRUCTUNION: | |
380 | { | |
381 | strOrUnionNode sn; | |
382 | cstring cn = cstring_undefined; | |
383 | ||
384 | sn = n->content.structorunion; | |
385 | ||
386 | llassert (sn != (strOrUnionNode) 0); | |
387 | ||
388 | if (!ltoken_isUndefined (sn->opttagid)) | |
389 | { | |
390 | cn = cstring_copy (ltoken_getRawString (sn->opttagid)); | |
391 | } | |
392 | else | |
393 | { | |
394 | cn = fakeTag (); | |
395 | } | |
396 | ||
397 | switch (sn->kind) | |
398 | { | |
399 | case SU_STRUCT: | |
400 | if (usymtab_existsStructTag (cn)) | |
401 | { | |
402 | ||
403 | result = qtype_create (uentry_getAbstractType | |
404 | (usymtab_lookupStructTag (cn))); | |
405 | cstring_free (cn); | |
406 | } | |
407 | else | |
408 | { | |
409 | uentryList fl = convertuentryList (sn->structdecls); | |
410 | ctype ct; | |
411 | ||
412 | ct = ctype_createStruct (cstring_copy (cn), fl); | |
413 | ||
414 | /* | |
415 | ** If it was a forward declaration, this could add it to | |
416 | ** the table. Need to check if it exists again... | |
417 | */ | |
418 | ||
419 | if (usymtab_existsStructTag (cn)) | |
420 | { | |
421 | result = qtype_create (uentry_getAbstractType | |
422 | (usymtab_lookupStructTag (cn))); | |
423 | } | |
424 | else | |
425 | { | |
426 | fileloc loc = fileloc_fromTok (n->content.structorunion->tok); | |
427 | uentry ue = uentry_makeStructTag (cn, ct, loc); | |
428 | ||
429 | result = qtype_create (usymtab_supTypeEntry (ue)); | |
430 | } | |
431 | ||
432 | cstring_free (cn); | |
433 | } | |
434 | /*@switchbreak@*/ break; | |
435 | case SU_UNION: | |
436 | if (usymtab_existsUnionTag (cn)) | |
437 | { | |
438 | ||
439 | result = qtype_create (uentry_getAbstractType | |
440 | (usymtab_lookupUnionTag (cn))); | |
441 | cstring_free (cn); | |
442 | } | |
443 | else | |
444 | { | |
445 | uentryList fl; | |
446 | ctype ct; | |
447 | ||
448 | fl = convertuentryList (sn->structdecls); | |
449 | ct = ctype_createUnion (cstring_copy (cn), fl); | |
450 | ||
451 | /* | |
452 | ** If it was a forward declaration, this could add it to | |
453 | ** the table. Need to check if it exists again... | |
454 | */ | |
455 | ||
456 | ||
457 | ||
458 | if (usymtab_existsUnionTag (cn)) | |
459 | { | |
460 | ||
461 | result = qtype_create (uentry_getAbstractType | |
462 | (usymtab_lookupUnionTag (cn))); | |
463 | } | |
464 | else | |
465 | { | |
466 | fileloc loc = fileloc_fromTok (n->content.structorunion->tok); | |
467 | uentry ue = uentry_makeUnionTag (cn, ct, loc); | |
468 | ||
469 | result = qtype_create (usymtab_supTypeEntry (ue)); | |
470 | } | |
471 | ||
472 | cstring_free (cn); | |
473 | } | |
474 | /*@switchbreak@*/ break; | |
475 | BADDEFAULT | |
476 | } | |
477 | break; | |
478 | } | |
479 | case LTS_ENUM: | |
480 | { | |
481 | enumSpecNode e = n->content.enumspec; | |
482 | enumNameList el; | |
483 | cstring ename; | |
484 | bool first = TRUE; | |
485 | ctype ta; | |
486 | ctype cet; | |
487 | ||
488 | llassert (e != NULL); | |
489 | el = convertEnumList (e->enums); | |
490 | ||
491 | if (!ltoken_isUndefined (e->opttagid)) /* named enumerator */ | |
492 | { | |
493 | ename = cstring_copy (ltoken_getRawString (e->opttagid)); | |
494 | } | |
495 | else | |
496 | { | |
497 | ename = fakeTag (); | |
498 | } | |
499 | ||
500 | cet = ctype_createEnum (ename, el); | |
501 | ||
502 | if (usymtab_existsEnumTag (ename)) | |
503 | { | |
504 | ta = uentry_getAbstractType (usymtab_lookupEnumTag (ename)); | |
505 | } | |
506 | else | |
507 | { | |
508 | fileloc loc = fileloc_fromTok (e->tok); | |
509 | uentry ue = uentry_makeEnumTag (ename, cet, loc); | |
510 | ||
511 | ta = usymtab_supTypeEntry (ue); | |
512 | } | |
513 | ||
514 | enumNameList_elements (el, en) | |
515 | { | |
516 | uentry ue; | |
517 | fileloc loc; | |
518 | ||
519 | if (first) | |
520 | { | |
521 | ltokenList_reset (e->enums); | |
522 | first = FALSE; | |
523 | } | |
524 | else | |
525 | { | |
526 | ltokenList_advance (e->enums); | |
527 | } | |
528 | ||
529 | loc = fileloc_fromTok (ltokenList_current (e->enums)); | |
530 | ue = uentry_makeSpecEnumConstant (en, cet, loc); | |
531 | ||
532 | /* | |
533 | ** Can't check name here, might not have | |
534 | ** type yet. Will check in .lh file? | |
535 | */ | |
536 | ||
537 | ue = usymtab_supGlobalEntryReturn (ue); | |
538 | ||
539 | if (context_inLCLLib ()) | |
540 | { | |
541 | uentry_setDefined (ue, loc); | |
542 | } | |
543 | } end_enumNameList_elements; | |
544 | ||
545 | result = qtype_create (ta); | |
546 | } | |
547 | break; | |
548 | default: | |
549 | { | |
550 | llfatalbug (message ("convertLclTypeSpecNode: unknown lclTypeSpec kind: %d", | |
551 | (int) n->kind)); | |
552 | } | |
553 | } | |
554 | ||
555 | result = qtype_addQualList (result, n->quals); | |
556 | ||
f9264521 | 557 | if (pointers_isDefined (n->pointers)) |
616915dd | 558 | { |
559 | qtype_adjustPointers (n->pointers, result); | |
560 | } | |
561 | ||
562 | return result; | |
563 | } | |
564 | else | |
565 | { | |
566 | llcontbug (cstring_makeLiteral ("convertLclTypeSpecNode: null")); | |
567 | return qtype_unknown (); | |
568 | } | |
569 | BADEXIT; | |
570 | } | |
571 | ||
572 | static /*@only@*/ multiVal | |
573 | literalValue (ctype ct, ltoken lit) | |
574 | { | |
575 | cstring text = cstring_fromChars (lsymbol_toChars (ltoken_getText (lit))); | |
576 | char first; | |
577 | ||
578 | if (cstring_length (text) > 0) | |
579 | { | |
580 | first = cstring_firstChar (text); | |
581 | } | |
582 | else | |
583 | { | |
584 | return multiVal_unknown (); | |
585 | } | |
586 | ||
587 | ||
588 | if /*@-usedef@*/ (first == '\"') /*@=usedef@*/ | |
589 | { | |
abd7f895 | 590 | size_t len = cstring_length (text) - 2; |
616915dd | 591 | char *val = mstring_create (len); |
592 | ||
593 | llassert (cstring_lastChar (text) == '\"'); | |
abd7f895 | 594 | strncpy (val, cstring_toCharsSafe (text) + 1, len); |
616915dd | 595 | return (multiVal_makeString (cstring_fromCharsO (val))); |
596 | } | |
597 | ||
598 | if (ctype_isDirectInt (ct) || ctype_isPointer (ct)) | |
599 | { | |
600 | long val = 0; | |
601 | ||
602 | if (sscanf (cstring_toCharsSafe (text), "%ld", &val) == 1) | |
603 | { | |
604 | return multiVal_makeInt (val); | |
605 | } | |
606 | } | |
607 | ||
608 | return multiVal_unknown (); | |
609 | } | |
610 | ||
611 | ||
612 | /* | |
613 | ** declareConstant | |
614 | ** | |
615 | ** unfortunately, because the abstract types are different, this | |
616 | ** cannot be easily subsumed into declareVar. | |
617 | */ | |
618 | ||
619 | void | |
620 | doDeclareConstant (constDeclarationNode c, bool priv) | |
621 | { | |
622 | lclTypeSpecNode t; | |
623 | ctype ctx; | |
624 | qtype qt; | |
625 | ||
626 | if (c == (constDeclarationNode) 0) | |
627 | { | |
628 | return; | |
629 | } | |
630 | ||
631 | t = c->type; | |
632 | qt = convertLclTypeSpecNode (t); | |
633 | ||
634 | ctx = qtype_getType (qt); | |
635 | ||
636 | initDeclNodeList_elements (c->decls, i) | |
637 | { | |
638 | ctype ct = convertTypeExpr (ctx, i->declarator->type); | |
639 | cstring s = getVarName (i->declarator->type); | |
640 | ||
641 | if (ctype_isFunction (ct)) | |
642 | { | |
643 | fcnNode fcn = fcnNode_fromDeclarator (lclTypeSpecNode_copy (t), | |
644 | declaratorNode_copy (i->declarator)); | |
645 | ||
646 | /* FALSE == unspecified function, only a declaration */ | |
647 | ||
648 | doDeclareFcn (fcn, typeId_invalid, priv, FALSE); | |
649 | fcnNode_free (fcn); | |
650 | } | |
651 | else | |
652 | { | |
653 | uentry ue; | |
654 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
655 | ||
656 | if (i->value != (termNode)0 && | |
657 | i->value->kind == TRM_LITERAL) | |
658 | { | |
5e211f69 | 659 | ue = uentry_makeConstantValue (s, ct, loc, priv, literalValue (ct, i->value->literal)); |
616915dd | 660 | } |
661 | else | |
662 | { | |
5e211f69 | 663 | ue = uentry_makeConstantValue (s, ct, loc, priv, multiVal_unknown ()); |
616915dd | 664 | } |
5e211f69 | 665 | |
666 | uentry_reflectQualifiers (ue, qtype_getQuals (qt)); | |
616915dd | 667 | |
668 | if (context_inLCLLib () && !priv) | |
669 | { | |
670 | uentry_setDefined (ue, loc); | |
671 | } | |
672 | ||
673 | usymtab_supGlobalEntry (ue); | |
674 | } | |
675 | } end_initDeclNodeList_elements; | |
676 | ||
677 | qtype_free (qt); | |
678 | } | |
679 | ||
680 | static cstring | |
681 | getVarName (/*@null@*/ typeExpr x) | |
682 | { | |
683 | cstring s = cstring_undefined; | |
684 | ||
685 | if (x != (typeExpr) 0) | |
686 | { | |
687 | switch (x->kind) | |
688 | { | |
689 | case TEXPR_BASE: | |
690 | s = ltoken_getRawString (x->content.base); | |
691 | break; | |
692 | case TEXPR_PTR: | |
693 | s = getVarName (x->content.pointer); | |
694 | break; | |
695 | case TEXPR_ARRAY: | |
696 | s = getVarName (x->content.array.elementtype); | |
697 | break; | |
698 | case TEXPR_FCN: | |
699 | s = getVarName (x->content.function.returntype); | |
700 | break; | |
701 | default: | |
702 | llfatalbug (message ("getVarName: unknown typeExprKind: %d", (int) x->kind)); | |
703 | } | |
704 | } | |
705 | ||
706 | return s; | |
707 | } | |
708 | ||
709 | void | |
710 | doDeclareVar (varDeclarationNode v, bool priv) | |
711 | { | |
712 | lclTypeSpecNode t; | |
713 | qtype c; | |
714 | ||
715 | if (v == (varDeclarationNode) 0) | |
716 | { | |
717 | return; | |
718 | } | |
719 | ||
720 | t = v->type; | |
721 | c = convertLclTypeSpecNode (t); | |
722 | ||
723 | initDeclNodeList_elements (v->decls, i) | |
724 | { | |
725 | ctype ct = convertTypeExpr (qtype_getType (c), i->declarator->type); | |
726 | cstring s = getVarName (i->declarator->type); | |
727 | ||
728 | qtype_setType (c, ct); | |
729 | ||
730 | if (ctype_isFunction (ct)) | |
731 | { | |
732 | fcnNode fcn; | |
733 | ||
734 | ||
735 | fcn = fcnNode_fromDeclarator (lclTypeSpecNode_copy (t), | |
736 | declaratorNode_copy (i->declarator)); | |
737 | ||
738 | /* FALSE == unspecified function, only a declaration */ | |
739 | declareFcnAux (fcn, qtype_unknown (), ct, | |
740 | typeId_invalid, priv, FALSE); | |
741 | fcnNode_free (fcn); | |
742 | } | |
743 | else | |
744 | { | |
745 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
746 | uentry le = uentry_makeVariable (s, ct, loc, priv); | |
747 | ||
748 | uentry_reflectQualifiers (le, qtype_getQuals (c)); | |
749 | ||
750 | if (uentry_isCheckedUnknown (le)) | |
751 | { | |
752 | if (context_getFlag (FLG_IMPCHECKEDSTRICTSPECGLOBALS)) | |
753 | { | |
754 | uentry_setCheckedStrict (le); | |
755 | } | |
756 | else if (context_getFlag (FLG_IMPCHECKEDSPECGLOBALS)) | |
757 | { | |
758 | uentry_setChecked (le); | |
759 | } | |
760 | else if (context_getFlag (FLG_IMPCHECKMODSPECGLOBALS)) | |
761 | { | |
762 | uentry_setCheckMod (le); | |
763 | } | |
764 | else | |
765 | { | |
766 | ; /* okay */ | |
767 | } | |
768 | } | |
769 | ||
770 | if (context_inLCLLib () && !priv) | |
771 | { | |
772 | uentry_setDefined (le, loc); | |
773 | } | |
774 | ||
775 | if (initDeclNode_isRedeclaration (i)) | |
776 | { | |
777 | usymtab_replaceEntry (le); | |
778 | } | |
779 | else | |
780 | { | |
781 | le = usymtab_supEntrySrefReturn (le); | |
782 | } | |
783 | } | |
784 | } end_initDeclNodeList_elements; | |
785 | ||
786 | qtype_free (c); | |
787 | } | |
788 | ||
789 | static globSet | |
790 | processGlob (/*@returned@*/ globSet globs, varDeclarationNode v) | |
791 | { | |
792 | if (v == (varDeclarationNode) 0) | |
793 | { | |
794 | return globs; | |
795 | } | |
796 | ||
797 | if (v->isSpecial) | |
798 | { | |
799 | globs = globSet_insert (globs, v->sref); | |
800 | } | |
801 | else | |
802 | { | |
803 | lclTypeSpecNode t = v->type; | |
804 | qtype qt = convertLclTypeSpecNode (t); | |
805 | ctype c = qtype_getType (qt); | |
806 | cstring s; | |
807 | ||
808 | initDeclNodeList_elements (v->decls, i) | |
809 | { | |
810 | ctype ct; | |
811 | uentry ue; | |
812 | qualList quals = qtype_getQuals (qt); | |
813 | ||
814 | s = getVarName (i->declarator->type); | |
815 | ue = usymtab_lookupGlobSafe (s); | |
816 | ||
817 | if (uentry_isInvalid (ue)) | |
818 | { | |
819 | ; /* error already reported */ | |
820 | } | |
821 | else | |
822 | { | |
823 | if (uentry_isPriv (ue)) | |
824 | { | |
825 | globs = globSet_insert (globs, sRef_makeSpecState ()); | |
826 | } | |
827 | else | |
828 | { | |
829 | uentry ce = uentry_copy (ue); | |
830 | ctype lt = uentry_getType (ce); | |
831 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
832 | ||
833 | ct = convertTypeExpr (c, i->declarator->type); | |
834 | ||
835 | if (!ctype_match (lt, ct)) | |
836 | { | |
837 | (void) gentypeerror | |
838 | (lt, exprNode_undefined, | |
839 | ct, exprNode_undefined, | |
840 | message ("Global type mismatch %s (%t, %t)", | |
841 | s, lt, ct), | |
842 | loc); | |
843 | } | |
844 | ||
845 | uentry_reflectQualifiers (ce, quals); | |
846 | globs = globSet_insert (globs, | |
847 | sRef_copy (uentry_getSref (ce))); | |
848 | fileloc_free (loc); | |
849 | uentry_free (ce); | |
850 | } | |
851 | } | |
852 | } end_initDeclNodeList_elements; | |
853 | ||
854 | qtype_free (qt); | |
855 | } | |
856 | ||
857 | return globs; | |
858 | } | |
859 | ||
860 | static void | |
861 | declareAbstractType (abstractNode n, bool priv) | |
862 | { | |
863 | cstring tn; | |
864 | fileloc loc; | |
865 | uentry ue; | |
b73d1009 | 866 | typeId uid; |
616915dd | 867 | abstBodyNode ab; |
868 | ||
869 | if (n == (abstractNode) 0) | |
870 | { | |
871 | return; | |
872 | } | |
873 | ||
874 | ||
875 | tn = ltoken_getRawString (n->name); | |
876 | ||
877 | loc = fileloc_fromTok (n->tok); | |
878 | ||
879 | ue = uentry_makeDatatypeAux (tn, ctype_unknown, | |
e5081f8c | 880 | ynm_fromBool (n->isMutable), |
881 | qual_createAbstract (), | |
882 | loc, priv); | |
616915dd | 883 | |
884 | if (n->isRefCounted) | |
885 | { | |
886 | uentry_setRefCounted (ue); | |
887 | } | |
888 | ||
889 | if (context_inLCLLib () && !priv) | |
890 | { | |
891 | uentry_setDefined (ue, loc); | |
892 | } | |
893 | ||
894 | uid = usymtab_supAbstractTypeEntry (ue, context_inLCLLib() && !priv); | |
895 | ||
896 | ||
897 | if (!priv && (ab = n->body) != (abstBodyNode) 0) | |
898 | { | |
899 | fcnNodeList ops = ab->fcns; | |
900 | ||
901 | if (!fcnNodeList_isEmpty (ops)) | |
902 | { | |
903 | fcnNodeList_elements (ops, i) | |
904 | { | |
905 | if (i->typespec == (lclTypeSpecNode) 0) | |
906 | { | |
907 | cstring fname = ltoken_getRawString (i->name); | |
908 | ||
909 | if (usymtab_exists (fname)) | |
910 | { | |
911 | uentry e = usymtab_lookup (fname); | |
912 | fileloc floc = fileloc_fromTok (i->declarator->id); | |
913 | ||
914 | if (uentry_isForward (e)) | |
915 | { | |
916 | usymtab_supEntry | |
917 | (uentry_makeTypeListFunction | |
918 | (fname, typeIdSet_insert (uentry_accessType (e), uid), | |
919 | floc)); | |
920 | } | |
921 | else | |
922 | { | |
923 | usymtab_supEntry | |
924 | (uentry_makeSpecFunction | |
925 | (fname, uentry_getType (e), | |
926 | typeIdSet_insert (uentry_accessType (e), uid), | |
927 | globSet_undefined, | |
928 | sRefSet_undefined, | |
929 | floc)); | |
930 | ||
931 | if (context_inLCLLib ()) | |
932 | { | |
933 | llbuglit ("Jolly jeepers Wilma, it ain't dead after all!"); | |
934 | } | |
935 | } | |
936 | } | |
937 | else | |
938 | { | |
939 | usymtab_supEntry | |
940 | (uentry_makeForwardFunction (fname, uid, loc)); | |
941 | } | |
942 | } | |
943 | else | |
944 | { | |
945 | declareFcn (i, uid); | |
946 | } | |
947 | } end_fcnNodeList_elements; | |
948 | } | |
949 | } | |
950 | } | |
951 | ||
b73d1009 | 952 | static void declareExposedType (exposedNode n, bool priv) |
616915dd | 953 | { |
616915dd | 954 | qtype c; |
955 | cstring s; | |
956 | ||
957 | ||
958 | if (n == (exposedNode) 0) | |
959 | { | |
960 | return; | |
961 | } | |
962 | ||
963 | c = convertLclTypeSpecNode (n->type); | |
964 | ||
965 | declaratorInvNodeList_elements (n->decls, i) | |
966 | { | |
967 | ctype realType = convertTypeExpr (qtype_getType (c), i->declarator->type); | |
968 | fileloc loc = fileloc_fromTok (i->declarator->id); | |
969 | uentry ue; | |
970 | ||
971 | s = getVarName (i->declarator->type); | |
972 | ||
e5081f8c | 973 | ue = uentry_makeDatatypeAux (s, realType, MAYBE, qual_createConcrete (), |
974 | loc, priv); | |
616915dd | 975 | |
976 | uentry_reflectQualifiers (ue, qtype_getQuals (c)); | |
977 | ||
978 | if (context_inLCLLib () && !priv) | |
979 | { | |
980 | uentry_setDefined (ue, loc); | |
981 | } | |
982 | ||
b73d1009 | 983 | (void) usymtab_supExposedTypeEntry (ue, context_inLCLLib () && !priv); |
616915dd | 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 | { | |
4caf866b | 1015 | llfatalbug (message ("declareType: unknown kind: %d", |
1016 | (int) t->kind)); | |
616915dd | 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 | ||
b73d1009 | 1121 | if (typeId_isInvalid (tn)) |
616915dd | 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 |