]> andersk Git - splint.git/blame - src/usymtab_interface.c
Fixed bug #697722 Assert error / global
[splint.git] / src / usymtab_interface.c
CommitLineData
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"
616915dd 35# include "llbasic.h"
36# include "gram.h"
37# include "lclscan.h"
38# include "lclsyntable.h"
39# include "lslparse.h"
40# include "usymtab_interface.h"
41# include "structNames.h"
42
43static void
44 declareFcnAux (fcnNode p_f, /*@only@*/ qtype p_qt, ctype p_ct, typeId p_tn,
45 bool p_priv, bool p_spec);
46
47static uentryList paramNodeList_toUentryList (paramNodeList p_p);
48static /*@observer@*/ cstring getVarName (/*@null@*/ typeExpr p_x);
49static qtype convertLclTypeSpecNode (/*@null@*/ lclTypeSpecNode p_n);
50static ctype convertTypeExpr (ctype p_c, /*@null@*/ typeExpr p_x);
51static ctype convertCTypeExpr (ctype p_c, /*@null@*/ typeExpr p_x);
52static /*@exposed@*/ sRef fixTermNode (termNode p_n, fcnNode p_f, uentryList p_cl);
53static sRefSet fixModifies (fcnNode p_f, uentryList p_cl);
54
55static 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
83static 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
153static ctype
154convertTypeExpr (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
193static
194ctype 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
237static 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
327static 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
344static /*@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
572static /*@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
619void
620doDeclareConstant (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
680static cstring
681getVarName (/*@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
709void
710doDeclareVar (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
789static globSet
790processGlob (/*@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
860static void
861declareAbstractType (abstractNode n, bool priv)
862{
863 cstring tn;
864 fileloc loc;
865 uentry ue;
866 usymId uid;
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
952static void
953 declareExposedType (exposedNode n, bool priv)
954{
955 usymId uid;
956 qtype c;
957 cstring s;
958
959
960 if (n == (exposedNode) 0)
961 {
962 return;
963 }
964
965 c = convertLclTypeSpecNode (n->type);
966
967 declaratorInvNodeList_elements (n->decls, i)
968 {
969 ctype realType = convertTypeExpr (qtype_getType (c), i->declarator->type);
970 fileloc loc = fileloc_fromTok (i->declarator->id);
971 uentry ue;
972
973 s = getVarName (i->declarator->type);
974
e5081f8c 975 ue = uentry_makeDatatypeAux (s, realType, MAYBE, qual_createConcrete (),
976 loc, priv);
616915dd 977
978 uentry_reflectQualifiers (ue, qtype_getQuals (c));
979
980 if (context_inLCLLib () && !priv)
981 {
982 uentry_setDefined (ue, loc);
983 }
984
985 uid = usymtab_supExposedTypeEntry (ue, context_inLCLLib () && !priv);
986 } end_declaratorInvNodeList_elements;
987
988 qtype_free (c);
989}
990
991/*
992** ah...remember ye old days...
993**
994** wow...same thing in THREE symbol tables! talk about space efficiency
995** (or as Joe Theory once said, its only a constant factor)
996*/
997
998void
999doDeclareType (typeNode t, bool priv)
1000{
1001
1002 if (t != (typeNode) 0)
1003 {
1004 switch (t->kind)
1005 {
1006 case TK_ABSTRACT:
1007 declareAbstractType (t->content.abstract, priv);
1008 break;
1009
1010 case TK_EXPOSED:
1011 declareExposedType (t->content.exposed, priv);
1012 break;
1013
1014 case TK_UNION:
1015 default:
1016 {
1017 llfatalbug (message ("declareType ERROR: unknown kind: %q",
1018 cstring_fromCharsO (FormatInt ((int)t->kind))));
1019 }
1020 }
1021 }
1022
1023}
1024
1025extern void
1026declareIter (iterNode iter)
1027{
1028 fileloc loc = fileloc_fromTok (iter->name);
1029 uentry ue =
1030 uentry_makeIter (ltoken_unparse (iter->name),
1031 ctype_makeFunction
1032 (ctype_void,
1033 paramNodeList_toUentryList (iter->params)),
1034 fileloc_copy (loc));
1035
1036 usymtab_supEntry (ue);
1037 usymtab_supEntry
1038 (uentry_makeEndIter (ltoken_unparse (iter->name), loc));
1039}
1040
1041/*
1042** declareFcn
1043*/
1044
1045static void
1046declareFcnAux (fcnNode f, /*@only@*/ qtype qt, ctype ct,
1047 typeId tn, bool priv, bool spec)
1048{
1049 globalList globals;
1050 typeIdSet acct;
1051 sRefSet sl = sRefSet_undefined;
1052 globSet globlist = globSet_undefined;
1053 cstring s = getVarName (f->declarator->type);
1054 fileloc loc = fileloc_fromTok (f->declarator->id);
1055 uentryList args;
1056
1057 /*
1058 ** type conversion generates args
1059 */
1060
1061 if (ctype_isFunction (ct))
1062 {
1063 args = ctype_argsFunction (ct);
1064 }
1065 else
1066 {
1067 llcontbug (message ("Not function: %s", ctype_unparse (ct)));
1068 args = uentryList_undefined;
1069 }
1070
1071
1072 fileloc_setColumnUndefined (loc);
1073
1074 if (spec)
1075 {
1076 globals = f->globals;
1077
28bf4b0b 1078 sl = fixModifies (f, args);
616915dd 1079
1080 /*
1081 ** Bind let declarations in modifies list
1082 */
1083
1084 varDeclarationNodeList_elements (globals, glob)
1085 {
1086 globlist = processGlob (globlist, glob);
1087 } end_varDeclarationNodeList_elements;
1088
1089
1090 if (f->checks != (lclPredicateNode) 0)
1091 /* push stderr on globalList */
1092 /* modifies *stderr^ */
1093 {
1094 uentry ue;
1095
1096 if (!(usymtab_existsVar (cstring_makeLiteralTemp ("stderr"))))
1097 {
1098 ctype tfile;
1099
1100 llmsglit ("Global stderr implied by checks clause, "
1101 "not declared in initializations.");
1102
1103 tfile = usymtab_lookupType (cstring_makeLiteralTemp ("FILE"));
1104
1105 if (ctype_isUndefined (tfile))
1106 {
1107 llmsglit ("FILE datatype implied by checks clause not defined.");
1108 tfile = ctype_unknown;
1109 }
1110
1111 usymtab_supGlobalEntry
1112 (uentry_makeVariable (cstring_makeLiteralTemp ("stderr"),
1113 tfile, fileloc_getBuiltin (), FALSE));
1114 }
1115
1116 ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stderr"));
1117
28bf4b0b 1118 globlist = globSet_insert (globlist, sRef_copy (uentry_getSref (ue)));
616915dd 1119 sl = sRefSet_insert (sl, sRef_buildPointer (uentry_getSref (ue)));
616915dd 1120 }
1121 }
1122
1123 if (usymId_isInvalid (tn))
1124 {
1125 acct = context_fileAccessTypes ();
1126 }
1127 else
1128 {
1129 acct = typeIdSet_single (tn);
1130 }
28bf4b0b 1131
616915dd 1132 if (usymtab_exists (s))
1133 {
1134 uentry l = usymtab_lookup (s);
1135 uentry ue;
1136
1137 if (uentry_isForward (l) || (fileloc_isLib (uentry_whereSpecified (l))))
1138 {
1139 typeIdSet accessType;
1140
1141 if (uentry_isFunction (l))
1142 {
1143 accessType = typeIdSet_union (uentry_accessType (l),
1144 context_fileAccessTypes ());
1145 }
1146 else
1147 {
1148 accessType = context_fileAccessTypes ();
1149 }
1150
1151 if (spec)
1152 {
1153 ue = uentry_makeSpecFunction (s, ct, accessType, globlist, sl, loc);
1154 }
1155 else
1156 {
1157 sRefSet_free (sl);
1158 globSet_free (globlist);
1159
1160 ue = uentry_makeUnspecFunction (s, ct, accessType, loc);
1161 }
1162
1163 uentry_reflectQualifiers (ue, qtype_getQuals (qt));
616915dd 1164 usymtab_supEntry (ue);
1165 }
1166 else
1167 {
1168 /*
1169 ** error reported by symtable already
1170 **
1171 ** llgenerror (message ("Function redeclared: %s (previous declaration: %s)", s,
1172 ** fileloc_unparse (uentry_whereSpecified (l))),
1173 ** loc);
1174 */
1175
616915dd 1176 fileloc_free (loc);
1177 sRefSet_free (sl);
1178 globSet_free (globlist);
1179 }
1180 }
1181 else
1182 {
1183 uentry le;
1184
1185 if (spec)
1186 {
1187 if (priv)
1188 {
1189 le = uentry_makePrivFunction2 (s, ct, acct, globlist, sl, loc);
1190 }
1191 else
1192 {
1193 le = uentry_makeSpecFunction (s, ct, acct, globlist, sl, loc);
1194 }
1195 }
1196 else
1197 {
1198 le = uentry_makeUnspecFunction (s, ct, acct, loc);
1199
1200 sRefSet_free (sl);
1201 globSet_free (globlist);
1202 }
1203
1204 if (context_inLCLLib () && !priv)
1205 {
1206 uentry_setDefined (le, loc);
1207 }
1208
1209 uentry_reflectQualifiers (le, qtype_getQuals (qt));
1210
28bf4b0b 1211 if (qual_isUnknown (f->special)) {
1212 ;
1213 } else if (qual_isPrintfLike (f->special)) {
1214 uentry_setPrintfLike (le);
1215 } else if (qual_isScanfLike (f->special)) {
1216 uentry_setScanfLike (le);
1217 } else if (qual_isMessageLike (f->special)) {
1218 uentry_setMessageLike (le);
1219 } else {
1220 BADBRANCH;
1221 }
616915dd 1222
1223 usymtab_supEntry (le);
1224 }
1225
1226 qtype_free (qt);
1227}
1228
1229extern void
1230doDeclareFcn (fcnNode f, typeId tn, bool priv, bool spec)
1231{
1232 qtype qt = convertLclTypeSpecNode (f->typespec);
1233 ctype ct = convertTypeExpr (qtype_getType (qt), f->declarator->type);
1234
28bf4b0b 1235 declareFcnAux (f, qt, ct, tn, priv, spec);
616915dd 1236}
1237
1238/*
1239** is s is an argument to f, return its arg no.
1240** otherwise, return 0
1241*/
1242
1243static int
1244getParamNo (cstring s, fcnNode f)
1245{
1246 /* gasp, maybe should do run-time checks here */
1247 paramNodeList params;
1248 typeExpr fd = f->declarator->type;
1249
1250 /* is this a bug in the LCL grammar? */
1251
1252 while (fd != NULL && (fd->kind == TEXPR_PTR || fd->kind == TEXPR_ARRAY))
1253 {
1254 if (fd->kind == TEXPR_PTR)
1255 {
1256 fd = fd->content.pointer;
1257 }
1258 else
1259 {
1260 /*@-null@*/ fd = fd->content.array.elementtype; /*@=null@*/
1261
1262 /*
1263 ** This is a bug in checking, that I should eventually fix.
1264 ** Need some way of deleting the guard from the true branch,
1265 ** but adding it back in the false branch...
1266 */
1267 }
1268 }
1269
1270 llassert (fd != NULL);
1271
1272 if (fd->kind != TEXPR_FCN)
1273 {
1274 llfatalbug (message ("getParamNo: not a function: %q (%d)",
1275 typeExpr_unparse (fd), (int) fd->kind));
1276 }
1277
1278 params = fd->content.function.args;
1279
1280 if (paramNodeList_empty (params))
1281 {
1282 return -1;
1283 }
1284 else
1285 {
1286 int pno = 0;
1287
1288 paramNodeList_elements (params, i)
1289 {
1290 if (i->paramdecl != (typeExpr) 0) /* handle (void) */
1291 {
1292 if (cstring_equal (s, getVarName (i->paramdecl)))
1293 {
1294 return pno;
1295 }
1296 }
1297 pno++;
1298 } end_paramNodeList_elements;
1299 return -1;
1300 }
1301}
1302
1303static /*@null@*/ /*@observer@*/ termNode
1304getLetDecl (cstring s, fcnNode f)
1305{
1306 letDeclNodeList x = f->lets;
1307
1308 letDeclNodeList_elements (x, i)
1309 {
1310 if (cstring_equal (s, ltoken_getRawString (i->varid)))
1311 {
1312 if (i->sortspec != NULL)
1313 {
1314 llbuglit ("getLetDecl: cannot return sort!");
1315 }
1316 else
1317 { /* is a termNode */
1318 return i->term;
1319 }
1320 }
1321 } end_letDeclNodeList_elements;
1322
1323 return (termNode) 0;
1324}
1325
1326/*
1327** processTermNode --- based on printTermNode2
1328*/
1329
1330static /*@exposed@*/ sRef
1331 processTermNode (/*@null@*/ opFormNode op, termNodeList args,
1332 fcnNode f, uentryList cl)
1333{
1334 if (op != (opFormNode) 0)
1335 {
1336 switch (op->kind)
1337 {
1338 case OPF_IF:
1339 llcontbuglit ("processTermNode: OPF_IF: not handled");
1340 break;
1341 case OPF_ANYOP:
1342 llcontbuglit ("processTermNode: OPF_ANYOP: not handled");
1343 break;
1344 case OPF_MANYOP:
1345 {
1346 int size = termNodeList_size (args);
1347
1348 if (size == 1
1349 && (cstring_equalLit (ltoken_getRawString (op->content.anyop), "'") ||
1350 cstring_equalLit (ltoken_getRawString (op->content.anyop), "^")))
1351 {
1352 return (fixTermNode (termNodeList_head (args), f, cl));
1353 }
1354 else
1355 {
1356 ;
1357 }
1358 break;
1359 }
1360 case OPF_ANYOPM:
1361 {
1362 int size = termNodeList_size (args);
1363
1364 if (size == 1
1365 && (cstring_equalLit (ltoken_getRawString (op->content.anyop), "*")))
1366 {
1367 sRef ft;
1368 sRef res;
1369
1370 ft = fixTermNode (termNodeList_head (args), f, cl);
1371 res = sRef_buildPointer (ft);
1372 return (res);
1373 }
1374 else
1375 {
1376 ;
1377 }
1378 break;
1379 }
1380 case OPF_MANYOPM:
1381 llcontbuglit ("OPF_MANYOPM: not handled\n");
1382 break;
1383 case OPF_MIDDLE:
1384 llcontbuglit ("OPF_MIDDLE: not handled\n");
1385 break;
1386 case OPF_MMIDDLE:
1387 llcontbuglit ("OPF_MMIDDLE: not handled\n");
1388 break;
1389 case OPF_MIDDLEM:
1390 llcontbuglit ("OPF_MIDDLEM: not handled\n");
1391 break;
1392 case OPF_MMIDDLEM:
1393 llcontbuglit ("OPF_MMIDDLEM: not handled\n");
1394 break;
1395 case OPF_BMIDDLE:
1396 if (op->content.middle == 1)
1397 llbug (message ("array fetch: [%q]",
1398 termNodeList_unparse (args)));
1399 else
1400 llcontbuglit ("OPF_BMIDDLE: bad\n");
1401 break;
1402
1403 case OPF_BMMIDDLE:
1404 if (op->content.middle <= 1)
1405 {
1406 sRef arr = fixTermNode (termNodeList_head (args), f, cl);
1407 sRef ret;
1408
1409 if (op->content.middle == 1)
1410 {
1411 termNode t = (termNodeList_reset (args),
1412 termNodeList_advance (args),
1413 termNodeList_current (args));
1414
1415 if (t->kind == TRM_LITERAL)
1416 {
1417 int i;
1418
1419 if (sscanf
1420 (cstring_toCharsSafe
1421 (ltoken_getRawString (t->literal)),
1422 "%d", &i) == 1)
1423 {
1424 ret = sRef_buildArrayFetchKnown (arr, i);
1425 }
1426 else
1427 {
1428 ret = sRef_buildArrayFetch (arr);
1429 }
1430
1431 return (ret);
1432 }
1433 }
1434
1435 /* unknown index */
1436
1437 ret = sRef_buildArrayFetch (arr);
1438
1439 return (ret);
1440 }
1441 else
1442 {
1443 llcontbug (message ("op->content.middle = %d",
1444 op->content.middle));
1445 break;
1446 }
1447
1448 case OPF_BMIDDLEM:
1449 llcontbuglit ("OPF_BMIDDLEM not handled");
1450 break;
1451
1452 case OPF_BMMIDDLEM:
1453 llcontbuglit ("OPF_BMMIDDLEM not handled");
1454 break;
1455
1456 case OPF_SELECT:
1457 llcontbug (message ("select: .%s",
1458 ltoken_getRawString (op->content.id)));
1459 break;
1460
1461 case OPF_MAP:
1462 llcontbug (message ("map: .%s",
1463 ltoken_getRawString (op->content.id)));
1464 break;
1465
1466 case OPF_MSELECT:
1467 {
1468 sRef rec = fixTermNode (termNodeList_head (args), f, cl);
1469 sRef ret;
1470 ctype ct = ctype_realType (sRef_deriveType (rec, cl));
1471 cstring fieldname = ltoken_getRawString (op->content.id);
1472
1473 ct = ctype_realType (ct);
1474
1475 /*
1476 ** does it correspond to a typedef struct field
1477 **
1478 ** (kind of kludgey, but there is no direct way to
1479 ** tell if it is an lsl operator instead)
1480 */
1481
1482 if (ctype_isStructorUnion (ct) &&
1483 uentry_isValid
1484 (uentryList_lookupField (ctype_getFields (ct), fieldname)))
1485 {
1486 cstring fname = cstring_copy (fieldname);
1487
1488 ret = sRef_buildField (rec, fname);
1489 cstring_markOwned (fname);
1490 }
1491 else
1492 {
1493 ret = sRef_undefined;
1494 }
1495
1496 return ret;
1497 }
1498 case OPF_MMAP:
1499 {
1500 sRef rec = fixTermNode (termNodeList_head (args), f, cl);
1501 sRef ret = sRef_undefined;
1502 ctype ct = ctype_realType (sRef_deriveType (rec, cl));
1503 cstring fieldname = ltoken_getRawString (op->content.id);
1504
1505 /*
1506 ** does it correspond to a typedef struct field
1507 */
1508
1509 if (ctype_isPointer (ct))
1510 {
1511 ctype ctb = ctype_realType (ctype_baseArrayPtr (ct));
1512
1513 if (ctype_isStructorUnion (ctb) &&
1514 uentry_isValid (uentryList_lookupField
1515 (ctype_getFields (ctb), fieldname)))
1516 {
1517 cstring fname = cstring_copy (fieldname);
1518
1519 ret = sRef_buildArrow (rec, fname);
1520 cstring_markOwned (fname);
1521 }
1522 }
1523
1524 return ret;
1525 }
1526 }
1527 }
1528
1529 return sRef_undefined;
1530}
1531
1532/*
1533** fixModifies
1534**
1535** o replace anything in modifies that is bound with let with value
1536** o replace spec variables with internal state
1537** o replace paramaters with paramno identifiers
1538** o replace globals with their usymid's
1539** o make everything sRefs
1540*/
1541
1542static /*@exposed@*/ sRef fixTermNode (termNode n, fcnNode f, uentryList cl)
1543{
1544 if (n != (termNode) 0)
1545 {
1546 switch (n->kind)
1547 {
1548 case TRM_LITERAL:
1549 break;
1550 case TRM_CONST:
1551 case TRM_VAR:
1552 case TRM_ZEROARY:
1553 {
1554 cstring s = ltoken_getRawString (n->literal);
1555 termNode tl = getLetDecl (s, f);
1556
1557 if (tl != (termNode) 0)
1558 {
1559 return (fixTermNode (tl, f, cl));
1560 }
1561 else
1562 {
1563 int i = getParamNo (s, f);
1564
1565 if (i < 0)
1566 {
1567 usymId usym = usymtab_getId (s);
1568
1569 if (usymId_isInvalid (usym))
1570 {
1571 if (usymtab_existsEither (s))
1572 {
1573 return sRef_makeSpecState ();
1574 }
1575 else
1576 {
1577 llcontbuglit ("Invalid symbol in modifies list");
1578 return sRef_undefined;
1579 }
1580 }
1581 else
6970c11b 1582 return (sRef_makeGlobal (usym, ctype_unknown, stateInfo_currentLoc ()));
616915dd 1583 }
1584
1585 else
1586 {
6970c11b 1587 sRef p = sRef_makeParam (i, ctype_unknown, stateInfo_currentLoc ());
1588 return (p);
616915dd 1589 }
1590 }
1591 }
1592 case TRM_APPLICATION:
1593 {
1594 nameNode nn = n->name;
1595
1596 if (nn != (nameNode) 0)
1597 {
1598 if (nn->isOpId)
1599 {
1600 /* must we handle n->given ? skip for now */
1601
1602 llfatalbug
1603 (message ("fixTermNode: expect non-empty nameNode: "
1604 "TRM_APPLICATION: %q",
1605 nameNode_unparse (nn)));
1606 }
1607 else
1608 {
1609 sRef sr;
1610
1611 sr = processTermNode (nn->content.opform, n->args, f, cl);
1612 return (sr);
1613 }
1614 }
1615
1616 return sRef_undefined;
1617 }
1618 case TRM_UNCHANGEDALL:
1619 case TRM_UNCHANGEDOTHERS:
1620 case TRM_SIZEOF:
1621 case TRM_QUANTIFIER:
1622 return sRef_undefined;
1623 }
1624 }
1625
1626 return sRef_undefined;
1627}
1628
1629static
1630/*@only@*/ sRefSet fixModifies (fcnNode f, uentryList cl)
1631{
1632 static bool shownWarning = FALSE;
1633 modifyNode m = f->modify;
1634 sRefSet sl = sRefSet_new ();
1635
1636 if (m != (modifyNode) 0)
1637 {
1638 if (m->hasStoreRefList)
1639 {
1640 storeRefNodeList srefs = m->list;
1641
1642 storeRefNodeList_elements (srefs, i)
1643 {
1644 if (storeRefNode_isObj (i) || storeRefNode_isType (i))
1645 {
1646 if (!shownWarning)
1647 {
1648 fileloc loc = fileloc_fromTok (f->name);
1649
1650 llmsg (message
1651 ("%q: Warning: object and type modifications "
11db3170 1652 "not understood by Splint",
616915dd 1653 fileloc_unparse (loc)));
1654 fileloc_free (loc);
1655 shownWarning = TRUE;
1656 }
1657 }
1658 else if (storeRefNode_isSpecial (i))
1659 {
1660 sl = sRefSet_insert (sl, i->content.ref);
1661 }
1662 else if (storeRefNode_isTerm (i))
1663 {
1664 sRef s = fixTermNode (i->content.term, f, cl);
1665
1666 if (sRef_isKnown (s))
1667 {
1668 sl = sRefSet_insert (sl, s);
1669 }
1670 }
1671 else
1672 {
1673 BADEXIT;
1674 }
1675 } end_storeRefNodeList_elements;
1676
1677 }
1678 }
1679
1680 return sl;
1681}
1682
1683static /*@only@*/ cstring
1684paramNode_name (paramNode x)
1685{
1686 return (typeExpr_name (x->paramdecl));
1687}
1688
1689static /*@only@*/ uentry
1690paramNode_toUentry (paramNode p)
1691{
1692 if (p != (paramNode) 0)
1693 {
1694 if (p->kind == PELIPSIS)
1695 {
1696 return uentry_makeElipsisMarker ();
1697 }
1698 else
1699 {
1700 qtype ct = convertLclTypeSpecNode (p->type);
1701 ctype cr = convertTypeExpr (qtype_getType (ct), p->paramdecl);
1702 cstring pname = (p->paramdecl == (typeExpr)0) ? cstring_undefined
1703 : paramNode_name (p);
6970c11b 1704 uentry ue = uentry_makeVariableParam (pname, cr, g_currentloc);
616915dd 1705
1706 uentry_reflectQualifiers (ue, qtype_getQuals (ct));
1707 qtype_free (ct);
1708 return (ue);
1709 }
1710 }
1711 else
1712 {
1713 llcontbuglit ("paramNode_toUentry: NULL");
1714 return uentry_undefined;
1715 }
1716 BADEXIT;
1717}
1718
1719static uentryList
1720 paramNodeList_toUentryList (paramNodeList p)
1721{
1722 uentryList cl = uentryList_new ();
1723
1724 if (paramNodeList_isNull (p)) return (cl);
1725
1726 paramNodeList_elements (p, current)
1727 {
1728 cl = uentryList_add (cl, paramNode_toUentry (current));
1729 } end_paramNodeList_elements;
1730
1731 return cl;
1732}
1733
1734
This page took 0.349518 seconds and 5 git commands to generate.