2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
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.
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.
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 ** cscannerHelp.c - procedures for scanning C
27 ** Most of this code was in cscanner.l, but moved here to separate it
28 ** from the flex-generated code.
31 # include "splintMacros.nf"
33 # include "cscannerHelp.h"
34 # include "cscanner.h"
35 # include "cgrammar.h"
38 static int lminput (void);
39 static int s_tokLength
= 0;
41 static /*@owned@*/ cstring s_lastidprocessed
= cstring_undefined
;
42 static bool s_inSpecPart
= FALSE
;
43 static int s_whichSpecPart
;
44 static char s_savechar
= '\0';
45 static bool s_expectingMetaStateName
= FALSE
;
46 static bool s_lastWasString
= FALSE
;
47 static bool s_expectingTypeName
= TRUE
;
51 /*@null@*/ /*@observer@*/ char *name
;
56 ** These tokens are followed by syntax that is parsed by the
60 static struct skeyword s_parsetable
[] = {
61 { "modifies", QMODIFIES
} ,
62 { "globals", QGLOBALS
} ,
65 { "constant", QCONSTANT
} ,
66 { "function", QFUNCTION
} ,
68 { "defines", QDEFINES
} ,
70 { "allocates", QALLOCATES
} ,
72 { "releases", QRELEASES
} ,
73 { "pre", QPRECLAUSE
} ,
74 { "post", QPOSTCLAUSE
} ,
75 { "setBufferSize", QSETBUFFERSIZE
},
76 { "setStringLength", QSETSTRINGLENGTH
},
77 { "testinRange", QTESTINRANGE
},
78 { "requires", QPRECLAUSE
} ,
79 { "ensures", QPOSTCLAUSE
} ,
80 { "invariant", QINVARIANT
} ,
85 ** These tokens are either stand-alone tokens, or followed by
86 ** token-specific text.
89 static struct skeyword s_keytable
[] = {
90 { "anytype", QANYTYPE
} ,
91 { "integraltype", QINTEGRALTYPE
} ,
92 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE
} ,
93 { "signedintegraltype", QSIGNEDINTEGRALTYPE
} ,
98 { "dependent", QDEPENDENT
} ,
99 { "partial", QPARTIAL
} ,
100 { "special", QSPECIAL
} ,
101 { "truenull", QTRUENULL
} ,
102 { "falsenull", QFALSENULL
} ,
103 { "nullwhentrue", QTRUENULL
} ,
104 { "falsewhennull", QFALSENULL
} ,
107 { "notnull", QNOTNULL
} ,
108 { "abstract", QABSTRACT
} ,
109 { "numabstract", QNUMABSTRACT
} ,
110 { "concrete", QCONCRETE
} ,
111 { "mutable", QMUTABLE
} ,
112 { "immutable", QIMMUTABLE
} ,
113 { "unused", QUNUSED
} ,
114 { "external", QEXTERNAL
} ,
116 { "unique", QUNIQUE
} ,
117 { "returned", QRETURNED
} ,
118 { "exposed", QEXPOSED
} ,
119 { "refcounted", QREFCOUNTED
} ,
121 { "newref", QNEWREF
} ,
122 { "tempref", QTEMPREF
} ,
123 { "killref", QKILLREF
} ,
125 { "relnull", QRELNULL
} ,
126 { "nullterminated", QNULLTERMINATED
},
127 { "setBufferSize", QSETBUFFERSIZE
},
128 { "testInRange", QTESTINRANGE
},
129 { "isnull", QISNULL
},
130 { "MaxSet", QMAXSET
},
131 { "MaxRead", QMAXREAD
},
132 { "maxSet", QMAXSET
},
133 { "maxRead", QMAXREAD
},
134 { "reldef", QRELDEF
} ,
135 { "observer", QOBSERVER
} ,
136 { "exits", QEXITS
} ,
137 { "noreturn", QEXITS
} ,
138 { "mayexit", QMAYEXIT
} ,
139 { "maynotreturn", QMAYEXIT
} ,
140 { "trueexit", QTRUEEXIT
} ,
141 { "falseexit", QFALSEEXIT
} ,
142 { "noreturnwhentrue", QTRUEEXIT
} ,
143 { "noreturnwhenfalse", QFALSEEXIT
} ,
144 { "neverexit", QNEVEREXIT
} ,
145 { "alwaysreturns", QNEVEREXIT
} ,
147 { "shared", QSHARED
} ,
149 { "unchecked", QUNCHECKED
} ,
150 { "checked", QCHECKED
} ,
151 { "checkmod", QCHECKMOD
} ,
152 { "checkedstrict", QCHECKEDSTRICT
} ,
153 { "innercontinue", QINNERCONTINUE
} ,
154 { "innerbreak", QINNERBREAK
} ,
155 { "loopbreak", QLOOPBREAK
} ,
156 { "switchbreak", QSWITCHBREAK
} ,
157 { "safebreak", QSAFEBREAK
} ,
158 { "fallthrough", QFALLTHROUGH
} ,
159 { "l_fallthrou", QLINTFALLTHROUGH
} ,
160 { "l_fallth", QLINTFALLTHRU
} ,
161 { "notreached", QNOTREACHED
} ,
162 { "l_notreach", QLINTNOTREACHED
} ,
163 { "printflike", QPRINTFLIKE
} ,
164 { "l_printfli", QLINTPRINTFLIKE
} ,
165 { "scanflike", QSCANFLIKE
} ,
166 { "messagelike", QMESSAGELIKE
} ,
167 { "l_argsus", QARGSUSED
} ,
172 ** would be better if these weren't hard coded...
175 static bool isArtificial (cstring s
)
177 return (cstring_equalLit (s
, "modifies")
178 || cstring_equalLit (s
, "globals")
179 || cstring_equalLit (s
, "warn")
180 || cstring_equalLit (s
, "alt"));
183 void cscannerHelp_swallowMacro (void)
186 bool skipnext
= FALSE
;
188 while ((i
= lminput ()) != EOF
)
204 reader_checkUngetc (i
, yyin
);
216 reader_checkUngetc (i
, yyin
);
220 static int commentMarkerToken (cstring s
)
224 while (s_parsetable
[i
].name
!= NULL
)
226 DPRINTF (("Try :%s:%s:", s
, s_parsetable
[i
].name
));
228 if (cstring_equalLit (s
, s_parsetable
[i
].name
))
230 return s_parsetable
[i
].token
;
239 static int tokenMacroCode (cstring s
)
243 while (s_keytable
[i
].name
!= NULL
)
245 if (cstring_equalLit (s
, s_keytable
[i
].name
))
247 if (s_keytable
[i
].token
== QLINTFALLTHROUGH
)
250 (FLG_WARNLINTCOMMENTS
,
252 ("Traditional lint comment /*FALLTHROUGH*/ used. "
253 "Splint interprets this in the same way as most Unix lints, but it is "
254 "preferable to replace it with the /*@fallthrough@*/ "
259 else if (s_keytable
[i
].token
== QLINTFALLTHRU
)
262 (FLG_WARNLINTCOMMENTS
,
264 ("Traditional lint comment /*FALLTHRU*/ used. "
265 "Splint interprets this in the same way as most Unix lints, but it is "
266 "preferable to replace it with the /*@fallthrough@*/ "
271 else if (s_keytable
[i
].token
== QLINTNOTREACHED
)
274 (FLG_WARNLINTCOMMENTS
,
276 ("Traditional lint comment /*NOTREACHED*/ used. "
277 "Splint interprets this in the same way as most Unix lints, but it is "
278 "preferable to replace it with the /*@notreached@*/ "
279 "semantic comment."),
284 else if (s_keytable
[i
].token
== QPRINTFLIKE
)
286 setSpecialFunction (qual_createPrintfLike ());
289 else if (s_keytable
[i
].token
== QLINTPRINTFLIKE
)
292 (FLG_WARNLINTCOMMENTS
,
294 ("Traditional lint comment /*PRINTFLIKE*/ used. "
295 "Splint interprets this in the same way as most Unix lints, but it is "
296 "preferable to replace it with either /*@printflike@*/, "
297 "/*@scanflike@*/ or /*@messagelike@*/."),
300 setSpecialFunction (qual_createPrintfLike ());
303 else if (s_keytable
[i
].token
== QSCANFLIKE
)
305 setSpecialFunction (qual_createScanfLike ());
308 else if (s_keytable
[i
].token
== QMESSAGELIKE
)
310 setSpecialFunction (qual_createMessageLike ());
313 else if (s_keytable
[i
].token
== QARGSUSED
)
316 (FLG_WARNLINTCOMMENTS
,
318 ("Traditional lint comment /*ARGSUSED*/ used. "
319 "Splint interprets this in the same way as most Unix lints, but it is "
320 "preferable to use /*@unused@*/ annotations on "
321 "the unused parameters."),
329 return s_keytable
[i
].token
;
339 static int lminput ()
341 if (s_savechar
== '\0')
344 return (cscanner_input ());
348 int save
= (int) s_savechar
;
354 static void lmsavechar (char c
)
356 if (s_savechar
== '\0')
362 llbuglit ("lmsavechar: override");
366 int cscannerHelp_ninput ()
370 if (c
!= EOF
&& ((char)c
== '\n'))
372 context_incLineno ();
378 static char macro_nextChar (void)
380 static bool in_quote
= FALSE
, in_escape
= FALSE
, in_char
= FALSE
;
385 c
= char_fromInt (ic
);
387 if (!in_quote
&& !in_char
&& (c
== '\\' || c
== BEFORE_COMMENT_MARKER
[0]))
391 while ((c
= char_fromInt (lminput ())) != '\0' && c
!= '\n')
393 ; /* skip to newline */
396 context_incLineno ();
400 return macro_nextChar ();
407 else /* if (c == '@') */
411 if (cscannerHelp_handleLlSpecial () != BADTOK
)
413 llerrorlit (FLG_SYNTAX
, "Macro cannot use special syntax");
416 return macro_nextChar ();
419 else if (!in_escape
&& c
== '\"')
421 in_quote
= !in_quote
;
423 else if (!in_escape
&& c
== '\'')
427 else if ((in_quote
|| in_char
) && c
== '\\')
429 in_escape
= !in_escape
;
431 else if ((in_quote
|| in_char
) && in_escape
)
435 else if (!in_quote
&& c
== '/')
439 if ((c2
= char_fromInt (lminput ())) == '*')
443 while ((c2
= char_fromInt (lminput ())) != '\0'
444 && c2
!= '\n' && c2
!= '*')
451 while ((c2
= char_fromInt (lminput ())) != '\0'
464 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
468 return macro_nextChar ();
472 /*** putchar does not work! why? puts to stdio...??! ***/
485 ** keeps semantic comments
488 static char macro_nextCharC (void)
490 static bool in_quote
= FALSE
, in_escape
= FALSE
, in_char
= FALSE
;
493 c
= char_fromInt (lminput ());
495 if (!in_quote
&& !in_char
&& c
== '\\')
497 while ((c
= char_fromInt (lminput ())) != '\0' && c
!= '\n')
499 ; /* skip to newline */
502 context_incLineno ();
506 return macro_nextCharC ();
513 else if (!in_escape
&& c
== '\"')
515 in_quote
= !in_quote
;
517 else if (!in_escape
&& c
== '\'')
521 else if ((in_quote
|| in_char
) && c
== '\\')
523 in_escape
= !in_escape
;
525 else if ((in_quote
|| in_char
) && in_escape
)
529 else if (!in_quote
&& c
== '/')
533 if ((c2
= char_fromInt (lminput ())) == '*')
537 while ((c2
= char_fromInt (lminput ())) != '\0'
538 && c2
!= '\n' && c2
!= '*')
545 while ((c2
= char_fromInt (lminput ())) != '\0'
558 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
562 return macro_nextCharC ();
569 else /* normal character */
578 ** skips whitespace (handles line continuations)
579 ** returns first non-whitespace character
582 static char skip_whitespace (void)
586 while ((c
= macro_nextChar ()) == ' ' || c
== '\t')
594 void cscannerHelp_handleMacro ()
596 cstring mac
= cstring_undefined
;
600 while (currentColumn () > 2)
602 mac
= cstring_appendChar (mac
, ' ');
603 cscannerHelp_setTokLength (-1);
606 c
= macro_nextCharC ();
608 if (c
>= '0' && c
<= '9')
612 for (i
= 0; i
< (((int) (c
- '0')) + 1); i
++)
614 mac
= cstring_appendChar (mac
, ' ');
622 while (((c
= macro_nextCharC ()) != '\0') && (c
!= '\n'))
624 mac
= cstring_appendChar (mac
, c
);
628 macrocode
= tokenMacroCode (mac
);
630 if (macrocode
== BADTOK
&& !isArtificial (mac
))
632 context_addMacroCache (mac
);
641 context_incLineno ();
645 bool cscannerHelp_handleSpecial (char *yyt
)
647 char *l
; /* !! = mstring_create (MAX_NAME_LENGTH); */
654 len_yyt
= strlen (yyt
+1) ;
656 l
= mstring_copy (yyt
+ 1);
658 while ((c
= char_fromInt (lminput ())) != '\n' && c
!= '\0')
660 l
= mstring_append(l
, c
);
663 /* Need to safe original l for deallocating. */
668 olc
= cstring_fromChars (ol
);
670 if (cstring_equalPrefixLit (olc
, "pragma"))
672 char *pname
= mstring_create (size_fromInt (MAX_PRAGMA_LEN
));
673 char *opname
= pname
;
674 char *ptr
= ol
+ 6; /* pragma is six characters, plus space */
678 /* skip whitespace */
679 while (((c
= *ptr
) != '\0') && isspace (c
))
685 while (((c
= *ptr
) != '\0') && !isspace (c
))
689 if (len
> MAX_PRAGMA_LEN
)
700 if (len
== PRAGMA_LEN_EXPAND
701 && mstring_equal (opname
, PRAGMA_EXPAND
))
703 cstring exname
= cstring_undefined
;
707 while (((c
= *ptr
) != '\0') && !isspace (c
))
709 exname
= cstring_appendChar (exname
, c
);
714 ue
= usymtab_lookupExposeGlob (exname
);
716 if (uentry_isExpandedMacro (ue
))
718 if (fileloc_isPreproc (uentry_whereDefined (ue
)))
720 fileloc_setColumn (g_currentloc
, 1);
721 uentry_setDefined (ue
, g_currentloc
);
725 cstring_free (exname
);
728 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: pragment increments line */
730 else if (cstring_equalPrefixLit (olc
, "ident"))
732 /* Some pre-processors will leave these in the code. Ignore rest of line */
733 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: ident increments line */
737 ** Yuk...Win32 filenames can have spaces in them...we need to read
738 ** to the matching end quote.
740 else if ((sscanf (ol
, "line %d \"", &lineno
) == 1)
741 || (sscanf (ol
, " %d \"", &lineno
) == 1))
748 while (*tmp
!= '\"' && *tmp
!= '\0')
753 llassert (*tmp
== '\"');
757 while (*tmp
!= '\"' && *tmp
!= '\0')
762 llassert (*tmp
== '\"');
765 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
768 ** DOS-like path delimiters get delivered in pairs, something like
769 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
770 ** remove the pre dirs yet as we usually specify tmp paths relative
771 ** to the current directory, so tmp files would not get found in
772 ** the hash table. If this method fails we try it again later.
779 ** Skip past the drive marker.
782 if (strchr (stmp
, ':') != NULL
)
784 stmp
= strchr (stmp
, ':') + 1;
787 while ((stmp
= strchr (stmp
, CONNECTCHAR
)) != NULL
)
789 if (*(stmp
+1) == CONNECTCHAR
)
791 memmove (stmp
, stmp
+1, strlen (stmp
));
797 fid
= fileTable_lookupBase (context_fileTable (), fname
);
798 if (!(fileId_isValid (fid
)))
800 fname
= removePreDirs (fname
);
801 fid
= fileTable_lookupBase (context_fileTable (), fname
);
804 # else /* !defined(OS2) && !defined(MSDOS) */
805 fname
= removePreDirs (fname
);
806 fid
= fileTable_lookupBase (context_fileTable (), fname
);
807 # endif /* !defined(OS2) && !defined(MSDOS) */
809 if (!(fileId_isValid (fid
)))
811 if (context_inXHFile ())
813 fid
= fileTable_addXHFile (context_fileTable (), fname
);
815 else if (isHeaderFile (fname
))
817 fid
= fileTable_addHeaderFile (context_fileTable (), fname
);
821 fid
= fileTable_addFile (context_fileTable (), fname
);
825 setFileLine (fid
, lineno
);
826 /*@noaccess cstring@*/
828 else if ((sscanf (ol
, "line %d", &lineno
) == 1)
829 || (sscanf (ol
, " %d", &lineno
) == 1))
831 setLine (lineno
); /* next line is <cr> */
835 if (mstring_equal (ol
, "")) {
836 DPRINTF (("Empty pp command!"));
838 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
839 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
842 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
846 (FLG_UNRECOGDIRECTIVE
,
847 message ("Unrecognized pre-processor directive: #%s",
848 cstring_fromChars (ol
)),
850 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
854 return FALSE
; /* evans 2001-12-30: was: TRUE; */
861 int cscannerHelp_handleLlSpecial (void)
866 char *s
= mstring_createEmpty ();
872 loc
= fileloc_copy (g_currentloc
);
873 DPRINTF (("Handle special: %s", fileloc_unparse (loc
)));
875 while (((ic
= cscannerHelp_ninput ()) != 0) && isalpha (ic
))
878 s
= mstring_append (s
, c
);
882 DPRINTF (("Read: %s / %s", s
, fileloc_unparse (g_currentloc
)));
885 if (charsread
== 0 && ic
== (int) AFTER_COMMENT_MARKER
[0])
887 ic
= cscannerHelp_ninput ();
889 llassert (ic
== (int) AFTER_COMMENT_MARKER
[1]);
895 return QNOMODS
; /* special token no modifications token */
899 DPRINTF (("Coment marker: %s", os
));
900 tok
= commentMarkerToken (cstring_fromChars (os
));
904 s_tokLength
= charsread
;
907 s_whichSpecPart
= tok
;
912 DPRINTF (("Not a comment marker..."));
913 /* Add rest of the comment */
915 if (ic
!= 0 && ic
!= EOF
)
919 s
= mstring_append (s
, c
);
922 while (((ic
= cscannerHelp_ninput ()) != 0) && (ic
!= EOF
)
923 && (ic
!= (int) AFTER_COMMENT_MARKER
[0]))
927 /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
930 hasnl
= TRUE
; /* This prevents tokLength from being set later. */
935 message ("Likely parse error: syntactic comment token spans multiple lines: %s",
936 cstring_fromChars (s
)),
940 s
= mstring_append (s
, c
);
944 } /* spurious (?) warnings about s */
947 DPRINTF (("Read: %s / %s", s
, fileloc_unparse (g_currentloc
)));
949 if (ic
== (int) AFTER_COMMENT_MARKER
[0])
951 int nc
= cscannerHelp_ninput ();
952 llassert ((char) nc
== AFTER_COMMENT_MARKER
[1]);
958 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
963 if (*s
== '-' || *s
== '+' || *s
== '=') /* setting flags */
967 while (c
== '-' || c
== '+' || c
== '=')
969 ynm set
= ynm_fromCodeChar (c
);
974 thisflag
= cstring_fromChars (s
);
976 while ((c
= *s
) != '\0' && (c
!= '-') && (c
!= '=')
977 && (c
!= '+') && (c
!= ' ') && (c
!= '\t') && (c
!= '\n'))
984 if (!context_getFlag (FLG_NOCOMMENTS
))
986 cstring flagname
= thisflag
;
987 flagcode fflag
= flags_identifyFlag (flagname
);
989 if (flagcode_isSkip (fflag
))
993 else if (flagcode_isModeName (fflag
))
995 if (ynm_isMaybe (set
))
1000 ("Semantic comment attempts to restore flag %s. "
1001 "A mode flag cannot be restored.",
1006 context_setMode (flagname
);
1009 else if (flagcode_isInvalid (fflag
))
1012 (FLG_UNRECOGFLAGCOMMENTS
,
1013 message ("Unrecognized option in semantic comment: %s",
1017 else if (flagcode_isGlobalFlag (fflag
))
1022 ("Semantic comment attempts to set global flag %s. "
1023 "A global flag cannot be set locally.",
1029 context_fileSetFlag (fflag
, set
, loc
);
1031 if (flagcode_hasArgument (fflag
))
1033 if (ynm_isMaybe (set
))
1038 ("Semantic comment attempts to restore flag %s. "
1039 "A flag for setting a value cannot be restored.",
1044 { /* cut-and-pastied from llmain...blecch */
1045 cstring extra
= cstring_undefined
;
1051 rest
= mstring_copy (s
);
1055 while ((rchar
= *rest
) != '\0'
1056 && (isspace (rchar
)))
1062 while ((rchar
= *rest
) != '\0'
1063 && !isspace (rchar
))
1065 extra
= cstring_appendChar (extra
, rchar
);
1069 s
--; /* evans 2002-07-12: this was previously only in the else branch.
1070 Leads to an invalid read on the true branch.
1075 if (cstring_isUndefined (extra
))
1080 ("Flag %s (in semantic comment) must be followed by an argument",
1081 flagcode_unparse (fflag
)));
1083 cstring_free (extra
);
1087 if (flagcode_hasNumber (fflag
))
1089 flags_setValueFlag (fflag
, extra
);
1091 else if (flagcode_hasChar (fflag
))
1093 flags_setValueFlag (fflag
, extra
);
1095 else if (flagcode_hasString (fflag
))
1097 flags_setStringFlag (fflag
, extra
);
1101 cstring_free (extra
);
1115 while ((c
== ' ') || (c
== '\t') || (c
== '\n'))
1121 if (context_inHeader () && !isArtificial (cstring_fromChars (os
)))
1123 DPRINTF (("Here adding comment: %s", os
));
1124 context_addComment (cstring_fromCharsNew (os
), loc
);
1136 annotationInfo ainfo
;
1138 while (*s
!= '\0' && *s
!= ' ' && *s
!= '\t' && *s
!= '\n')
1150 t
= cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t
)));
1151 macrocode
= tokenMacroCode (cstring_fromChars (t
));
1153 if (macrocode
!= BADTOK
)
1155 s_tokLength
= hasnl
? 0 : size_toInt (mstring_length (t
));
1161 if (macrocode
== SKIPTOK
)
1169 ainfo
= context_lookupAnnotation (cstring_fromChars (os
));
1171 if (annotationInfo_isDefined (ainfo
)) {
1172 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo
)));
1173 yylval
.annotation
= ainfo
;
1181 if (context_inHeader ())
1188 if ((context_inMacro () || context_inGlobalContext ())
1189 && macrocode
!= SKIPTOK
1190 && !isArtificial (cstring_fromChars (os
)))
1192 if (context_processingMacros ())
1194 /* evans 2002-02-24: don't add comments when procssing macros */
1198 context_addComment (cstring_fromCharsNew (os
), loc
);
1212 if (mstring_equal (t
, "ignore"))
1214 if (!context_getFlag (FLG_NOCOMMENTS
))
1216 context_enterSuppressRegion (loc
);
1219 else if ((*t
== 'i' || *t
== 't')
1220 && (*(t
+ 1) == '\0'))
1222 if (!context_getFlag (FLG_NOCOMMENTS
)
1223 && (*t
== 'i' || context_getFlag (FLG_TMPCOMMENTS
)))
1225 context_enterSuppressLine (-1, loc
); /* infinite suppression */
1228 else if (((*t
== 'i') || (*t
== 't'))
1229 && ((*(t
+ 1) >= '0' && *(t
+ 1) <= '9')))
1231 bool tmpcomment
= (*t
== 't');
1233 char *tt
= t
; /* don't mangle t, since it is free'd */
1236 if (lc
>= '0' && lc
<= '9')
1238 val
= (int)(lc
- '0');
1241 while (lc
>= '0' && lc
<= '9')
1244 val
+= (int) (lc
- '0');
1249 if (!context_getFlag (FLG_NOCOMMENTS
)
1250 && (!tmpcomment
|| context_getFlag (FLG_TMPCOMMENTS
)))
1252 DPRINTF (("Here: enter suppress: %s", fileloc_unparse (loc
)));
1253 context_enterSuppressLine (val
, loc
);
1256 else if (mstring_equal (t
, "end"))
1258 if (!context_getFlag (FLG_NOCOMMENTS
))
1260 context_exitSuppressRegion (loc
);
1263 else if (mstring_equal (t
, "notfunction"))
1265 ; /* handled by pcpp */
1267 else if (mstring_equal (t
, "access"))
1273 while (((c
= *s
) != '\0') && (c
== ' ' || c
== '\t' || c
== '\n'))
1283 tname
= cstring_fromChars (s
);
1285 while ((c
= *s
) != '\0' && c
!= ' '
1286 && c
!= '\t' && c
!= '\n' && c
!= ',')
1293 DPRINTF (("Access %s", tname
));
1295 if (!context_getFlag (FLG_NOCOMMENTS
)
1296 && !context_getFlag (FLG_NOACCESS
))
1298 if (usymtab_existsType (tname
))
1300 typeId uid
= usymtab_getTypeId (tname
);
1301 uentry ue
= usymtab_getTypeEntry (uid
);
1303 if (uentry_isAbstractDatatype (ue
))
1305 context_addFileAccessType (uid
);
1306 DPRINTF (("Adding access to: %s / %d", tname
, uid
));
1313 ("Non-abstract type %s used in access comment",
1320 if (!(context_inSuppressRegion ()
1321 || context_inSuppressZone (loc
)))
1326 ("Unrecognized type %s used in access comment",
1338 if (c
!= ',' && c
!= ' ')
1344 else if (mstring_equal (t
, "noaccess"))
1351 while (((lc
= *s
) != '\0') && (lc
== ' ' || lc
== '\t' || lc
== '\n'))
1361 tname
= cstring_fromChars (s
);
1363 while ((lc
= *s
) != '\0' && lc
!= ' ' && lc
!= '\t'
1364 && lc
!= '\n' && lc
!= ',')
1371 if (!context_getFlag (FLG_NOCOMMENTS
)
1372 && !context_getFlag (FLG_NOACCESS
))
1374 if (usymtab_existsType (tname
))
1376 typeId tuid
= usymtab_getTypeId (tname
);
1378 if (context_couldHaveAccess (tuid
))
1380 DPRINTF (("Removing access: %s", tname
));
1381 context_removeFileAccessType (tuid
);
1385 if (!(context_inSuppressRegion ()
1386 || context_inSuppressZone (loc
)))
1388 uentry ue
= usymtab_getTypeEntry (tuid
);
1390 if (uentry_isAbstractDatatype (ue
))
1395 ("Non-accessible abstract type %s used in noaccess comment",
1404 ("Non-abstract type %s used in noaccess comment",
1413 if (!(context_inSuppressRegion ()
1414 || context_inSuppressZone (loc
)))
1419 ("Unrecognized type %s used in noaccess comment",
1431 if (lc
!= ',' && lc
!= ' ')
1439 voptgenerror (FLG_UNRECOGCOMMENTS
,
1440 message ("Semantic comment unrecognized: %s",
1441 cstring_fromChars (os
)),
1444 } /* spurious (?) warning about t */
1455 /*@only@*/ cstring
cscannerHelp_makeIdentifier (char *s
)
1457 char *c
= mstring_create (strlen (s
) + 1);
1458 cstring id
= cstring_fromChars (c
);
1460 while (isalnum (*s
) || (*s
== '_') || (*s
== '$'))
1469 /*@observer@*/ /*@dependent@*/ uentry
cscannerHelp_coerceId (cstring cn
)
1471 if (!(usymtab_exists (cn
)))
1473 fileloc loc
= fileloc_createExternal ();
1476 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
1479 uentry ce
= uentry_makeUnrecognized (cn
, loc
);
1481 if (!context_inIterEnd ())
1485 message ("Unrecognized (possibly system) identifier: %q",
1486 uentry_getName (ce
)),
1493 return (usymtab_lookup (cn
));
1497 ** like, cscannerHelp_coerceId, but doesn't supercede for iters
1500 /*@observer@*/ uentry
cscannerHelp_coerceIterId (cstring cn
)
1502 if (!(usymtab_exists (cn
)))
1504 return uentry_undefined
;
1507 return (usymtab_lookup (cn
));
1511 ** Need to keep this in case there is a declaration that isn't processed until
1512 ** the scope exits. Would be good to rearrange the symbol table so this doesn't
1513 ** happen, and save all the cstring copying.
1516 /*@observer@*/ cstring
cscannerHelp_observeLastIdentifier ()
1518 cstring res
= s_lastidprocessed
;
1522 static void cscanner_setLastIdentifier (/*@keep@*/ cstring id
) /*@modifies s_lastidprocessed@*/
1524 if (cstring_isDefined (s_lastidprocessed
))
1526 cstring_free (s_lastidprocessed
);
1529 s_lastidprocessed
= id
;
1532 int cscannerHelp_processIdentifier (cstring id
)
1536 if (context_getFlag (FLG_GRAMMAR
))
1538 lldiagmsg (message ("Process identifier: %s", id
));
1541 context_clearJustPopped ();
1542 cscanner_setLastIdentifier (id
);
1544 DPRINTF (("Context: %s", context_unparse ()));
1546 if (context_inFunctionHeader ())
1548 int tok
= commentMarkerToken (id
);
1549 DPRINTF (("in function decl: %s", id
));
1557 tok
= tokenMacroCode (id
);
1565 annotationInfo ainfo
;
1567 if (s_expectingMetaStateName
)
1569 metaStateInfo msinfo
= context_lookupMetaStateInfo (id
);
1571 if (metaStateInfo_isDefined (msinfo
))
1573 yylval
.msinfo
= msinfo
;
1574 return METASTATE_NAME
;
1578 DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id
)));
1582 ainfo
= context_lookupAnnotation (id
);
1584 if (annotationInfo_isDefined (ainfo
))
1586 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo
)));
1587 yylval
.annotation
= ainfo
;
1592 DPRINTF (("Not annotation: %s", id
));
1598 DPRINTF (("Here!"));
1600 /* Consider handling: Defined by C99 as static const char __func__[] */
1602 if (context_getFlag (FLG_GNUEXTENSIONS
))
1606 if (cstring_equalLit (id
, "__stdcall")
1607 || cstring_equalLit (id
, "__cdecl")
1608 || cstring_equalLit (id
, "__extension__"))
1612 else if (cstring_equalLit (id
, "__volatile__"))
1616 else if (cstring_equalLit (id
, "__signed"))
1620 else if (cstring_equalLit (id
, "__unsigned"))
1624 else if (cstring_equalLit (id
, "__const__"))
1628 else if (cstring_equalLit (id
, "__alignof__"))
1630 tok
= CALIGNOF
; /* alignof is parsed like sizeof */
1632 else if (cstring_equalLit (id
, "__typeof__"))
1636 else if (cstring_equalLit (id
, "typeof"))
1640 else if (cstring_equalLit (id
, "__FUNCTION__")
1641 || cstring_equalLit (id
, "__PRETTY_FUNCTION__"))
1643 /* These tokens hold the name of the current function as strings */
1644 /* evans 2001-12-30: changed from exprNode_stringLiteral; bug reported by Jim Zelenka. */
1645 yylval
.expr
= exprNode_makeConstantString (id
, fileloc_copy (g_currentloc
));
1647 s_lastWasString
= TRUE
;
1651 else if (cstring_equalLit (id
, "__attribute__")
1652 || cstring_equalLit (id
, "__asm__")
1653 || cstring_equalLit (id
, "_asm")
1654 || cstring_equalLit (id
, "__asm")
1655 || cstring_equalLit (id
, "__declspec"))
1658 bool useparens
= FALSE
;
1659 bool usebraces
= FALSE
;
1660 bool inquote
= FALSE
;
1661 bool inescape
= FALSE
;
1664 while ((ic
= cscanner_input ()) != EOF
)
1666 char cc
= (char) ic
;
1672 else if (cc
== '\\')
1676 else if (cc
== '\"')
1712 else if (cc
== ')' && useparens
)
1715 if (depth
== 0) break;
1717 else if (cc
== '}' && usebraces
)
1720 if (depth
== 0) break;
1723 && !usebraces
&& !useparens
1724 && cstring_equalLit (id
, "__asm"))
1727 ** We need this because some MS VC++ include files
1728 ** have __asm mov ... }
1729 ** Its a kludge, but otherwise would need to parse
1746 context_incLineno ();
1748 if (cstring_equalLit (id
, "__asm")
1749 && !useparens
&& !usebraces
)
1756 llassert ((useparens
&& ic
== (int) ')')
1757 || (usebraces
&& ic
== (int) '}')
1758 || (!useparens
&& !usebraces
));
1762 else if (cstring_equalLit (id
, "inline")
1763 || cstring_equalLit (id
, "__inline")
1764 || cstring_equalLit (id
, "_inline")
1765 || cstring_equalLit (id
, "__inline__"))
1776 return (cscannerHelp_returnToken (tok
));
1780 le
= usymtab_lookupSafe (id
);
1782 /*@-dependenttrans@*/
1784 if (uentry_isIter (le
))
1789 else if (uentry_isEndIter (le
))
1792 return (ITER_ENDNAME
);
1794 else if (uentry_isUndefined (le
))
1796 yylval
.cname
= cstring_copy (id
);
1798 /* avoid parse errors for certain system built ins */
1800 if (s_expectingTypeName
&& (cstring_firstChar (id
) == '_')
1801 && (cstring_secondChar (id
) == '_'))
1803 return (TYPE_NAME_OR_ID
);
1806 return (NEW_IDENTIFIER
);
1808 else if (!uentry_isDeclared (le
) && !uentry_isCodeDefined (le
))
1810 if (uentry_isDatatype (le
))
1812 yylval
.cname
= cstring_copy (id
);
1813 return (NEW_IDENTIFIER
);
1818 return (IDENTIFIER
);
1821 else if (uentry_isDatatype (le
))
1823 if (!s_expectingTypeName
)
1825 yylval
.cname
= cstring_copy (id
);
1827 return (NEW_IDENTIFIER
);
1831 yylval
.ctyp
= uentry_getAbstractType (le
);
1833 uentry_setUsed (le
, g_currentloc
);
1840 return (IDENTIFIER
);
1843 /*@=dependenttrans@*/
1846 bool cscannerHelp_processHashIdentifier (/*@only@*/ cstring id
)
1848 if (context_inMacro () || context_inIterDef () ||
1849 context_inIterEnd ())
1853 context_clearJustPopped ();
1855 le
= usymtab_lookupSafe (id
);
1856 cscanner_setLastIdentifier (id
);
1858 if (uentry_isParam (le
) || uentry_isRefParam (le
))
1870 ** Will be handled by handleLlSpecial
1878 /*@only@*/ exprNode
cscannerHelp_processString (void)
1882 char *nl
= strchr (yytext
, '\n');
1883 cstring ns
= cstring_fromCharsNew (yytext
);
1887 loc
= fileloc_copy (g_currentloc
);
1888 addColumn (size_toInt (cstring_length (ns
)));
1894 loc
= fileloc_copy (g_currentloc
);
1896 context_incLineno ();
1898 while ((nl
= strchr ((nl
+ 1), '\n')) != NULL
)
1900 context_incLineno ();
1906 res
= exprNode_stringLiteral (ns
, loc
);
1911 ** process a wide character string L"...."
1914 /*@only@*/ exprNode
cscannerHelp_processWideString ()
1918 char *nl
= strchr (yytext
, '\n');
1921 llassert (*yytext
== 'L');
1924 ns
= cstring_fromCharsNew (yytext
);
1928 loc
= fileloc_copy (g_currentloc
);
1929 addColumn (size_toInt (cstring_length (ns
)));
1935 loc
= fileloc_copy (g_currentloc
);
1937 context_incLineno ();
1939 while ((nl
= strchr ((nl
+ 1), '\n')) != NULL
)
1941 context_incLineno ();
1946 res
= exprNode_wideStringLiteral (ns
, loc
);
1950 char cscannerHelp_processChar ()
1955 llassert (*yytext
!= '\0');
1956 fchar
= *(yytext
+ 1);
1957 if (fchar
!= '\\') return fchar
;
1959 next
= *(yytext
+ 2);
1963 case 'n': return '\n';
1964 case 't': return '\t';
1965 case '\"': return '\"';
1966 case '\'': return '\'';
1967 case '\\': return '\\';
1968 default: return '\0';
1972 double cscannerHelp_processFloat ()
1974 double ret
= atof (yytext
);
1979 long cscannerHelp_processHex ()
1984 llassert (yytext
[0] == '0'
1985 && (yytext
[1] == 'X' || yytext
[1] == 'x'));
1987 while (yytext
[index
] != '\0') {
1989 char c
= yytext
[index
];
1991 if (c
>= '0' && c
<= '9') {
1992 tval
= (int) c
- (int) '0';
1993 } else if (c
>= 'A' && c
<= 'F') {
1994 tval
= (int) c
- (int) 'A' + 10;
1995 } else if (c
>= 'a' && c
<= 'f') {
1996 tval
= (int) c
- (int) 'a' + 10;
1997 } else if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
1999 while (yytext
[index
] != '\0') {
2000 if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2005 message ("Invalid character (%c) following specifier in hex constant: %s",
2006 c
, cstring_fromChars (yytext
)),
2016 message ("Invalid character (%c) in hex constant: %s",
2017 c
, cstring_fromChars (yytext
)),
2022 val
= (val
* 16) + tval
;
2026 DPRINTF (("Hex constant: %s = %ld", yytext
, val
));
2030 long cscannerHelp_processOctal ()
2035 llassert (yytext
[0] == '0' && yytext
[1] != 'X' && yytext
[1] != 'x');
2037 while (yytext
[index
] != '\0') {
2039 char c
= yytext
[index
];
2041 if (c
>= '0' && c
<= '7') {
2042 tval
= (int) c
- (int) '0';
2043 } else if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2045 while (yytext
[index
] != '\0') {
2046 if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2051 message ("Invalid character (%c) following specifier in octal constant: %s",
2052 c
, cstring_fromChars (yytext
)),
2062 message ("Invalid character (%c) in octal constant: %s",
2063 c
, cstring_fromChars (yytext
)),
2068 val
= (val
* 8) + tval
;
2072 DPRINTF (("Octal constant: %s = %ld", yytext
, val
));
2076 long cscannerHelp_processDec ()
2078 return (atol (yytext
));
2081 int cscannerHelp_processSpec (int tok
)
2083 size_t length
= strlen (yytext
);
2089 patched to fix assert failures in constraint code.
2090 Added the else if test so that splint does not treat MaxSet and MaxRead
2093 if (s_whichSpecPart
== QMODIFIES
2094 || s_whichSpecPart
== QDEFINES
2095 || s_whichSpecPart
== QUSES
2096 || s_whichSpecPart
== QALLOCATES
2097 || s_whichSpecPart
== QSETS
2098 || s_whichSpecPart
== QRELEASES
)
2101 DPRINTF((message("Treating specifaction keyword %s as an identifiers. (This corresponds to"
2102 " token %d and we're in the specification denoted by %d see cgrammar_tokens.h"
2103 " for an explanation of these numbers",
2104 yytext
, tok
, s_whichSpecPart
)
2107 ; /* Allow specificiation keywords to be used as identifiers in these contexts. */
2109 else if ( (s_whichSpecPart
== QPRECLAUSE
2110 || s_whichSpecPart
== QPOSTCLAUSE
2111 || s_whichSpecPart
== QINVARIANT
)
2112 && (!cscannerHelp_isConstraintToken(tok
) )
2115 DPRINTF((message("Treating specifaction keyword %s as an identifiers. (This corresponds to"
2116 " token %d and we're in the specification denoted by %d see cgrammar_tokens.h"
2117 " for an explanation of these numbers",
2118 yytext
, tok
, s_whichSpecPart
)
2121 /* Allow specificiation keywords to be used as identifiers in these contexts. */
2125 cscannerHelp_setTokLengthT (length
);
2126 return cscannerHelp_returnToken (tok
);
2130 context_saveLocation ();
2131 cscannerHelp_setTokLengthT (length
);
2132 return (cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (yytext
)));
2135 void cscannerHelp_expectingMetaStateName ()
2137 llassert (!s_expectingMetaStateName
);
2138 llassert (context_inFunctionHeader ());
2139 s_expectingMetaStateName
= TRUE
;
2142 void cscannerHelp_clearExpectingMetaStateName ()
2144 llassert (s_expectingMetaStateName
);
2145 s_expectingMetaStateName
= FALSE
;
2148 bool cscannerHelp_isConstraintToken (int tok
)
2149 /* drl added 12/11/2002
2150 Tell whether a token has special meaning
2151 within a function constraint
2154 return (tok
== QMAXSET
|| tok
== QMAXREAD
);
2155 /* || tok == QMINREAD || tok == QMINSET */
2156 /* uncomment the additional if statement tests when minSet and minRead are supported */
2159 bool cscannerHelp_processMacro (void)
2164 cstring fname
= cstring_undefined
;
2166 bool isspecfcn
= FALSE
;
2167 bool isiter
= FALSE
;
2168 bool skipparam
= FALSE
;
2169 bool isenditer
= FALSE
;
2170 bool unknownm
= FALSE
;
2171 bool hasParams
= FALSE
;
2172 bool emptyMacro
= FALSE
;
2173 char c
= skip_whitespace ();
2174 fileloc loc
= fileloc_noColumn (g_currentloc
);
2176 /* are both of these necessary? what do they mean? */
2177 uentryList specparams
= uentryList_undefined
;
2178 uentryList pn
= uentryList_undefined
;
2180 context_resetMacroMissingParams ();
2182 if (c
== '\0' || c
== '\n')
2184 llcontbug (cstring_makeLiteral ("Bad macro"));
2189 fname
= cstring_appendChar (fname
, c
);
2191 while ((c
= macro_nextChar ()) != '(' && c
!= '\0'
2192 && c
!= ' ' && c
!= '\t' && c
!= '\n')
2194 fname
= cstring_appendChar (fname
, c
);
2197 if (c
== ' ' || c
== '\t' || c
== '\n')
2203 while (c
== ' ' || c
== '\t')
2205 c
= macro_nextChar ();
2207 cscanner_unput ((int) c
);
2213 cscanner_unput ((int) c
);
2219 hasParams
= (c
== '(');
2221 if (usymtab_exists (fname
))
2223 e2
= usymtab_lookupExpose (fname
);
2224 ct
= uentry_getType (e2
);
2226 if (uentry_isCodeDefined (e2
)
2227 && fileloc_isUser (uentry_whereDefined (e2
)))
2231 message ("Macro %s already defined", fname
),
2234 uentry_showWhereDefined (e2
);
2235 uentry_clearDefined (e2
);
2238 if (uentry_isFunction (e2
))
2240 uentry_setType (e2
, ctype_unknown
);
2243 context_enterUnknownMacro (e2
);
2247 context_enterConstantMacro (e2
);
2252 if (uentry_isForward (e2
) && uentry_isFunction (e2
))
2259 ("Parameterized macro has no prototype or specification: %s ",
2264 uentry_setType (e2
, ctype_unknown
);
2265 uentry_setFunctionDefined (e2
, loc
);
2266 uentry_setUsed (e2
, fileloc_undefined
);
2267 context_enterUnknownMacro (e2
);
2271 if (uentry_isIter (e2
))
2274 specparams
= uentry_getParams (e2
);
2275 noparams
= uentryList_size (specparams
);
2276 uentry_setDefined (e2
, loc
);
2277 context_enterIterDef (e2
);
2279 else if (uentry_isEndIter (e2
))
2282 uentry_setDefined (e2
, loc
);
2283 context_enterIterEnd (e2
); /* don't care about it now */
2284 /* but should parse like an iter! */
2286 else if (uentry_isConstant (e2
))
2292 message ("Constant %s implemented as parameterized macro",
2296 uentry_showWhereSpecified (e2
);
2297 uentry_setType (e2
, ctype_unknown
);
2298 uentry_makeConstantFunction (e2
);
2299 uentry_setDefined (e2
, g_currentloc
);
2300 uentry_setFunctionDefined (e2
, g_currentloc
);
2301 context_enterUnknownMacro (e2
);
2305 if (!uentry_isSpecified (e2
))
2307 fileloc oloc
= uentry_whereDeclared (e2
);
2309 if (fileloc_isLib (oloc
))
2313 else if (fileloc_isUndefined (oloc
)
2314 || fileloc_isPreproc (oloc
))
2319 (FLG_MACROCONSTDECL
,
2321 ("Macro constant %q not declared",
2322 uentry_getName (e2
)),
2326 else if (!fileloc_withinLines (oloc
, loc
, 2))
2327 { /* bogus! will give errors if there is too much whitespace */
2329 (FLG_MACROCONSTDIST
,
2331 ("Macro constant name %s matches name in "
2332 "distant constant declaration. This constant "
2333 "is declared at %q", fname
,
2334 fileloc_unparse (oloc
)),
2343 context_enterConstantMacro (e2
);
2344 cstring_free (fname
);
2350 else if (ctype_isFunction (ct
))
2353 specparams
= ctype_argsFunction (ct
);
2354 noparams
= uentryList_size (specparams
);
2356 uentry_setFunctionDefined (e2
, loc
);
2357 context_enterMacro (e2
);
2359 else if (uentry_isVar (e2
))
2365 message ("Variable %s implemented as parameterized macro",
2369 uentry_showWhereSpecified (e2
);
2370 uentry_setType (e2
, ctype_unknown
);
2371 uentry_makeVarFunction (e2
);
2372 uentry_setDefined (e2
, g_currentloc
);
2373 uentry_setFunctionDefined (e2
, g_currentloc
);
2374 context_enterUnknownMacro (e2
);
2378 uentry ucons
= uentry_makeConstant (fname
,
2381 if (uentry_isExpandedMacro (e2
))
2389 message ("Variable %s implemented by a macro",
2393 uentry_showWhereSpecified (e2
);
2397 uentry_setDefined (e2
, loc
);
2398 uentry_setUsed (ucons
, loc
);
2400 context_enterConstantMacro (ucons
);
2401 uentry_markOwned (ucons
);
2402 cstring_free (fname
);
2408 if (uentry_isDatatype (e2
))
2412 message ("Type implemented as macro: %x",
2413 uentry_getName (e2
)),
2414 message ("A type is implemented using a macro definition. A "
2415 "typedef should be used instead."),
2418 cscannerHelp_swallowMacro ();
2419 /* Must exit scope (not sure why a new scope was entered?) */
2420 usymtab_quietExitScope (g_currentloc
);
2421 uentry_setDefined (e2
, g_currentloc
);
2427 (message ("Unexpanded macro not function or constant: %q",
2428 uentry_unparse (e2
)));
2429 uentry_setType (e2
, ctype_unknown
);
2433 uentry_makeVarFunction (e2
);
2434 uentry_setDefined (e2
, g_currentloc
);
2435 uentry_setFunctionDefined (e2
, g_currentloc
);
2436 context_enterUnknownMacro (e2
);
2447 /* evans 2001-09-09 - if it has params, assume a function */
2451 (FLG_MACROMATCHNAME
,
2452 message ("Unexpanded macro %s does not match name of a declared "
2453 "function. The name used in the control "
2454 "comment on the previous line should match.",
2458 ce
= uentry_makeFunction (fname
, ctype_unknown
,
2462 warnClause_undefined
,
2464 uentry_setUsed (ce
, loc
); /* perhaps bogus? */
2465 e2
= usymtab_supEntryReturn (ce
);
2466 context_enterUnknownMacro (e2
);
2471 (FLG_MACROMATCHNAME
,
2472 message ("Unexpanded macro %s does not match name of a constant "
2473 "or iter declaration. The name used in the control "
2474 "comment on the previous line should match. "
2475 "(Assuming macro defines a constant.)",
2479 ce
= uentry_makeConstant (fname
, ctype_unknown
, fileloc_undefined
);
2480 uentry_setUsed (ce
, loc
); /* perhaps bogus? */
2481 e2
= usymtab_supEntryReturn (ce
);
2483 context_enterConstantMacro (e2
);
2484 cstring_free (fname
);
2490 /* in macros, ( must follow immediatetly after name */
2496 c
= skip_whitespace ();
2498 while (c
!= ')' && c
!= '\0')
2501 bool suppress
= context_inSuppressRegion ();
2502 cstring paramname
= cstring_undefined
;
2505 ** save the parameter location
2509 context_saveLocation ();
2512 while (c
!= ' ' && c
!= '\t' && c
!= ',' && c
!= '\0' && c
!= ')')
2514 paramname
= cstring_appendChar (paramname
, c
);
2515 c
= macro_nextChar ();
2518 if (c
== ' ' || c
== '\t') c
= skip_whitespace ();
2522 c
= macro_nextChar ();
2523 if (c
== ' ' || c
== '\t') c
= skip_whitespace ();
2528 llfatalerror (cstring_makeLiteral
2529 ("Bad macro syntax: uentryList"));
2532 if ((isspecfcn
|| isiter
) && (paramno
< noparams
)
2533 && !uentry_isElipsisMarker (uentryList_getN
2534 (specparams
, paramno
)))
2536 fileloc sloc
= context_getSaveLocation ();
2537 uentry decl
= uentryList_getN (specparams
, paramno
);
2540 param
= uentry_nameCopy (paramname
, decl
);
2542 uentry_setParam (param
);
2543 sr
= sRef_makeParam (paramno
, uentry_getType (param
),
2544 stateInfo_makeLoc (sloc
, SA_DECLARED
));
2546 if (sRef_getNullState (sr
) == NS_ABSNULL
)
2548 ctype pt
= ctype_realType (uentry_getType (param
));
2550 if (ctype_isUser (pt
))
2552 uentry te
= usymtab_getTypeEntrySafe (ctype_typeId (pt
));
2554 if (uentry_isValid (te
))
2556 sRef_setStateFromUentry (sr
, te
);
2561 sRef_setNullState (sr
, NS_UNKNOWN
, sloc
);
2565 uentry_setSref (param
, sr
);
2566 uentry_setDeclaredForceOnly (param
, sloc
);
2568 skipparam
= isiter
&& uentry_isOut (uentryList_getN (specparams
, paramno
));
2572 fileloc sloc
= context_getSaveLocation ();
2574 param
= uentry_makeVariableSrefParam
2575 (paramname
, ctype_unknown
, fileloc_copy (sloc
),
2576 sRef_makeParam (paramno
, ctype_unknown
,
2577 stateInfo_makeLoc (sloc
, SA_DECLARED
)));
2578 DPRINTF (("Unknown param: %s", uentry_unparseFull (param
)));
2579 cstring_free (paramname
);
2581 sRef_setPosNull (uentry_getSref (param
), sloc
);
2582 uentry_setDeclaredForce (param
, sloc
);
2585 fileloc_free (sloc
);
2590 llassert (!uentry_isElipsisMarker (param
));
2594 sRef_makeUnsafe (uentry_getSref (param
));
2597 pn
= uentryList_add (pn
, uentry_copy (param
));
2598 usymtab_supEntry (param
);
2602 /* don't add param */
2603 uentry_free (param
);
2608 (void) macro_nextChar ();
2609 c
= skip_whitespace ();
2617 if (isspecfcn
|| isiter
)
2619 if (paramno
!= noparams
&& noparams
>= 0)
2621 cscannerHelp_advanceLine ();
2625 message ("Macro %s specified with %d args, defined with %d",
2626 fname
, noparams
, paramno
),
2629 uentry_showWhereSpecified (e2
);
2630 uentry_resetParams (e2
, pn
);
2635 uentry_resetParams (e2
, pn
);
2642 ** the form should be:
2644 ** # define newname oldname
2645 ** where oldname refers to a function matching the specification
2651 sRef_setGlobalScope ();
2652 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname
, ctype_unknown
));
2653 sRef_clearGlobalScope ();
2657 context_setMacroMissingParams ();
2662 /* context_setuentryList (pn); */
2663 usymtab_enterScope ();
2666 cstring_free (fname
);
2671 void cscannerHelp_setTokLength (int len
)
2675 DPRINTF (("Set tok length: %d", len
));
2678 void cscannerHelp_setTokLengthT (size_t len
)
2680 cscannerHelp_setTokLength (size_toInt (len
));
2683 void cscannerHelp_advanceLine (void)
2689 int cscannerHelp_returnToken (int t
)
2691 if (s_tokLength
> fileloc_column (g_currentloc
)) {
2692 yylval
.tok
= lltok_create (t
, fileloc_copy (g_currentloc
));
2694 yylval
.tok
= lltok_create (t
, fileloc_decColumn (g_currentloc
, s_tokLength
));
2698 s_lastWasString
= FALSE
;
2702 int cscannerHelp_returnTokenLength (int t
, int length
)
2704 cscannerHelp_setTokLength (length
);
2705 return cscannerHelp_returnToken (t
);
2708 int cscannerHelp_returnString (cstring s
)
2710 yylval
.expr
= exprNode_stringLiteral (s
, fileloc_decColumn (g_currentloc
, s_tokLength
));
2712 s_lastWasString
= TRUE
;
2716 int cscannerHelp_returnInt (ctype ct
, long val
)
2720 if (ctype_equal (ct
, ctype_int
))
2724 c
= context_typeofZero ();
2728 c
= context_typeofOne ();
2736 yylval
.expr
= exprNode_numLiteral (c
, cstring_fromChars (yytext
),
2737 fileloc_decColumn (g_currentloc
, s_tokLength
),
2740 s_lastWasString
= FALSE
;
2744 int cscannerHelp_returnFloat (ctype ct
, double f
)
2746 yylval
.expr
= exprNode_floatLiteral (f
, ct
, cstring_fromChars (yytext
),
2747 fileloc_decColumn (g_currentloc
, s_tokLength
));
2749 s_lastWasString
= FALSE
;
2753 int cscannerHelp_returnChar (char c
)
2755 yylval
.expr
= exprNode_charLiteral (c
, cstring_fromChars (yytext
),
2756 fileloc_decColumn (g_currentloc
, s_tokLength
));
2758 s_lastWasString
= FALSE
;
2762 int cscannerHelp_returnType (int tok
, ctype ct
)
2766 s_lastWasString
= FALSE
;
2770 int cscannerHelp_returnExpr (exprNode e
)
2774 s_lastWasString
= TRUE
;
2778 void cscannerHelp_setExpectingTypeName ()
2780 s_expectingTypeName
= TRUE
;
2783 void cscannerHelp_clearExpectingTypeName ()
2785 s_expectingTypeName
= FALSE
;
2788 bool cscannerHelp_isExpectingTypeName ()
2790 return s_expectingTypeName
;
2793 int cscannerHelp_processTextIdentifier (char *text
)
2795 context_saveLocation ();
2796 cscannerHelp_setTokLength (size_toInt (mstring_length (text
)));
2797 return cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (text
));
2800 static bool s_continueLine
= FALSE
;
2802 int cscannerHelp_handleNewLine ()
2804 context_incLineno ();
2806 if (s_tokLength
!= 0) {
2808 /* No error to report
2811 message ("Likely parse error: token spans multiple lines."),
2818 s_continueLine
= FALSE
;
2822 if (context_inMacro ())
2824 /* Don't use return cscannerHelp_returnToken */
2825 /* !!! evans 2002-03-13 */
2826 yylval
.tok
= lltok_create (TENDMACRO
, fileloc_copy (g_currentloc
));
2827 s_lastWasString
= FALSE
;
2835 void cscannerHelp_setContinueLine ()
2837 s_continueLine
= TRUE
;
2840 void cscannerHelp_exitSpecPart ()
2842 llassert (s_inSpecPart
);
2843 s_inSpecPart
= FALSE
;
2844 s_whichSpecPart
= BADTOK
;