Less permissive syntax for notreached comment.
[splint-patched.git] / src / usymtab_interface.c
blob2aafbe122e6a6baa4add84c8d1b742f1d99600c1
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
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.
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
25 ** usymtab_interface.c
27 ** Grammar interface to symtab.
29 ** The Splint parser will build symbol tables for abstract types and
30 ** function declarations.
34 # include "splintMacros.nf"
35 # include "basic.h"
36 # include "llgrammar.h"
37 # include "usymtab_interface.h"
38 # include "structNames.h"
40 static void
41 declareFcnAux (fcnNode p_f, /*@only@*/ qtype p_qt, ctype p_ct, typeId p_tn,
42 bool p_priv, bool p_spec);
44 static uentryList paramNodeList_toUentryList (paramNodeList p_p);
45 static /*@observer@*/ cstring getVarName (/*@null@*/ typeExpr p_x);
46 static qtype convertLclTypeSpecNode (/*@null@*/ lclTypeSpecNode p_n);
47 static ctype convertTypeExpr (ctype p_c, /*@null@*/ typeExpr p_x);
48 static /*@exposed@*/ sRef fixTermNode (termNode p_n, fcnNode p_f, uentryList p_cl);
49 static sRefSet fixModifies (fcnNode p_f, uentryList p_cl);
51 static uentryList
52 convertuentryList (stDeclNodeList x)
54 uentryList fl = uentryList_new ();
57 stDeclNodeList_elements (x, i)
59 declaratorNodeList d = i->declarators;
60 qtype q = convertLclTypeSpecNode (i->lcltypespec);
62 declaratorNodeList_elements (d, j)
64 idDecl id;
66 qtype_setType (q, convertTypeExpr (qtype_getType (q), j->type));
67 id = idDecl_create (cstring_copy (getVarName (j->type)), qtype_copy (q));
68 fl = uentryList_add (fl, uentry_makeIdVariable (id));
69 idDecl_free (id);
70 } end_declaratorNodeList_elements;
72 qtype_free (q);
73 } end_stDeclNodeList_elements;
76 return (fl);
79 #ifdef DEADCODE
80 static uentryList
81 convert_uentryList (paramNodeList x)
83 uentryList p = uentryList_undefined;
84 bool first_one = TRUE;
87 paramNodeList_elements (x, i)
89 if (i != (paramNode) 0)
91 if (paramNode_isElipsis (i))
93 first_one = FALSE;
94 p = uentryList_add (p, uentry_makeElipsisMarker ());
96 else
98 qtype q = convertLclTypeSpecNode (i->type);
99 typeExpr t = i->paramdecl;
101 qtype_setType (q, convertTypeExpr (qtype_getType (q), t));
103 /* note: has to be like this to hack around void ???? still */
105 if (first_one)
107 if (ctype_isVoid (qtype_getType (q)))
109 llassert (uentryList_isUndefined (p));
110 qtype_free (q);
111 return (p);
114 first_one = FALSE;
118 ** don't do qualifiers here, will get errors later
121 p = uentryList_add (p, uentry_makeUnnamedVariable (qtype_getType (q)));
122 qtype_free (q);
125 else
127 llbug (cstring_makeLiteral ("convertuentryList: null paramNode"));
129 } end_paramNodeList_elements;
131 if (first_one)
133 llassert (uentryList_isUndefined (p));
135 p = uentryList_makeMissingParams ();
138 return p;
140 #endif
143 ** convertTypeExpr
145 ** modify c with pointer, array, function
147 ** (based on printTypeExpr2 from abstract.c)
151 static ctype
152 convertTypeExpr (ctype c, typeExpr x)
154 if (x == (typeExpr) 0)
156 return c;
159 switch (x->kind)
161 case TEXPR_BASE:
162 return (c);
163 case TEXPR_PTR:
164 return (convertTypeExpr (ctype_makePointer (c), x->content.pointer));
165 case TEXPR_ARRAY:
166 return (convertTypeExpr (ctype_makeArray (c), x->content.array.elementtype));
167 case TEXPR_FCN:
169 ctype rv = convertTypeExpr (c, x->content.function.returntype);
170 uentryList p = paramNodeList_toUentryList (x->content.function.args);
172 if (x->content.function.returntype != NULL
173 && x->content.function.returntype->wrapped == 1
174 && ctype_isPointer (rv))
176 rv = ctype_baseArrayPtr (rv);
179 return (ctype_makeParamsFunction (rv, p));
181 default:
183 llfatalbug (message ("convertTypeExpr: unknown typeExprKind: %d",
184 (int) x->kind));
188 BADEXIT;
191 #ifdef DEADCODE
192 static
193 ctype convertCTypeExpr (ctype c, typeExpr x)
195 if (x == (typeExpr) 0)
197 return c;
200 switch (x->kind)
202 case TEXPR_BASE: return (c);
203 case TEXPR_PTR: return (convertCTypeExpr (ctype_makePointer (c),
204 x->content.pointer));
205 case TEXPR_ARRAY: return (convertCTypeExpr (ctype_makeArray (c),
206 x->content.array.elementtype));
207 case TEXPR_FCN:
209 ctype rv = convertCTypeExpr (c, x->content.function.returntype);
210 uentryList p = convert_uentryList (x->content.function.args);
212 return (ctype_makeParamsFunction (rv, p));
214 default:
216 llfatalbug (message ("convertCTypeExpr: unknown typeExprKind: %d", (int) x->kind));
219 BADEXIT;
221 #endif
224 ** convertLclTypeSpecNode
226 ** LclTypeSpecNode --> ctype
227 ** this is the base type only!
231 ** convertLeaves
233 ** for now, assume only last leaf is relevant.
234 ** this should be a safe assumption in general???
237 static ctype
238 convertLeaves (ltokenList f)
240 ctype c = ctype_unknown;
242 ltokenList_reset (f);
244 ltokenList_elements (f, current)
246 switch (ltoken_getCode (current))
248 case LLT_TYPEDEF_NAME:
250 cstring tn = ltoken_getRawString (current);
252 if (usymtab_existsTypeEither (tn))
254 c = ctype_combine (uentry_getAbstractType
255 (usymtab_lookupEither (tn)), c);
257 else if (cstring_equalLit (tn, "bool"))
260 ** Bogus...keep consistent with old lcl builtin.
262 c = ctype_bool;
264 else
266 fileloc loc = fileloc_fromTok (current);
268 voptgenerror (FLG_UNRECOG,
269 message ("Unrecognized type: %s", tn), loc);
270 fileloc_free (loc);
272 usymtab_supEntry
273 (uentry_makeDatatype
274 (tn, ctype_unknown, MAYBE, qual_createConcrete (),
275 fileloc_getBuiltin ()));
278 /*@switchbreak@*/ break;
280 case LLT_CHAR:
281 c = ctype_combine (ctype_char, c);
282 /*@switchbreak@*/ break;
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)));
322 } end_ltokenList_elements;
324 return c;
327 static enumNameList
328 convertEnumList (ltokenList enums)
330 enumNameList el = enumNameList_new ();
332 if (ltokenList_isDefined (enums))
334 ltokenList_elements (enums, i)
336 enumNameList_addh
337 (el, enumName_create (cstring_copy (ltoken_unparse (i))));
338 } end_ltokenList_elements;
341 return el;
344 static /*@only@*/ qtype
345 convertLclTypeSpecNode (/*@null@*/ lclTypeSpecNode n)
348 if (n != (lclTypeSpecNode) 0)
350 qtype result;
352 switch (n->kind)
354 case LTS_CONJ:
356 qtype c1 = convertLclTypeSpecNode (n->content.conj->a);
357 qtype c2 = convertLclTypeSpecNode (n->content.conj->b);
360 ** Is it explicit?
363 if (fileloc_isLib (g_currentloc)
364 || fileloc_isStandardLibrary (g_currentloc))
366 result = qtype_mergeImplicitAlt (c1, c2);
368 else
370 result = qtype_mergeAlt (c1, c2);
373 break;
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:
381 strOrUnionNode sn;
382 cstring cn = cstring_undefined;
384 sn = n->content.structorunion;
386 llassert (sn != (strOrUnionNode) 0);
388 if (!ltoken_isUndefined (sn->opttagid))
390 cn = cstring_copy (ltoken_getRawString (sn->opttagid));
392 else
394 cn = fakeTag ();
397 switch (sn->kind)
399 case SU_STRUCT:
400 if (usymtab_existsStructTag (cn))
403 result = qtype_create (uentry_getAbstractType
404 (usymtab_lookupStructTag (cn)));
405 cstring_free (cn);
407 else
409 uentryList fl = convertuentryList (sn->structdecls);
410 ctype ct;
412 ct = ctype_createStruct (cstring_copy (cn), fl);
415 ** If it was a forward declaration, this could add it to
416 ** the table. Need to check if it exists again...
419 if (usymtab_existsStructTag (cn))
421 result = qtype_create (uentry_getAbstractType
422 (usymtab_lookupStructTag (cn)));
424 else
426 fileloc loc = fileloc_fromTok (n->content.structorunion->tok);
427 uentry ue = uentry_makeStructTag (cn, ct, loc);
429 result = qtype_create (usymtab_supTypeEntry (ue));
432 cstring_free (cn);
434 /*@switchbreak@*/ break;
435 case SU_UNION:
436 if (usymtab_existsUnionTag (cn))
439 result = qtype_create (uentry_getAbstractType
440 (usymtab_lookupUnionTag (cn)));
441 cstring_free (cn);
443 else
445 uentryList fl;
446 ctype ct;
448 fl = convertuentryList (sn->structdecls);
449 ct = ctype_createUnion (cstring_copy (cn), fl);
452 ** If it was a forward declaration, this could add it to
453 ** the table. Need to check if it exists again...
458 if (usymtab_existsUnionTag (cn))
461 result = qtype_create (uentry_getAbstractType
462 (usymtab_lookupUnionTag (cn)));
464 else
466 fileloc loc = fileloc_fromTok (n->content.structorunion->tok);
467 uentry ue = uentry_makeUnionTag (cn, ct, loc);
469 result = qtype_create (usymtab_supTypeEntry (ue));
472 cstring_free (cn);
474 /*@switchbreak@*/ break;
475 BADDEFAULT;
477 break;
479 case LTS_ENUM:
481 enumSpecNode e = n->content.enumspec;
482 enumNameList el;
483 cstring ename;
484 bool first = TRUE;
485 ctype ta;
486 ctype cet;
488 llassert (e != NULL);
489 el = convertEnumList (e->enums);
491 if (!ltoken_isUndefined (e->opttagid)) /* named enumerator */
493 ename = cstring_copy (ltoken_getRawString (e->opttagid));
495 else
497 ename = fakeTag ();
500 cet = ctype_createEnum (ename, el);
502 if (usymtab_existsEnumTag (ename))
504 ta = uentry_getAbstractType (usymtab_lookupEnumTag (ename));
506 else
508 fileloc loc = fileloc_fromTok (e->tok);
509 uentry ue = uentry_makeEnumTag (ename, cet, loc);
511 ta = usymtab_supTypeEntry (ue);
514 enumNameList_elements (el, en)
516 uentry ue;
517 fileloc loc;
519 if (first)
521 ltokenList_reset (e->enums);
522 first = FALSE;
524 else
526 ltokenList_advance (e->enums);
529 loc = fileloc_fromTok (ltokenList_current (e->enums));
530 ue = uentry_makeSpecEnumConstant (en, cet, loc);
533 ** Can't check name here, might not have
534 ** type yet. Will check in .lh file?
537 ue = usymtab_supGlobalEntryReturn (ue);
539 if (context_inLCLLib ())
541 uentry_setDefined (ue, loc);
543 } end_enumNameList_elements;
545 result = qtype_create (ta);
547 break;
548 default:
550 llfatalbug (message ("convertLclTypeSpecNode: unknown lclTypeSpec kind: %d",
551 (int) n->kind));
555 result = qtype_addQualList (result, n->quals);
557 if (pointers_isDefined (n->pointers))
559 qtype_adjustPointers (n->pointers, result);
562 return result;
564 else
566 llcontbug (cstring_makeLiteral ("convertLclTypeSpecNode: null"));
567 return qtype_unknown ();
569 BADEXIT;
572 static /*@only@*/ multiVal
573 literalValue (ctype ct, ltoken lit)
575 cstring text = cstring_fromChars (lsymbol_toChars (ltoken_getText (lit)));
576 char first;
578 if (cstring_length (text) > 0)
580 first = cstring_firstChar (text);
582 else
584 return multiVal_unknown ();
588 if /*@-usedef@*/ (first == '\"') /*@=usedef@*/
590 size_t len = cstring_length (text) - 2;
591 char *val = mstring_create (len);
593 llassert (cstring_lastChar (text) == '\"');
594 strncpy (val, cstring_toCharsSafe (text) + 1, len);
595 return (multiVal_makeString (cstring_fromCharsO (val)));
598 if (ctype_isDirectInt (ct) || ctype_isPointer (ct))
600 long val = 0;
602 if (sscanf (cstring_toCharsSafe (text), "%ld", &val) == 1)
604 return multiVal_makeInt (val);
608 return multiVal_unknown ();
613 ** declareConstant
615 ** unfortunately, because the abstract types are different, this
616 ** cannot be easily subsumed into declareVar.
619 void
620 doDeclareConstant (constDeclarationNode c, bool priv)
622 lclTypeSpecNode t;
623 ctype ctx;
624 qtype qt;
626 if (c == (constDeclarationNode) 0)
628 return;
631 t = c->type;
632 qt = convertLclTypeSpecNode (t);
634 ctx = qtype_getType (qt);
636 initDeclNodeList_elements (c->decls, i)
638 ctype ct = convertTypeExpr (ctx, i->declarator->type);
639 cstring s = getVarName (i->declarator->type);
641 if (ctype_isFunction (ct))
643 fcnNode fcn = fcnNode_fromDeclarator (lclTypeSpecNode_copy (t),
644 declaratorNode_copy (i->declarator));
646 /* FALSE == unspecified function, only a declaration */
648 doDeclareFcn (fcn, typeId_invalid, priv, FALSE);
649 fcnNode_free (fcn);
651 else
653 uentry ue;
654 fileloc loc = fileloc_fromTok (i->declarator->id);
656 if (i->value != (termNode)0 &&
657 i->value->kind == TRM_LITERAL)
659 ue = uentry_makeConstantValue (s, ct, loc, priv, literalValue (ct, i->value->literal));
661 else
663 ue = uentry_makeConstantValue (s, ct, loc, priv, multiVal_unknown ());
666 uentry_reflectQualifiers (ue, qtype_getQuals (qt));
668 if (context_inLCLLib () && !priv)
670 uentry_setDefined (ue, loc);
673 usymtab_supGlobalEntry (ue);
675 } end_initDeclNodeList_elements;
677 qtype_free (qt);
680 static cstring
681 getVarName (/*@null@*/ typeExpr x)
683 cstring s = cstring_undefined;
685 if (x != (typeExpr) 0)
687 switch (x->kind)
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));
706 return s;
709 void
710 doDeclareVar (varDeclarationNode v, bool priv)
712 lclTypeSpecNode t;
713 qtype c;
715 if (v == (varDeclarationNode) 0)
717 return;
720 t = v->type;
721 c = convertLclTypeSpecNode (t);
723 initDeclNodeList_elements (v->decls, i)
725 ctype ct = convertTypeExpr (qtype_getType (c), i->declarator->type);
726 cstring s = getVarName (i->declarator->type);
728 qtype_setType (c, ct);
730 if (ctype_isFunction (ct))
732 fcnNode fcn;
735 fcn = fcnNode_fromDeclarator (lclTypeSpecNode_copy (t),
736 declaratorNode_copy (i->declarator));
738 /* FALSE == unspecified function, only a declaration */
739 declareFcnAux (fcn, qtype_unknown (), ct,
740 typeId_invalid, priv, FALSE);
741 fcnNode_free (fcn);
743 else
745 fileloc loc = fileloc_fromTok (i->declarator->id);
746 uentry le = uentry_makeVariable (s, ct, loc, priv);
748 uentry_reflectQualifiers (le, qtype_getQuals (c));
750 if (uentry_isCheckedUnknown (le))
752 if (context_getFlag (FLG_IMPCHECKEDSTRICTSPECGLOBALS))
754 uentry_setCheckedStrict (le);
756 else if (context_getFlag (FLG_IMPCHECKEDSPECGLOBALS))
758 uentry_setChecked (le);
760 else if (context_getFlag (FLG_IMPCHECKMODSPECGLOBALS))
762 uentry_setCheckMod (le);
764 else
766 ; /* okay */
770 if (context_inLCLLib () && !priv)
772 uentry_setDefined (le, loc);
775 if (initDeclNode_isRedeclaration (i))
777 usymtab_replaceEntry (le);
779 else
781 le = usymtab_supEntrySrefReturn (le);
784 } end_initDeclNodeList_elements;
786 qtype_free (c);
789 static globSet
790 processGlob (/*@returned@*/ globSet globs, varDeclarationNode v)
792 if (v == (varDeclarationNode) 0)
794 return globs;
797 if (v->isSpecial)
799 globs = globSet_insert (globs, v->sref);
801 else
803 lclTypeSpecNode t = v->type;
804 qtype qt = convertLclTypeSpecNode (t);
805 ctype c = qtype_getType (qt);
806 cstring s;
808 initDeclNodeList_elements (v->decls, i)
810 ctype ct;
811 uentry ue;
812 qualList quals = qtype_getQuals (qt);
814 s = getVarName (i->declarator->type);
815 ue = usymtab_lookupGlobSafe (s);
817 if (uentry_isInvalid (ue))
819 ; /* error already reported */
821 else
823 if (uentry_isPriv (ue))
825 globs = globSet_insert (globs, sRef_makeSpecState ());
827 else
829 uentry ce = uentry_copy (ue);
830 ctype lt = uentry_getType (ce);
831 fileloc loc = fileloc_fromTok (i->declarator->id);
833 ct = convertTypeExpr (c, i->declarator->type);
835 if (!ctype_match (lt, ct))
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);
845 uentry_reflectQualifiers (ce, quals);
846 globs = globSet_insert (globs,
847 sRef_copy (uentry_getSref (ce)));
848 fileloc_free (loc);
849 uentry_free (ce);
852 } end_initDeclNodeList_elements;
854 qtype_free (qt);
857 return globs;
860 static void
861 declareAbstractType (abstractNode n, bool priv)
863 cstring tn;
864 fileloc loc;
865 uentry ue;
866 typeId uid;
867 abstBodyNode ab;
869 if (n == (abstractNode) 0)
871 return;
875 tn = ltoken_getRawString (n->name);
877 loc = fileloc_fromTok (n->tok);
879 ue = uentry_makeDatatypeAux (tn, ctype_unknown,
880 ynm_fromBool (n->isMutable),
881 qual_createAbstract (),
882 loc, priv);
884 if (n->isRefCounted)
886 uentry_setRefCounted (ue);
889 if (context_inLCLLib () && !priv)
891 uentry_setDefined (ue, loc);
894 uid = usymtab_supAbstractTypeEntry (ue, context_inLCLLib() && !priv);
897 if (!priv && (ab = n->body) != (abstBodyNode) 0)
899 fcnNodeList ops = ab->fcns;
901 if (!fcnNodeList_isEmpty (ops))
903 fcnNodeList_elements (ops, i)
905 if (i->typespec == (lclTypeSpecNode) 0)
907 cstring fname = ltoken_getRawString (i->name);
909 if (usymtab_exists (fname))
911 uentry e = usymtab_lookup (fname);
912 fileloc floc = fileloc_fromTok (i->declarator->id);
914 if (uentry_isForward (e))
916 usymtab_supEntry
917 (uentry_makeTypeListFunction
918 (fname, typeIdSet_insert (uentry_accessType (e), uid),
919 floc));
921 else
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));
931 if (context_inLCLLib ())
933 llbuglit ("Jolly jeepers Wilma, it ain't dead after all!");
937 else
939 usymtab_supEntry
940 (uentry_makeForwardFunction (fname, uid, loc));
943 else
945 declareFcn (i, uid);
947 } end_fcnNodeList_elements;
952 static void declareExposedType (exposedNode n, bool priv)
954 qtype c;
955 cstring s;
958 if (n == (exposedNode) 0)
960 return;
963 c = convertLclTypeSpecNode (n->type);
965 declaratorInvNodeList_elements (n->decls, i)
967 ctype realType = convertTypeExpr (qtype_getType (c), i->declarator->type);
968 fileloc loc = fileloc_fromTok (i->declarator->id);
969 uentry ue;
971 s = getVarName (i->declarator->type);
973 ue = uentry_makeDatatypeAux (s, realType, MAYBE, qual_createConcrete (),
974 loc, priv);
976 uentry_reflectQualifiers (ue, qtype_getQuals (c));
978 if (context_inLCLLib () && !priv)
980 uentry_setDefined (ue, loc);
983 (void) usymtab_supExposedTypeEntry (ue, context_inLCLLib () && !priv);
984 } end_declaratorInvNodeList_elements;
986 qtype_free (c);
990 ** ah...remember ye old days...
992 ** wow...same thing in THREE symbol tables! talk about space efficiency
993 ** (or as Joe Theory once said, its only a constant factor)
996 void
997 doDeclareType (typeNode t, bool priv)
1000 if (t != (typeNode) 0)
1002 switch (t->kind)
1004 case TK_ABSTRACT:
1005 declareAbstractType (t->content.abstract, priv);
1006 break;
1008 case TK_EXPOSED:
1009 declareExposedType (t->content.exposed, priv);
1010 break;
1012 case TK_UNION:
1013 default:
1015 llfatalbug (message ("declareType: unknown kind: %d",
1016 (int) t->kind));
1023 extern void
1024 declareIter (iterNode iter)
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));
1034 usymtab_supEntry (ue);
1035 usymtab_supEntry
1036 (uentry_makeEndIter (ltoken_unparse (iter->name), loc));
1040 ** declareFcn
1043 static void
1044 declareFcnAux (fcnNode f, /*@only@*/ qtype qt, ctype ct,
1045 typeId tn, bool priv, bool spec)
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;
1056 ** type conversion generates args
1059 if (ctype_isFunction (ct))
1061 args = ctype_argsFunction (ct);
1063 else
1065 llcontbug (message ("Not function: %s", ctype_unparse (ct)));
1066 args = uentryList_undefined;
1070 fileloc_setColumnUndefined (loc);
1072 if (spec)
1074 globals = f->globals;
1076 sl = fixModifies (f, args);
1079 ** Bind let declarations in modifies list
1082 varDeclarationNodeList_elements (globals, glob)
1084 globlist = processGlob (globlist, glob);
1085 } end_varDeclarationNodeList_elements;
1088 if (f->checks != (lclPredicateNode) 0)
1089 /* push stderr on globalList */
1090 /* modifies *stderr^ */
1092 uentry ue;
1094 if (!(usymtab_existsVar (cstring_makeLiteralTemp ("stderr"))))
1096 ctype tfile;
1098 llmsglit ("Global stderr implied by checks clause, "
1099 "not declared in initializations.");
1101 tfile = usymtab_lookupType (cstring_makeLiteralTemp ("FILE"));
1103 if (ctype_isUndefined (tfile))
1105 llmsglit ("FILE datatype implied by checks clause not defined.");
1106 tfile = ctype_unknown;
1109 usymtab_supGlobalEntry
1110 (uentry_makeVariable (cstring_makeLiteralTemp ("stderr"),
1111 tfile, fileloc_getBuiltin (), FALSE));
1114 ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stderr"));
1116 globlist = globSet_insert (globlist, sRef_copy (uentry_getSref (ue)));
1117 sl = sRefSet_insert (sl, sRef_buildPointer (uentry_getSref (ue)));
1121 if (typeId_isInvalid (tn))
1123 acct = context_fileAccessTypes ();
1125 else
1127 acct = typeIdSet_single (tn);
1130 if (usymtab_exists (s))
1132 uentry l = usymtab_lookup (s);
1133 uentry ue;
1135 if (uentry_isForward (l) || (fileloc_isLib (uentry_whereSpecified (l))))
1137 typeIdSet accessType;
1139 if (uentry_isFunction (l))
1141 accessType = typeIdSet_union (uentry_accessType (l),
1142 context_fileAccessTypes ());
1144 else
1146 accessType = context_fileAccessTypes ();
1149 if (spec)
1151 ue = uentry_makeSpecFunction (s, ct, accessType, globlist, sl, loc);
1153 else
1155 sRefSet_free (sl);
1156 globSet_free (globlist);
1158 ue = uentry_makeUnspecFunction (s, ct, accessType, loc);
1161 uentry_reflectQualifiers (ue, qtype_getQuals (qt));
1162 usymtab_supEntry (ue);
1164 else
1167 ** error reported by symtable already
1169 ** llgenerror (message ("Function redeclared: %s (previous declaration: %s)", s,
1170 ** fileloc_unparse (uentry_whereSpecified (l))),
1171 ** loc);
1174 fileloc_free (loc);
1175 sRefSet_free (sl);
1176 globSet_free (globlist);
1179 else
1181 uentry le;
1183 if (spec)
1185 if (priv)
1187 le = uentry_makePrivFunction2 (s, ct, acct, globlist, sl, loc);
1189 else
1191 le = uentry_makeSpecFunction (s, ct, acct, globlist, sl, loc);
1194 else
1196 le = uentry_makeUnspecFunction (s, ct, acct, loc);
1198 sRefSet_free (sl);
1199 globSet_free (globlist);
1202 if (context_inLCLLib () && !priv)
1204 uentry_setDefined (le, loc);
1207 uentry_reflectQualifiers (le, qtype_getQuals (qt));
1209 if (qual_isUnknown (f->special)) {
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;
1221 usymtab_supEntry (le);
1224 qtype_free (qt);
1227 extern void
1228 doDeclareFcn (fcnNode f, typeId tn, bool priv, bool spec)
1230 qtype qt = convertLclTypeSpecNode (f->typespec);
1231 ctype ct = convertTypeExpr (qtype_getType (qt), f->declarator->type);
1233 declareFcnAux (f, qt, ct, tn, priv, spec);
1237 ** is s is an argument to f, return its arg no.
1238 ** otherwise, return 0
1241 static int
1242 getParamNo (cstring s, fcnNode f)
1244 /* gasp, maybe should do run-time checks here */
1245 paramNodeList params;
1246 typeExpr fd = f->declarator->type;
1248 /* is this a bug in the LCL grammar? */
1250 while (fd != NULL && (fd->kind == TEXPR_PTR || fd->kind == TEXPR_ARRAY))
1252 if (fd->kind == TEXPR_PTR)
1254 fd = fd->content.pointer;
1256 else
1258 /*@-null@*/ fd = fd->content.array.elementtype; /*@=null@*/
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...
1268 llassert (fd != NULL);
1270 if (fd->kind != TEXPR_FCN)
1272 llfatalbug (message ("getParamNo: not a function: %q (%d)",
1273 typeExpr_unparse (fd), (int) fd->kind));
1276 params = fd->content.function.args;
1278 if (paramNodeList_empty (params))
1280 return -1;
1282 else
1284 int pno = 0;
1286 paramNodeList_elements (params, i)
1288 if (i->paramdecl != (typeExpr) 0) /* handle (void) */
1290 if (cstring_equal (s, getVarName (i->paramdecl)))
1292 return pno;
1295 pno++;
1296 } end_paramNodeList_elements;
1297 return -1;
1301 static /*@null@*/ /*@observer@*/ termNode
1302 getLetDecl (cstring s, fcnNode f)
1304 letDeclNodeList x = f->lets;
1306 letDeclNodeList_elements (x, i)
1308 if (cstring_equal (s, ltoken_getRawString (i->varid)))
1310 if (i->sortspec != NULL)
1312 llbuglit ("getLetDecl: cannot return sort!");
1314 else
1315 { /* is a termNode */
1316 return i->term;
1319 } end_letDeclNodeList_elements;
1321 return (termNode) 0;
1325 ** processTermNode --- based on printTermNode2
1328 static /*@exposed@*/ sRef
1329 processTermNode (/*@null@*/ opFormNode op, termNodeList args,
1330 fcnNode f, uentryList cl)
1332 if (op != (opFormNode) 0)
1334 switch (op->kind)
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:
1344 int size = termNodeList_size (args);
1346 if (size == 1
1347 && (cstring_equalLit (ltoken_getRawString (op->content.anyop), "'") ||
1348 cstring_equalLit (ltoken_getRawString (op->content.anyop), "^")))
1350 return (fixTermNode (termNodeList_head (args), f, cl));
1352 else
1356 break;
1358 case OPF_ANYOPM:
1360 int size = termNodeList_size (args);
1362 if (size == 1
1363 && (cstring_equalLit (ltoken_getRawString (op->content.anyop), "*")))
1365 sRef ft;
1366 sRef res;
1368 ft = fixTermNode (termNodeList_head (args), f, cl);
1369 res = sRef_buildPointer (ft);
1370 return (res);
1372 else
1376 break;
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;
1401 case OPF_BMMIDDLE:
1402 if (op->content.middle <= 1)
1404 sRef arr = fixTermNode (termNodeList_head (args), f, cl);
1405 sRef ret;
1407 if (op->content.middle == 1)
1409 termNode t = (termNodeList_reset (args),
1410 termNodeList_advance (args),
1411 termNodeList_current (args));
1413 if (t->kind == TRM_LITERAL)
1415 int i;
1417 if (sscanf
1418 (cstring_toCharsSafe
1419 (ltoken_getRawString (t->literal)),
1420 "%d", &i) == 1)
1422 ret = sRef_buildArrayFetchKnown (arr, i);
1424 else
1426 ret = sRef_buildArrayFetch (arr);
1429 return (ret);
1433 /* unknown index */
1435 ret = sRef_buildArrayFetch (arr);
1437 return (ret);
1439 else
1441 llcontbug (message ("op->content.middle = %d",
1442 op->content.middle));
1443 break;
1446 case OPF_BMIDDLEM:
1447 llcontbuglit ("OPF_BMIDDLEM not handled");
1448 break;
1450 case OPF_BMMIDDLEM:
1451 llcontbuglit ("OPF_BMMIDDLEM not handled");
1452 break;
1454 case OPF_SELECT:
1455 llcontbug (message ("select: .%s",
1456 ltoken_getRawString (op->content.id)));
1457 break;
1459 case OPF_MAP:
1460 llcontbug (message ("map: .%s",
1461 ltoken_getRawString (op->content.id)));
1462 break;
1464 case OPF_MSELECT:
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);
1471 ct = ctype_realType (ct);
1474 ** does it correspond to a typedef struct field
1476 ** (kind of kludgey, but there is no direct way to
1477 ** tell if it is an lsl operator instead)
1480 if (ctype_isStructorUnion (ct) &&
1481 uentry_isValid
1482 (uentryList_lookupField (ctype_getFields (ct), fieldname)))
1484 cstring fname = cstring_copy (fieldname);
1486 ret = sRef_buildField (rec, fname);
1487 cstring_markOwned (fname);
1489 else
1491 ret = sRef_undefined;
1494 return ret;
1496 case OPF_MMAP:
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);
1504 ** does it correspond to a typedef struct field
1507 if (ctype_isPointer (ct))
1509 ctype ctb = ctype_realType (ctype_baseArrayPtr (ct));
1511 if (ctype_isStructorUnion (ctb) &&
1512 uentry_isValid (uentryList_lookupField
1513 (ctype_getFields (ctb), fieldname)))
1515 cstring fname = cstring_copy (fieldname);
1517 ret = sRef_buildArrow (rec, fname);
1518 cstring_markOwned (fname);
1522 return ret;
1527 return sRef_undefined;
1531 ** fixModifies
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
1540 static /*@exposed@*/ sRef fixTermNode (termNode n, fcnNode f, uentryList cl)
1542 if (n != (termNode) 0)
1544 switch (n->kind)
1546 case TRM_LITERAL:
1547 break;
1548 case TRM_CONST:
1549 case TRM_VAR:
1550 case TRM_ZEROARY:
1552 cstring s = ltoken_getRawString (n->literal);
1553 termNode tl = getLetDecl (s, f);
1555 if (tl != (termNode) 0)
1557 return (fixTermNode (tl, f, cl));
1559 else
1561 int i = getParamNo (s, f);
1563 if (i < 0)
1565 usymId usym = usymtab_getId (s);
1567 if (usymId_isInvalid (usym))
1569 if (usymtab_existsEither (s))
1571 return sRef_makeSpecState ();
1573 else
1575 llcontbuglit ("Invalid symbol in modifies list");
1576 return sRef_undefined;
1579 else
1580 return (sRef_makeGlobal (usym, ctype_unknown, stateInfo_currentLoc ()));
1583 else
1585 sRef p = sRef_makeParam (i, ctype_unknown, stateInfo_currentLoc ());
1586 return (p);
1590 case TRM_APPLICATION:
1592 nameNode nn = n->name;
1594 if (nn != (nameNode) 0)
1596 if (nn->isOpId)
1598 /* must we handle n->given ? skip for now */
1600 llfatalbug
1601 (message ("fixTermNode: expect non-empty nameNode: "
1602 "TRM_APPLICATION: %q",
1603 nameNode_unparse (nn)));
1605 else
1607 sRef sr;
1609 sr = processTermNode (nn->content.opform, n->args, f, cl);
1610 return (sr);
1614 return sRef_undefined;
1616 case TRM_UNCHANGEDALL:
1617 case TRM_UNCHANGEDOTHERS:
1618 case TRM_SIZEOF:
1619 case TRM_QUANTIFIER:
1620 return sRef_undefined;
1624 return sRef_undefined;
1627 static
1628 /*@only@*/ sRefSet fixModifies (fcnNode f, uentryList cl)
1630 static bool shownWarning = FALSE;
1631 modifyNode m = f->modify;
1632 sRefSet sl = sRefSet_new ();
1634 if (m != (modifyNode) 0)
1636 if (m->hasStoreRefList)
1638 storeRefNodeList srefs = m->list;
1640 storeRefNodeList_elements (srefs, i)
1642 if (storeRefNode_isObj (i) || storeRefNode_isType (i))
1644 if (!shownWarning)
1646 fileloc loc = fileloc_fromTok (f->name);
1648 llmsg (message
1649 ("%q: Warning: object and type modifications "
1650 "not understood by Splint",
1651 fileloc_unparse (loc)));
1652 fileloc_free (loc);
1653 shownWarning = TRUE;
1656 else if (storeRefNode_isSpecial (i))
1658 sl = sRefSet_insert (sl, i->content.ref);
1660 else if (storeRefNode_isTerm (i))
1662 sRef s = fixTermNode (i->content.term, f, cl);
1664 if (sRef_isKnown (s))
1666 sl = sRefSet_insert (sl, s);
1669 else
1671 BADEXIT;
1673 } end_storeRefNodeList_elements;
1678 return sl;
1681 static /*@only@*/ cstring
1682 paramNode_name (paramNode x)
1684 return (typeExpr_name (x->paramdecl));
1687 static /*@only@*/ uentry
1688 paramNode_toUentry (paramNode p)
1690 if (p != (paramNode) 0)
1692 if (p->kind == PELIPSIS)
1694 return uentry_makeElipsisMarker ();
1696 else
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);
1702 uentry ue = uentry_makeVariableParam (pname, cr, g_currentloc);
1704 uentry_reflectQualifiers (ue, qtype_getQuals (ct));
1705 qtype_free (ct);
1706 return (ue);
1709 else
1711 llcontbuglit ("paramNode_toUentry: NULL");
1712 return uentry_undefined;
1714 BADEXIT;
1717 static uentryList
1718 paramNodeList_toUentryList (paramNodeList p)
1720 uentryList cl = uentryList_new ();
1722 if (paramNodeList_isNull (p)) return (cl);
1724 paramNodeList_elements (p, current)
1726 cl = uentryList_add (cl, paramNode_toUentry (current));
1727 } end_paramNodeList_elements;
1729 return cl;