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_expectingTypeName
= TRUE
;
50 /*@null@*/ /*@observer@*/ char *name
;
55 ** These tokens are followed by syntax that is parsed by the
59 static struct skeyword s_parsetable
[] = {
60 { "modifies", QMODIFIES
} ,
61 { "globals", QGLOBALS
} ,
64 { "constant", QCONSTANT
} ,
65 { "function", QFUNCTION
} ,
67 { "defines", QDEFINES
} ,
69 { "allocates", QALLOCATES
} ,
71 { "releases", QRELEASES
} ,
72 { "pre", QPRECLAUSE
} ,
73 { "post", QPOSTCLAUSE
} ,
74 { "requires", QPRECLAUSE
} ,
75 { "ensures", QPOSTCLAUSE
} ,
80 ** These tokens are either stand-alone tokens, or followed by
81 ** token-specific text.
84 static struct skeyword s_keytable
[] = {
85 { "anytype", QANYTYPE
} ,
86 { "integraltype", QINTEGRALTYPE
} ,
87 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE
} ,
88 { "signedintegraltype", QSIGNEDINTEGRALTYPE
} ,
93 { "dependent", QDEPENDENT
} ,
94 { "partial", QPARTIAL
} ,
95 { "special", QSPECIAL
} ,
96 { "truenull", QTRUENULL
} ,
97 { "falsenull", QFALSENULL
} ,
98 { "nullwhentrue", QTRUENULL
} ,
99 { "falsewhennull", QFALSENULL
} ,
102 { "notnull", QNOTNULL
} ,
103 { "abstract", QABSTRACT
} ,
104 { "numabstract", QNUMABSTRACT
} ,
105 { "concrete", QCONCRETE
} ,
106 { "mutable", QMUTABLE
} ,
107 { "immutable", QIMMUTABLE
} ,
108 { "unused", QUNUSED
} ,
109 { "external", QEXTERNAL
} ,
111 { "unique", QUNIQUE
} ,
112 { "returned", QRETURNED
} ,
113 { "exposed", QEXPOSED
} ,
114 { "refcounted", QREFCOUNTED
} ,
116 { "newref", QNEWREF
} ,
117 { "tempref", QTEMPREF
} ,
118 { "killref", QKILLREF
} ,
120 { "relnull", QRELNULL
} ,
121 { "nullterminated", QNULLTERMINATED
},
122 { "isnull", QISNULL
},
123 { "MaxSet", QMAXSET
},
124 { "MaxRead", QMAXREAD
},
125 { "maxSet", QMAXSET
},
126 { "maxRead", QMAXREAD
},
127 { "reldef", QRELDEF
} ,
128 { "observer", QOBSERVER
} ,
129 { "exits", QEXITS
} ,
130 { "noreturn", QEXITS
} ,
131 { "mayexit", QMAYEXIT
} ,
132 { "maynotreturn", QMAYEXIT
} ,
133 { "trueexit", QTRUEEXIT
} ,
134 { "falseexit", QFALSEEXIT
} ,
135 { "noreturnwhentrue", QTRUEEXIT
} ,
136 { "noreturnwhenfalse", QFALSEEXIT
} ,
137 { "neverexit", QNEVEREXIT
} ,
138 { "alwaysreturns", QNEVEREXIT
} ,
140 { "shared", QSHARED
} ,
142 { "unchecked", QUNCHECKED
} ,
143 { "checked", QCHECKED
} ,
144 { "checkmod", QCHECKMOD
} ,
145 { "checkedstrict", QCHECKEDSTRICT
} ,
146 { "innercontinue", QINNERCONTINUE
} ,
147 { "innerbreak", QINNERBREAK
} ,
148 { "loopbreak", QLOOPBREAK
} ,
149 { "switchbreak", QSWITCHBREAK
} ,
150 { "safebreak", QSAFEBREAK
} ,
151 { "fallthrough", QFALLTHROUGH
} ,
152 { "l_fallthrou", QLINTFALLTHROUGH
} ,
153 { "l_fallth", QLINTFALLTHRU
} ,
154 { "notreached", QNOTREACHED
} ,
155 { "l_notreach", QLINTNOTREACHED
} ,
156 { "printflike", QPRINTFLIKE
} ,
157 { "l_printfli", QLINTPRINTFLIKE
} ,
158 { "scanflike", QSCANFLIKE
} ,
159 { "messagelike", QMESSAGELIKE
} ,
160 { "l_argsus", QARGSUSED
} ,
164 static bool cscannerHelp_isSpecTokenRegularId (int p_tok
) /*@*/;
165 static void cscannerHelp_advanceLine (void) /*@modifies g_currentloc, internalState@*/ ;
168 ** would be better if these weren't hard coded...
171 static bool isArtificial (cstring s
)
173 return (cstring_equalLit (s
, "modifies")
174 || cstring_equalLit (s
, "globals")
175 || cstring_equalLit (s
, "warn")
176 || cstring_equalLit (s
, "alt"));
179 void cscannerHelp_swallowMacro (void)
182 bool skipnext
= FALSE
;
184 while ((i
= lminput ()) != EOF
)
200 reader_checkUngetc (i
, c_in
);
212 reader_checkUngetc (i
, c_in
);
216 static int commentMarkerToken (cstring s
)
220 while (s_parsetable
[i
].name
!= NULL
)
222 DPRINTF (("Try :%s:%s:", s
, s_parsetable
[i
].name
));
224 if (cstring_equalLit (s
, s_parsetable
[i
].name
))
226 return s_parsetable
[i
].token
;
235 static int tokenMacroCode (cstring s
)
239 while (s_keytable
[i
].name
!= NULL
)
241 if (cstring_equalLit (s
, s_keytable
[i
].name
))
243 if (s_keytable
[i
].token
== QLINTFALLTHROUGH
)
246 (FLG_WARNLINTCOMMENTS
,
248 ("Traditional lint comment /*FALLTHROUGH*/ used. "
249 "Splint interprets this in the same way as most Unix lints, but it is "
250 "preferable to replace it with the /*@fallthrough@*/ "
255 else if (s_keytable
[i
].token
== QLINTFALLTHRU
)
258 (FLG_WARNLINTCOMMENTS
,
260 ("Traditional lint comment /*FALLTHRU*/ used. "
261 "Splint interprets this in the same way as most Unix lints, but it is "
262 "preferable to replace it with the /*@fallthrough@*/ "
267 else if (s_keytable
[i
].token
== QLINTNOTREACHED
)
270 (FLG_WARNLINTCOMMENTS
,
272 ("Traditional lint comment /*NOTREACHED*/ used. "
273 "Splint interprets this in the same way as most Unix lints, but it is "
274 "preferable to replace it with the /*@notreached@*/ "
275 "semantic comment."),
280 else if (s_keytable
[i
].token
== QPRINTFLIKE
)
282 setSpecialFunction (qual_createPrintfLike ());
285 else if (s_keytable
[i
].token
== QLINTPRINTFLIKE
)
288 (FLG_WARNLINTCOMMENTS
,
290 ("Traditional lint comment /*PRINTFLIKE*/ used. "
291 "Splint interprets this in the same way as most Unix lints, but it is "
292 "preferable to replace it with either /*@printflike@*/, "
293 "/*@scanflike@*/ or /*@messagelike@*/."),
296 setSpecialFunction (qual_createPrintfLike ());
299 else if (s_keytable
[i
].token
== QSCANFLIKE
)
301 setSpecialFunction (qual_createScanfLike ());
304 else if (s_keytable
[i
].token
== QMESSAGELIKE
)
306 setSpecialFunction (qual_createMessageLike ());
309 else if (s_keytable
[i
].token
== QARGSUSED
)
312 (FLG_WARNLINTCOMMENTS
,
314 ("Traditional lint comment /*ARGSUSED*/ used. "
315 "Splint interprets this in the same way as most Unix lints, but it is "
316 "preferable to use /*@unused@*/ annotations on "
317 "the unused parameters."),
325 return s_keytable
[i
].token
;
335 static int lminput (void)
337 if (s_savechar
== '\0')
340 return (cscanner_input ());
344 int save
= (int) s_savechar
;
350 static void lmsavechar (char c
)
352 if (s_savechar
== '\0')
358 llbuglit ("lmsavechar: override");
362 int cscannerHelp_ninput (void)
366 if (c
!= EOF
&& ((char)c
== '\n'))
368 context_incLineno ();
374 static char macro_nextChar (void)
376 static bool in_quote
= FALSE
, in_escape
= FALSE
, in_char
= FALSE
;
381 c
= char_fromInt (ic
);
383 if (!in_quote
&& !in_char
&& (c
== '\\' || c
== BEFORE_COMMENT_MARKER
[0]))
387 while ((c
= char_fromInt (lminput ())) != '\0' && c
!= '\n')
389 ; /* skip to newline */
392 context_incLineno ();
396 return macro_nextChar ();
403 else /* if (c == '@') */
407 if (cscannerHelp_handleLlSpecial () != BADTOK
)
409 llerrorlit (FLG_SYNTAX
, "Macro cannot use special syntax");
412 return macro_nextChar ();
415 else if (!in_escape
&& c
== '\"')
417 in_quote
= !in_quote
;
419 else if (!in_escape
&& c
== '\'')
423 else if ((in_quote
|| in_char
) && c
== '\\')
425 in_escape
= !in_escape
;
427 else if ((in_quote
|| in_char
) && in_escape
)
431 else if (!in_quote
&& c
== '/')
435 if ((c2
= char_fromInt (lminput ())) == '*')
439 while ((c2
= char_fromInt (lminput ())) != '\0'
440 && c2
!= '\n' && c2
!= '*')
447 while ((c2
= char_fromInt (lminput ())) != '\0'
460 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
464 return macro_nextChar ();
468 /*** putchar does not work! why? puts to stdio...??! ***/
481 ** keeps semantic comments
484 static char macro_nextCharC (void)
486 static bool in_quote
= FALSE
, in_escape
= FALSE
, in_char
= FALSE
;
489 c
= char_fromInt (lminput ());
491 if (!in_quote
&& !in_char
&& c
== '\\')
493 while ((c
= char_fromInt (lminput ())) != '\0' && c
!= '\n')
495 ; /* skip to newline */
498 context_incLineno ();
502 return macro_nextCharC ();
509 else if (!in_escape
&& c
== '\"')
511 in_quote
= !in_quote
;
513 else if (!in_escape
&& c
== '\'')
517 else if ((in_quote
|| in_char
) && c
== '\\')
519 in_escape
= !in_escape
;
521 else if ((in_quote
|| in_char
) && in_escape
)
525 else if (!in_quote
&& c
== '/')
529 if ((c2
= char_fromInt (lminput ())) == '*')
533 while ((c2
= char_fromInt (lminput ())) != '\0'
534 && c2
!= '\n' && c2
!= '*')
541 while ((c2
= char_fromInt (lminput ())) != '\0'
554 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
558 return macro_nextCharC ();
565 else /* normal character */
574 ** skips whitespace (handles line continuations)
575 ** returns first non-whitespace character
578 static char skip_whitespace (void)
582 while ((c
= macro_nextChar ()) == ' ' || c
== '\t')
590 void cscannerHelp_handleMacro (void)
592 cstring mac
= cstring_undefined
;
596 while (currentColumn () > 2)
598 mac
= cstring_appendChar (mac
, ' ');
599 cscannerHelp_setTokLength (-1);
602 c
= macro_nextCharC ();
604 if (c
>= '0' && c
<= '9')
608 for (i
= 0; i
< (((int) (c
- '0')) + 1); i
++)
610 mac
= cstring_appendChar (mac
, ' ');
618 while (((c
= macro_nextCharC ()) != '\0') && (c
!= '\n'))
620 mac
= cstring_appendChar (mac
, c
);
623 macrocode
= tokenMacroCode (mac
);
625 if (macrocode
== BADTOK
&& !isArtificial (mac
))
627 context_addMacroCache (mac
);
636 context_incLineno ();
640 bool cscannerHelp_handleSpecial (char *text
)
642 char *l
; /* !! = mstring_create (MAX_NAME_LENGTH); */
648 l
= mstring_copy (text
+ 1);
650 while ((c
= char_fromInt (lminput ())) != '\n' && c
!= '\0')
652 l
= mstring_append(l
, c
);
657 olc
= cstring_fromChars (ol
);
659 if (cstring_equalPrefixLit (olc
, "pragma"))
661 char *pname
= mstring_create (size_fromInt (MAX_PRAGMA_LEN
));
662 char *opname
= pname
;
663 char *ptr
= ol
+ 6; /* pragma is six characters, plus space */
667 /* skip whitespace */
668 while (((c
= *ptr
) != '\0') && isspace (c
))
674 while (((c
= *ptr
) != '\0') && !isspace (c
))
678 if (len
> MAX_PRAGMA_LEN
)
689 if (len
== PRAGMA_LEN_EXPAND
690 && mstring_equal (opname
, PRAGMA_EXPAND
))
692 cstring exname
= cstring_undefined
;
696 while (((c
= *ptr
) != '\0') && !isspace (c
))
698 exname
= cstring_appendChar (exname
, c
);
703 ue
= usymtab_lookupExposeGlob (exname
);
705 if (uentry_isExpandedMacro (ue
))
707 if (fileloc_isPreproc (uentry_whereDefined (ue
)))
709 fileloc_setColumn (g_currentloc
, 1);
710 uentry_setDefined (ue
, g_currentloc
);
714 cstring_free (exname
);
717 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: pragment increments line */
719 else if (cstring_equalPrefixLit (olc
, "ident"))
721 /* Some pre-processors will leave these in the code. Ignore rest of line */
722 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: ident increments line */
726 ** Yuk...Win32 filenames can have spaces in them...we need to read
727 ** to the matching end quote.
729 else if ((sscanf (ol
, "line %d \"", &lineno
) == 1)
730 || (sscanf (ol
, " %d \"", &lineno
) == 1))
737 while (*tmp
!= '\"' && *tmp
!= '\0')
742 llassert (*tmp
== '\"');
746 while (*tmp
!= '\"' && *tmp
!= '\0')
751 llassert (*tmp
== '\"');
754 # if defined(OS2) || defined(WIN32)
757 ** DOS-like path delimiters get delivered in pairs, something like
758 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
759 ** remove the pre dirs yet as we usually specify tmp paths relative
760 ** to the current directory, so tmp files would not get found in
761 ** the hash table. If this method fails we try it again later.
768 ** Skip past the drive marker.
771 if (strchr (stmp
, ':') != NULL
)
773 stmp
= strchr (stmp
, ':') + 1;
776 while ((stmp
= strchr (stmp
, CONNECTCHAR
)) != NULL
)
778 if (*(stmp
+1) == CONNECTCHAR
)
780 memmove (stmp
, stmp
+1, strlen (stmp
));
786 fid
= fileTable_lookupBase (context_fileTable (), fname
);
787 if (!(fileId_isValid (fid
)))
789 fname
= osd_removePreDirs (fname
);
790 fid
= fileTable_lookupBase (context_fileTable (), fname
);
794 fname
= osd_removePreDirs (fname
);
795 fid
= fileTable_lookupBase (context_fileTable (), fname
);
798 if (!(fileId_isValid (fid
)))
802 if (context_inXHFile ())
804 ftype
= FILE_XH
; /* Files included by XH files are also XH files */
806 else if (fileLib_isHeader (fname
))
815 fid
= fileTable_addFile (context_fileTable (), ftype
, fname
);
818 setFileLine (fid
, lineno
);
819 /*@noaccess cstring@*/
821 else if ((sscanf (ol
, "line %d", &lineno
) == 1)
822 || (sscanf (ol
, " %d", &lineno
) == 1))
824 setLine (lineno
); /* next line is <cr> */
828 if (mstring_equal (ol
, "")) {
829 DPRINTF (("Empty pp command!"));
831 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
832 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
835 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
839 (FLG_UNRECOGDIRECTIVE
,
840 message ("Unrecognized pre-processor directive: #%s",
841 cstring_fromChars (ol
)),
843 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
847 return FALSE
; /* evans 2001-12-30: was: TRUE; */
854 int cscannerHelp_handleLlSpecial (void)
859 char *s
= mstring_createEmpty ();
865 loc
= fileloc_copy (g_currentloc
);
866 DPRINTF (("Handle special: %s", fileloc_unparse (loc
)));
868 while (((ic
= cscannerHelp_ninput ()) != 0) && isalpha (ic
))
871 s
= mstring_append (s
, c
);
875 DPRINTF (("Read: %s / %s", s
, fileloc_unparse (g_currentloc
)));
878 if (charsread
== 0 && ic
== (int) AFTER_COMMENT_MARKER
[0])
880 ic
= cscannerHelp_ninput ();
882 llassert (ic
== (int) AFTER_COMMENT_MARKER
[1]);
888 return QNOMODS
; /* special token no modifications token */
892 DPRINTF (("Coment marker: %s", os
));
893 tok
= commentMarkerToken (cstring_fromChars (os
));
897 s_tokLength
= charsread
;
902 s_whichSpecPart
= tok
;
906 DPRINTF (("Not a comment marker..."));
907 /* Add rest of the comment */
909 if (ic
!= 0 && ic
!= EOF
)
913 s
= mstring_append (s
, c
);
916 while (((ic
= cscannerHelp_ninput ()) != 0) && (ic
!= EOF
)
917 && (ic
!= (int) AFTER_COMMENT_MARKER
[0]))
921 /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
924 hasnl
= TRUE
; /* This prevents tokLength from being set later. */
929 message ("Likely parse error: syntactic comment token spans multiple lines: %s",
930 cstring_fromChars (s
)),
934 s
= mstring_append (s
, c
);
938 } /* spurious (?) warnings about s */
941 DPRINTF (("Read: %s / %s", s
, fileloc_unparse (g_currentloc
)));
943 if (ic
== (int) AFTER_COMMENT_MARKER
[0])
945 int nc
= cscannerHelp_ninput ();
946 llassert ((char) nc
== AFTER_COMMENT_MARKER
[1]);
952 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
957 if (*s
== '-' || *s
== '+' || *s
== '=') /* setting flags */
961 while (c
== '-' || c
== '+' || c
== '=')
963 ynm set
= ynm_fromCodeChar (c
);
968 thisflag
= cstring_fromChars (s
);
970 while ((c
= *s
) != '\0' && (c
!= '-') && (c
!= '=')
971 && (c
!= '+') && (c
!= ' ') && (c
!= '\t') && (c
!= '\n'))
978 if (!context_getFlag (FLG_NOCOMMENTS
))
980 cstring flagname
= thisflag
;
981 flagcode fflag
= flags_identifyFlag (flagname
);
983 if (flagcode_isSkip (fflag
))
987 else if (flagcode_isModeName (fflag
))
989 if (ynm_isMaybe (set
))
994 ("Semantic comment attempts to restore flag %s. "
995 "A mode flag cannot be restored.",
1000 context_setMode (flagname
);
1003 else if (flagcode_isInvalid (fflag
))
1006 (FLG_UNRECOGFLAGCOMMENTS
,
1007 message ("Unrecognized option in semantic comment: %s",
1011 else if (flagcode_isGlobalFlag (fflag
))
1016 ("Semantic comment attempts to set global flag %s. "
1017 "A global flag cannot be set locally.",
1023 context_fileSetFlag (fflag
, set
, loc
);
1025 if (flagcode_hasArgument (fflag
))
1027 if (ynm_isMaybe (set
))
1032 ("Semantic comment attempts to restore flag %s. "
1033 "A flag for setting a value cannot be restored.",
1038 { /* cut-and-pastied from llmain...blecch */
1039 cstring extra
= cstring_undefined
;
1045 rest
= mstring_copy (s
);
1049 while ((rchar
= *rest
) != '\0'
1050 && (isspace (rchar
)))
1056 while ((rchar
= *rest
) != '\0'
1057 && !isspace (rchar
))
1059 extra
= cstring_appendChar (extra
, rchar
);
1063 s
--; /* evans 2002-07-12: this was previously only in the else branch.
1064 Leads to an invalid read on the true branch.
1069 if (cstring_isUndefined (extra
))
1074 ("Flag %s (in semantic comment) must be followed by an argument",
1075 flagcode_unparse (fflag
)));
1077 cstring_free (extra
);
1081 if (flagcode_hasNumber (fflag
))
1083 flags_setValueFlag (fflag
, extra
);
1085 else if (flagcode_hasChar (fflag
))
1087 flags_setValueFlag (fflag
, extra
);
1089 else if (flagcode_hasString (fflag
))
1091 flags_setStringFlag (fflag
, extra
);
1095 cstring_free (extra
);
1109 while ((c
== ' ') || (c
== '\t') || (c
== '\n'))
1115 if (context_inHeader () && !isArtificial (cstring_fromChars (os
)))
1117 DPRINTF (("Here adding comment: %s", os
));
1118 context_addComment (cstring_fromCharsNew (os
), loc
);
1130 annotationInfo ainfo
;
1132 while (*s
!= '\0' && *s
!= ' ' && *s
!= '\t' && *s
!= '\n')
1144 t
= cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t
)));
1145 macrocode
= tokenMacroCode (cstring_fromChars (t
));
1147 if (macrocode
!= BADTOK
)
1149 s_tokLength
= hasnl
? 0 : size_toInt (mstring_length (t
));
1155 if (macrocode
== SKIPTOK
)
1163 ainfo
= context_lookupAnnotation (cstring_fromChars (os
));
1165 if (annotationInfo_isDefined (ainfo
)) {
1166 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo
)));
1167 c_lval
.annotation
= ainfo
;
1175 if (context_inHeader ())
1182 if ((context_inMacro () || context_inGlobalContext ())
1183 && macrocode
!= SKIPTOK
1184 && !isArtificial (cstring_fromChars (os
)))
1186 if (context_processingMacros ())
1188 /* evans 2002-02-24: don't add comments when procssing macros */
1192 context_addComment (cstring_fromCharsNew (os
), loc
);
1206 if (mstring_equal (t
, "ignore"))
1208 if (!context_getFlag (FLG_NOCOMMENTS
))
1210 context_enterSuppressRegion (loc
);
1213 else if ((*t
== 'i' || *t
== 't')
1214 && (*(t
+ 1) == '\0'))
1216 if (!context_getFlag (FLG_NOCOMMENTS
)
1217 && (*t
== 'i' || context_getFlag (FLG_TMPCOMMENTS
)))
1219 context_enterSuppressLine (-1, loc
); /* infinite suppression */
1222 else if (((*t
== 'i') || (*t
== 't'))
1223 && ((*(t
+ 1) >= '0' && *(t
+ 1) <= '9')))
1225 bool tmpcomment
= (*t
== 't');
1227 char *tt
= t
; /* don't mangle t, since it is free'd */
1230 if (lc
>= '0' && lc
<= '9')
1232 val
= (int)(lc
- '0');
1235 while (lc
>= '0' && lc
<= '9')
1238 val
+= (int) (lc
- '0');
1243 if (!context_getFlag (FLG_NOCOMMENTS
)
1244 && (!tmpcomment
|| context_getFlag (FLG_TMPCOMMENTS
)))
1246 DPRINTF (("Here: enter suppress: %s", fileloc_unparse (loc
)));
1247 context_enterSuppressLine (val
, loc
);
1250 else if (mstring_equal (t
, "end"))
1252 if (!context_getFlag (FLG_NOCOMMENTS
))
1254 context_exitSuppressRegion (loc
);
1257 else if (mstring_equal (t
, "notfunction"))
1259 ; /* handled by pcpp */
1261 else if (mstring_equal (t
, "access"))
1267 while (((c
= *s
) != '\0') && (c
== ' ' || c
== '\t' || c
== '\n'))
1277 tname
= cstring_fromChars (s
);
1279 while ((c
= *s
) != '\0' && c
!= ' '
1280 && c
!= '\t' && c
!= '\n' && c
!= ',')
1287 DPRINTF (("Access %s", tname
));
1289 if (!context_getFlag (FLG_NOCOMMENTS
)
1290 && !context_getFlag (FLG_NOACCESS
))
1292 if (usymtab_existsType (tname
))
1294 typeId uid
= usymtab_getTypeId (tname
);
1295 uentry ue
= usymtab_getTypeEntry (uid
);
1297 if (uentry_isAbstractDatatype (ue
))
1299 context_addFileAccessType (uid
);
1300 DPRINTF (("Adding access to: %s / %d", tname
, uid
));
1307 ("Non-abstract type %s used in access comment",
1314 if (!(context_inSuppressRegion ()
1315 || context_inSuppressZone (loc
)))
1320 ("Unrecognized type %s used in access comment",
1332 if (c
!= ',' && c
!= ' ')
1338 else if (mstring_equal (t
, "noaccess"))
1345 while (((lc
= *s
) != '\0') && (lc
== ' ' || lc
== '\t' || lc
== '\n'))
1355 tname
= cstring_fromChars (s
);
1357 while ((lc
= *s
) != '\0' && lc
!= ' ' && lc
!= '\t'
1358 && lc
!= '\n' && lc
!= ',')
1365 if (!context_getFlag (FLG_NOCOMMENTS
)
1366 && !context_getFlag (FLG_NOACCESS
))
1368 if (usymtab_existsType (tname
))
1370 typeId tuid
= usymtab_getTypeId (tname
);
1372 if (context_couldHaveAccess (tuid
))
1374 DPRINTF (("Removing access: %s", tname
));
1375 context_removeFileAccessType (tuid
);
1379 if (!(context_inSuppressRegion ()
1380 || context_inSuppressZone (loc
)))
1382 uentry ue
= usymtab_getTypeEntry (tuid
);
1384 if (uentry_isAbstractDatatype (ue
))
1389 ("Non-accessible abstract type %s used in noaccess comment",
1398 ("Non-abstract type %s used in noaccess comment",
1407 if (!(context_inSuppressRegion ()
1408 || context_inSuppressZone (loc
)))
1413 ("Unrecognized type %s used in noaccess comment",
1425 if (lc
!= ',' && lc
!= ' ')
1433 voptgenerror (FLG_UNRECOGCOMMENTS
,
1434 message ("Semantic comment unrecognized: %s",
1435 cstring_fromChars (os
)),
1438 } /* spurious (?) warning about t */
1449 /*@only@*/ cstring
cscannerHelp_makeIdentifier (char *s
)
1451 char *c
= mstring_create (strlen (s
));
1452 cstring id
= cstring_fromChars (c
);
1454 while (isalnum (*s
) || (*s
== '_') || (*s
== '$'))
1464 /*@observer@*/ /*@dependent@*/ uentry
cscannerHelp_coerceId (cstring cn
)
1466 if (!(usymtab_exists (cn
)))
1468 fileloc loc
= fileloc_createExternal ();
1471 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
1474 uentry ce
= uentry_makeUnrecognized (cn
, loc
);
1476 if (!context_inIterEnd ())
1480 message ("Unrecognized (possibly system) identifier: %q",
1481 uentry_getName (ce
)),
1488 return (usymtab_lookup (cn
));
1492 ** like, cscannerHelp_coerceId, but doesn't supercede for iters
1495 /*@observer@*/ uentry
cscannerHelp_coerceIterId (cstring cn
)
1497 if (!(usymtab_exists (cn
)))
1499 return uentry_undefined
;
1502 return (usymtab_lookup (cn
));
1504 # endif /* DEADCODE */
1507 ** Need to keep this in case there is a declaration that isn't processed until
1508 ** the scope exits. Would be good to rearrange the symbol table so this doesn't
1509 ** happen, and save all the cstring copying.
1512 /*@observer@*/ cstring
cscannerHelp_observeLastIdentifier (void)
1514 cstring res
= s_lastidprocessed
;
1518 static void cscanner_setLastIdentifier (/*@keep@*/ cstring id
) /*@modifies s_lastidprocessed@*/
1520 if (cstring_isDefined (s_lastidprocessed
))
1522 cstring_free (s_lastidprocessed
);
1525 s_lastidprocessed
= id
;
1529 cscannerHelp_processIdentifier (/*@only@*/ cstring id
)
1530 /*@modifies internalState@*/
1534 if (context_getFlag (FLG_GRAMMAR
))
1536 lldiagmsg (message ("Process identifier: %s", id
));
1539 context_clearJustPopped ();
1540 cscanner_setLastIdentifier (id
);
1542 DPRINTF (("Context: %s", context_unparse ()));
1544 if (context_inFunctionHeader ())
1547 annotationInfo ainfo
;
1549 DPRINTF (("in function decl: %s", id
));
1551 tok
= commentMarkerToken (id
);
1554 s_inSpecPart
= TRUE
;
1555 s_whichSpecPart
= tok
;
1559 tok
= tokenMacroCode (id
);
1560 if (tok
!= BADTOK
&& !cscannerHelp_isSpecTokenRegularId(tok
))
1565 if (s_expectingMetaStateName
)
1567 metaStateInfo msinfo
= context_lookupMetaStateInfo (id
);
1568 if (metaStateInfo_isDefined (msinfo
))
1570 c_lval
.msinfo
= msinfo
;
1571 return METASTATE_NAME
;
1575 DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id
)));
1579 ainfo
= context_lookupAnnotation (id
);
1580 if (annotationInfo_isDefined (ainfo
))
1582 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo
)));
1583 c_lval
.annotation
= ainfo
;
1588 DPRINTF (("Not annotation: %s", id
));
1592 DPRINTF (("Here!"));
1594 if (context_getFlag (FLG_GNUEXTENSIONS
))
1598 if (cstring_equalLit (id
, "__stdcall")
1599 || cstring_equalLit (id
, "__cdecl")
1600 || cstring_equalLit (id
, "__extension__"))
1604 else if (cstring_equalLit (id
, "__volatile__"))
1608 else if (cstring_equalLit (id
, "__const__"))
1612 else if (cstring_equalLit (id
, "__alignof__"))
1614 tok
= CALIGNOF
; /* alignof is parsed like sizeof */
1616 else if (cstring_equalLit (id
, "__typeof__")
1617 || cstring_equalLit (id
, "typeof"))
1621 else if (cstring_equalLit (id
, "__FUNCTION__")
1622 || cstring_equalLit (id
, "__PRETTY_FUNCTION__"))
1624 return cscannerHelp_returnFunctionName (id
);
1626 else if (cstring_equalLit (id
, "__attribute__")
1627 || cstring_equalLit (id
, "__asm__")
1628 || cstring_equalLit (id
, "_asm")
1629 || cstring_equalLit (id
, "__asm")
1630 || cstring_equalLit (id
, "__declspec"))
1633 bool useparens
= FALSE
;
1634 bool usebraces
= FALSE
;
1635 bool inquote
= FALSE
;
1636 bool inescape
= FALSE
;
1639 while ((ic
= cscanner_input ()) != EOF
)
1641 char cc
= (char) ic
;
1647 else if (cc
== '\\')
1651 else if (cc
== '\"')
1687 else if (cc
== ')' && useparens
)
1690 if (depth
== 0) break;
1692 else if (cc
== '}' && usebraces
)
1695 if (depth
== 0) break;
1698 && !usebraces
&& !useparens
1699 && cstring_equalLit (id
, "__asm"))
1702 ** We need this because some MS VC++ include files
1703 ** have __asm mov ... }
1704 ** Its a kludge, but otherwise would need to parse
1721 context_incLineno ();
1723 if (cstring_equalLit (id
, "__asm")
1724 && !useparens
&& !usebraces
)
1731 llassert ((useparens
&& ic
== (int) ')')
1732 || (usebraces
&& ic
== (int) '}')
1733 || (!useparens
&& !usebraces
));
1737 else if (cstring_equalLit (id
, "__inline__")
1738 || cstring_equalLit (id
, "__inline")
1739 || cstring_equalLit (id
, "_inline"))
1750 return (cscannerHelp_returnToken (tok
));
1754 le
= usymtab_lookupSafe (id
);
1756 /*@-dependenttrans@*/
1758 if (uentry_isIter (le
))
1763 else if (uentry_isEndIter (le
))
1766 return (ITER_ENDNAME
);
1768 else if (uentry_isUndefined (le
))
1770 c_lval
.cname
= cstring_copy (id
);
1771 return (NEW_IDENTIFIER
);
1773 else if (!uentry_isDeclared (le
) && !uentry_isCodeDefined (le
))
1775 if (uentry_isDatatype (le
))
1777 c_lval
.cname
= cstring_copy (id
);
1778 return (NEW_IDENTIFIER
);
1783 return (IDENTIFIER
);
1786 else if (uentry_isDatatype (le
))
1788 if (!s_expectingTypeName
)
1790 c_lval
.cname
= cstring_copy (id
);
1792 return (NEW_IDENTIFIER
);
1796 c_lval
.ctyp
= uentry_getAbstractType (le
);
1798 uentry_setUsed (le
, g_currentloc
);
1805 return (IDENTIFIER
);
1808 /*@=dependenttrans@*/
1811 bool cscannerHelp_processHashIdentifier (/*@only@*/ cstring id
)
1813 if (context_inMacro () || context_inIterDef () ||
1814 context_inIterEnd ())
1818 context_clearJustPopped ();
1820 le
= usymtab_lookupSafe (id
);
1821 cscanner_setLastIdentifier (id
);
1823 if (uentry_isParam (le
) || uentry_isRefParam (le
))
1835 ** Will be handled by handleLlSpecial
1844 * states & input classes needed for constant string processing automata;
1847 * should be defined inside process_stringLiteral(), but Splint has problems
1848 * with dumping when enumeration data types are defined inside procedures.
1857 str_errnul
, /* special treatement for null character error */
1869 static /*@only@*/ /*@notnull@*/ cstring
1870 process_stringLiteral (const /*@notnull@*/ char* in
, size_t inlen
)
1873 * in expected to be of the form "..."[(( \t\n)*"...")*]
1875 * - strip leading & trailing '\"' of each individual constant string;
1876 * - handle possible null characters inside constant string;
1877 * - if there are more then one constant strings, merge them [strip white
1878 * space between them].
1885 enum str_state state
;
1887 static const enum str_state automata
[str_ok
+1][ch_other
+1] = {
1888 /* null quote escape white other */
1889 /* init */ { str_errfmt
, str_inside
, str_errfmt
, str_errfmt
, str_errfmt
},
1890 /* inside */ { str_errnul
, str_ok
, str_escape
, str_inside
, str_inside
},
1891 /* escape */ { str_errnul
, str_inside
, str_inside
, str_inside
, str_inside
},
1892 /* white */ { str_errfmt
, str_inside
, str_errfmt
, str_white
, str_errfmt
},
1893 /* ok */ { str_errfmt
, str_inside
, str_errfmt
, str_white
, str_errfmt
}
1897 llassertfatal (in
!= NULL
);
1899 out
= mstring_create (inlen
);
1904 /* no reason to continue once in error state */
1905 && !(state
== str_errnul
|| state
== str_errfmt
))
1907 enum str_state newstate
;
1912 case '\0': chi
= ch_null
; /*@switchbreak@*/ break;
1913 case '\"': chi
= ch_quote
; /*@switchbreak@*/ break;
1914 case '\\': chi
= ch_escape
; /*@switchbreak@*/ break;
1915 case '\n': col
= 0; context_incLineno ();
1918 case '\t': chi
= ch_white
; /*@switchbreak@*/ break;
1919 default : chi
= ch_other
; /*@switchbreak@*/ break;
1922 newstate
= automata
[state
][chi
];
1924 if ((newstate
== str_inside
|| newstate
== str_escape
) &&
1925 (state
== str_inside
|| state
== str_escape
))
1927 out
[outlen
] = in
[i
];
1937 if (!(state
== str_ok
|| state
== str_errnul
))
1939 llbug (message ("String literal has unexpected format"));
1943 if (state
== str_errnul
)
1945 /* FIXME: should add a flag contolling this, and transform message
1946 * into warning ... */
1947 llgenmsg (message ("Null character(s) present in string literal"),
1951 if (context_getFlag (FLG_STRINGLITERALLEN
) &&
1952 outlen
> size_fromInt (context_getValue (FLG_STRINGLITERALLEN
)))
1954 voptgenerror (FLG_STRINGLITERALLEN
,
1956 ("String literal length (%d) exceeds maximum "
1957 "length (%d): \"%s\"",
1958 size_toInt (outlen
),
1959 context_getValue (FLG_STRINGLITERALLEN
),
1960 cstring_fromChars (out
)),
1965 return cstring_fromChars (out
);
1968 /*@only@*/ exprNode
cscannerHelp_processString (void)
1970 fileloc loc
= fileloc_copy (g_currentloc
);
1971 return exprNode_stringLiteral (process_stringLiteral (c_text
, c_leng
), loc
);
1975 ** process a wide character string L"...."
1978 /*@only@*/ exprNode
cscannerHelp_processWideString (void)
1980 fileloc loc
= fileloc_copy (g_currentloc
);
1981 llassert (*c_text
== 'L');
1982 return exprNode_wideStringLiteral (process_stringLiteral (c_text
+1, c_leng
-1), loc
);
1985 char cscannerHelp_processChar (void)
1990 llassert (*c_text
!= '\0');
1991 fchar
= *(c_text
+ 1);
1992 if (fchar
!= '\\') return fchar
;
1994 next
= *(c_text
+ 2);
1998 case 'n': return '\n';
1999 case 't': return '\t';
2000 case '\"': return '\"';
2001 case '\'': return '\'';
2002 case '\\': return '\\';
2003 default: return '\0';
2007 double cscannerHelp_processFloat (void)
2009 double ret
= atof (c_text
);
2014 long cscannerHelp_processHex (void)
2019 llassert (c_text
[0] == '0'
2020 && (c_text
[1] == 'X' || c_text
[1] == 'x'));
2022 while (c_text
[index
] != '\0') {
2024 char c
= c_text
[index
];
2026 if (c
>= '0' && c
<= '9') {
2027 tval
= (int) c
- (int) '0';
2028 } else if (c
>= 'A' && c
<= 'F') {
2029 tval
= (int) c
- (int) 'A' + 10;
2030 } else if (c
>= 'a' && c
<= 'f') {
2031 tval
= (int) c
- (int) 'a' + 10;
2032 } else if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2034 while (c_text
[index
] != '\0') {
2035 if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2040 message ("Invalid character (%c) following specifier in hex constant: %s",
2041 c
, cstring_fromChars (c_text
)),
2051 message ("Invalid character (%c) in hex constant: %s",
2052 c
, cstring_fromChars (c_text
)),
2057 val
= (val
<< 4) + tval
;
2061 DPRINTF (("Hex constant: %s = %ld", c_text
, val
));
2065 long cscannerHelp_processOctal (void)
2070 llassert (c_text
[0] == '0' && c_text
[1] != 'X' && c_text
[1] != 'x');
2072 while (c_text
[index
] != '\0') {
2074 char c
= c_text
[index
];
2076 if (c
>= '0' && c
<= '7') {
2077 tval
= (int) c
- (int) '0';
2078 } else if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2080 while (c_text
[index
] != '\0') {
2081 if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2086 message ("Invalid character (%c) following specifier in octal constant: %s",
2087 c
, cstring_fromChars (c_text
)),
2097 message ("Invalid character (%c) in octal constant: %s",
2098 c
, cstring_fromChars (c_text
)),
2103 val
= (val
* 8) + tval
;
2107 DPRINTF (("Octal constant: %s = %ld", c_text
, val
));
2111 long cscannerHelp_processDec (void)
2113 return (atol (c_text
));
2116 /* Allow specificiation keywords to be used as identifiers in certain contexts. */
2117 static bool cscannerHelp_isSpecTokenRegularId (int tok
)
2124 if ( s_whichSpecPart
== QMODIFIES
2125 || s_whichSpecPart
== QDEFINES
2126 || s_whichSpecPart
== QUSES
2127 || s_whichSpecPart
== QALLOCATES
2128 || s_whichSpecPart
== QSETS
2129 || s_whichSpecPart
== QRELEASES
2130 || s_whichSpecPart
== QWARN
)
2135 if (s_whichSpecPart
== QGLOBALS
)
2137 if (!(tok
== QKILLED
|| tok
== QUNDEF
|| tok
== QOUT
|| tok
== QIN
|| tok
== QPARTIAL
))
2143 if (s_whichSpecPart
== QPRECLAUSE
|| s_whichSpecPart
== QPOSTCLAUSE
)
2145 if (!(tok
== QMAXSET
|| tok
== QMAXREAD
2146 /* uncomment the additional tests when minSet and minRead are supported */
2147 /* || tok == QMINREAD || tok == QMINSET */
2149 || tok
== QOBSERVER
|| tok
== QEXPOSED
2150 || tok
== QONLY
|| tok
== QSHARED
2151 || tok
== QOWNED
|| tok
== QDEPENDENT
2154 || tok
== QISNULL
|| tok
== QNULL
2155 || tok
== QNOTNULL
|| tok
== QRELNULL
2156 || tok
== QNULLTERMINATED
2158 /* || tok == QYIELD */
2159 /* || tok == QTEMP */
2160 /* || tok == QKEEP */
2161 /* || tok == QKEPT */
2168 /* Specification parts not handled (they require a more complex solution
2169 * then this simple hack): QCONSTANT, QFUNCTION, QITER & QALT. */
2174 int cscannerHelp_processSpec (int tok
)
2176 size_t length
= strlen (c_text
);
2178 if (!cscannerHelp_isSpecTokenRegularId (tok
))
2180 cscannerHelp_setTokLengthT (length
);
2181 return cscannerHelp_returnToken (tok
);
2184 context_saveLocation ();
2185 cscannerHelp_setTokLengthT (length
);
2186 return (cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (c_text
)));
2189 void cscannerHelp_expectingMetaStateName (void)
2191 llassert (!s_expectingMetaStateName
);
2192 llassert (context_inFunctionHeader ());
2193 s_expectingMetaStateName
= TRUE
;
2196 void cscannerHelp_clearExpectingMetaStateName (void)
2198 llassert (s_expectingMetaStateName
);
2199 s_expectingMetaStateName
= FALSE
;
2202 bool cscannerHelp_processMacro (void)
2207 cstring fname
= cstring_undefined
;
2209 bool isspecfcn
= FALSE
;
2210 bool isiter
= FALSE
;
2211 bool skipparam
= FALSE
;
2212 bool unknownm
= FALSE
;
2213 bool hasParams
= FALSE
;
2214 bool emptyMacro
= FALSE
;
2215 char c
= skip_whitespace ();
2216 fileloc loc
= fileloc_noColumn (g_currentloc
);
2218 /* are both of these necessary? what do they mean? */
2219 uentryList specparams
= uentryList_undefined
;
2220 uentryList pn
= uentryList_undefined
;
2222 context_resetMacroMissingParams ();
2224 if (c
== '\0' || c
== '\n')
2226 llcontbug (cstring_makeLiteral ("Bad macro"));
2231 fname
= cstring_appendChar (fname
, c
);
2233 while ((c
= macro_nextChar ()) != '(' && c
!= '\0'
2234 && c
!= ' ' && c
!= '\t' && c
!= '\n')
2236 fname
= cstring_appendChar (fname
, c
);
2239 if (c
== ' ' || c
== '\t' || c
== '\n')
2245 while (c
== ' ' || c
== '\t')
2247 c
= macro_nextChar ();
2249 cscanner_unput ((int) c
);
2255 cscanner_unput ((int) c
);
2261 hasParams
= (c
== '(');
2263 if (usymtab_exists (fname
))
2265 e2
= usymtab_lookupExpose (fname
);
2266 ct
= uentry_getType (e2
);
2268 if (uentry_isCodeDefined (e2
)
2269 && fileloc_isUser (uentry_whereDefined (e2
)))
2273 message ("Macro %s already defined", fname
),
2276 uentry_showWhereDefined (e2
);
2277 uentry_clearDefined (e2
);
2280 if (uentry_isFunction (e2
))
2282 uentry_setType (e2
, ctype_unknown
);
2285 context_enterUnknownMacro (e2
);
2289 context_enterConstantMacro (e2
);
2292 else if (uentry_isForward (e2
) && uentry_isFunction (e2
))
2299 ("Parameterized macro has no prototype or specification: %s ",
2304 uentry_setType (e2
, ctype_unknown
);
2305 uentry_setFunctionDefined (e2
, loc
);
2306 uentry_setUsed (e2
, fileloc_undefined
);
2307 context_enterUnknownMacro (e2
);
2309 else if (uentry_isIter (e2
))
2312 specparams
= uentry_getParams (e2
);
2313 noparams
= uentryList_size (specparams
);
2314 uentry_setDefined (e2
, loc
);
2315 context_enterIterDef (e2
);
2317 else if (uentry_isEndIter (e2
))
2319 uentry_setDefined (e2
, loc
);
2320 context_enterIterEnd (e2
); /* don't care about it now */
2321 /* but should parse like an iter! */
2323 else if (uentry_isEitherConstant (e2
))
2329 message ("Constant %s implemented as parameterized macro",
2333 uentry_showWhereSpecified (e2
);
2334 uentry_setType (e2
, ctype_unknown
);
2335 uentry_makeConstantFunction (e2
);
2336 uentry_setDefined (e2
, g_currentloc
);
2337 uentry_setFunctionDefined (e2
, g_currentloc
);
2338 context_enterUnknownMacro (e2
);
2342 if (!uentry_isSpecified (e2
))
2344 fileloc oloc
= uentry_whereDeclared (e2
);
2346 if (fileloc_isLib (oloc
))
2350 else if (fileloc_isUndefined (oloc
)
2351 || fileloc_isPreproc (oloc
))
2356 (FLG_MACROCONSTDECL
,
2358 ("Macro constant %q not declared",
2359 uentry_getName (e2
)),
2363 else if (!fileloc_withinLines (oloc
, loc
, 2))
2364 { /* bogus! will give errors if there is too much whitespace */
2366 (FLG_MACROCONSTDIST
,
2368 ("Macro constant name %s matches name in "
2369 "distant constant declaration. This constant "
2370 "is declared at %q", fname
,
2371 fileloc_unparse (oloc
)),
2380 context_enterConstantMacro (e2
);
2381 cstring_free (fname
);
2386 else if (ctype_isFunction (ct
))
2389 specparams
= ctype_argsFunction (ct
);
2390 noparams
= uentryList_size (specparams
);
2392 uentry_setFunctionDefined (e2
, loc
);
2393 context_enterMacro (e2
);
2395 else if (uentry_isVar (e2
))
2401 message ("Variable %s implemented as parameterized macro",
2405 uentry_showWhereSpecified (e2
);
2406 uentry_setType (e2
, ctype_unknown
);
2407 uentry_makeVarFunction (e2
);
2408 uentry_setDefined (e2
, g_currentloc
);
2409 uentry_setFunctionDefined (e2
, g_currentloc
);
2410 context_enterUnknownMacro (e2
);
2414 uentry ucons
= uentry_makeConstant (fname
,
2417 if (uentry_isExpandedMacro (e2
))
2425 message ("Variable %s implemented by a macro",
2429 uentry_showWhereSpecified (e2
);
2433 uentry_setDefined (e2
, loc
);
2434 uentry_setUsed (ucons
, loc
);
2436 context_enterConstantMacro (ucons
);
2437 uentry_markOwned (ucons
);
2438 cstring_free (fname
);
2442 else if (uentry_isDatatype (e2
))
2446 message ("Type implemented as macro: %x",
2447 uentry_getName (e2
)),
2448 message ("A type is implemented using a macro definition. A "
2449 "typedef should be used instead."),
2452 cscannerHelp_swallowMacro ();
2453 /* Must exit scope (not sure why a new scope was entered?) */
2454 usymtab_quietExitScope (g_currentloc
);
2455 uentry_setDefined (e2
, g_currentloc
);
2461 (message ("Unexpanded macro not function or constant: %q",
2462 uentry_unparse (e2
)));
2463 uentry_setType (e2
, ctype_unknown
);
2467 uentry_makeVarFunction (e2
);
2468 uentry_setDefined (e2
, g_currentloc
);
2469 uentry_setFunctionDefined (e2
, g_currentloc
);
2470 context_enterUnknownMacro (e2
);
2478 /* evans 2001-09-09 - if it has params, assume a function */
2482 (FLG_MACROMATCHNAME
,
2483 message ("Unexpanded macro %s does not match name of a declared "
2484 "function. The name used in the control "
2485 "comment on the previous line should match.",
2489 ce
= uentry_makeFunction (fname
, ctype_unknown
,
2493 warnClause_undefined
,
2495 uentry_setUsed (ce
, loc
); /* perhaps bogus? */
2496 e2
= usymtab_supEntryReturn (ce
);
2497 context_enterUnknownMacro (e2
);
2502 (FLG_MACROMATCHNAME
,
2503 message ("Unexpanded macro %s does not match name of a constant "
2504 "or iter declaration. The name used in the control "
2505 "comment on the previous line should match. "
2506 "(Assuming macro defines a constant.)",
2510 ce
= uentry_makeConstant (fname
, ctype_unknown
, fileloc_undefined
);
2511 uentry_setUsed (ce
, loc
); /* perhaps bogus? */
2512 e2
= usymtab_supEntryReturn (ce
);
2514 context_enterConstantMacro (e2
);
2515 cstring_free (fname
);
2521 /* in macros, ( must follow immediatetly after name */
2527 c
= skip_whitespace ();
2529 while (c
!= ')' && c
!= '\0')
2532 bool suppress
= context_inSuppressRegion ();
2533 cstring paramname
= cstring_undefined
;
2536 ** save the parameter location
2540 context_saveLocation ();
2543 while (c
!= ' ' && c
!= '\t' && c
!= ',' && c
!= '\0' && c
!= ')')
2545 paramname
= cstring_appendChar (paramname
, c
);
2546 c
= macro_nextChar ();
2549 if (c
== ' ' || c
== '\t') c
= skip_whitespace ();
2553 c
= macro_nextChar ();
2554 if (c
== ' ' || c
== '\t') c
= skip_whitespace ();
2559 llfatalerror (cstring_makeLiteral
2560 ("Bad macro syntax: uentryList"));
2563 if ((isspecfcn
|| isiter
) && (paramno
< noparams
)
2564 && !uentry_isElipsisMarker (uentryList_getN
2565 (specparams
, paramno
)))
2567 fileloc sloc
= context_getSaveLocation ();
2568 uentry decl
= uentryList_getN (specparams
, paramno
);
2571 param
= uentry_nameCopy (paramname
, decl
);
2573 uentry_setParam (param
);
2574 sr
= sRef_makeParam (paramno
, uentry_getType (param
),
2575 stateInfo_makeLoc (sloc
, SA_DECLARED
));
2577 if (sRef_getNullState (sr
) == NS_ABSNULL
)
2579 ctype pt
= ctype_realType (uentry_getType (param
));
2581 if (ctype_isUser (pt
))
2583 uentry te
= usymtab_getTypeEntrySafe (ctype_typeId (pt
));
2585 if (uentry_isValid (te
))
2587 sRef_setStateFromUentry (sr
, te
);
2592 sRef_setNullState (sr
, NS_UNKNOWN
, sloc
);
2596 uentry_setSref (param
, sr
);
2597 uentry_setDeclaredForceOnly (param
, sloc
);
2599 skipparam
= isiter
&& uentry_isOut (uentryList_getN (specparams
, paramno
));
2603 fileloc sloc
= context_getSaveLocation ();
2605 param
= uentry_makeVariableSrefParam
2606 (paramname
, ctype_unknown
, fileloc_copy (sloc
),
2607 sRef_makeParam (paramno
, ctype_unknown
,
2608 stateInfo_makeLoc (sloc
, SA_DECLARED
)));
2609 DPRINTF (("Unknown param: %s", uentry_unparseFull (param
)));
2610 cstring_free (paramname
);
2612 sRef_setPosNull (uentry_getSref (param
), sloc
);
2613 uentry_setDeclaredForce (param
, sloc
);
2616 fileloc_free (sloc
);
2621 llassert (!uentry_isElipsisMarker (param
));
2625 sRef_makeUnsafe (uentry_getSref (param
));
2628 pn
= uentryList_add (pn
, uentry_copy (param
));
2629 usymtab_supEntry (param
);
2633 /* don't add param */
2634 uentry_free (param
);
2639 (void) macro_nextChar ();
2640 c
= skip_whitespace ();
2648 if (isspecfcn
|| isiter
)
2650 if (paramno
!= noparams
&& noparams
>= 0)
2652 cscannerHelp_advanceLine ();
2656 message ("Macro %s specified with %d args, defined with %d",
2657 fname
, noparams
, paramno
),
2660 uentry_showWhereSpecified (e2
);
2661 uentry_resetParams (e2
, pn
);
2666 uentry_resetParams (e2
, pn
);
2673 ** the form should be:
2675 ** # define newname oldname
2676 ** where oldname refers to a function matching the specification
2682 sRef_setGlobalScope ();
2683 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname
, ctype_unknown
));
2684 sRef_clearGlobalScope ();
2688 context_setMacroMissingParams ();
2693 /* context_setuentryList (pn); */
2694 usymtab_enterScope ();
2697 cstring_free (fname
);
2702 void cscannerHelp_setTokLength (int len
)
2706 DPRINTF (("Set tok length: %d", len
));
2709 void cscannerHelp_setTokLengthT (size_t len
)
2711 cscannerHelp_setTokLength (size_toInt (len
));
2714 static void cscannerHelp_advanceLine (void)
2720 int cscannerHelp_returnToken (int t
)
2722 if (s_tokLength
> fileloc_column (g_currentloc
)) {
2723 c_lval
.tok
= lltok_create (t
, fileloc_copy (g_currentloc
));
2725 c_lval
.tok
= lltok_create (t
, fileloc_decColumn (g_currentloc
, s_tokLength
));
2732 int cscannerHelp_returnTokenLength (int t
, int length
)
2734 cscannerHelp_setTokLength (length
);
2735 return cscannerHelp_returnToken (t
);
2738 int cscannerHelp_returnString (cstring s
)
2740 c_lval
.expr
= exprNode_stringLiteral (s
, fileloc_decColumn (g_currentloc
, s_tokLength
));
2745 int cscannerHelp_returnInt (ctype ct
, long val
)
2749 if (ctype_equal (ct
, ctype_int
))
2753 c
= context_typeofZero ();
2757 c
= context_typeofOne ();
2765 c_lval
.expr
= exprNode_numLiteral (c
, cstring_fromChars (c_text
),
2766 fileloc_decColumn (g_currentloc
, s_tokLength
),
2772 int cscannerHelp_returnFloat (ctype ct
, double f
)
2774 c_lval
.expr
= exprNode_floatLiteral (f
, ct
, cstring_fromChars (c_text
),
2775 fileloc_decColumn (g_currentloc
, s_tokLength
));
2780 int cscannerHelp_returnChar (char c
)
2782 c_lval
.expr
= exprNode_charLiteral (c
, cstring_fromChars (c_text
),
2783 fileloc_decColumn (g_currentloc
, s_tokLength
));
2788 int cscannerHelp_returnType (int tok
, ctype ct
)
2795 int cscannerHelp_returnExpr (exprNode e
)
2802 /* Should hold the name of the current function as string; instead it just
2803 * saves the (literal) value of the token ... */
2804 int cscannerHelp_returnFunctionName (cstring id
)
2806 c_lval
.expr
= exprNode_makeConstantString (id
,
2807 fileloc_decColumn (g_currentloc
, s_tokLength
));
2812 void cscannerHelp_setExpectingTypeName (void)
2814 s_expectingTypeName
= TRUE
;
2817 void cscannerHelp_clearExpectingTypeName (void)
2819 s_expectingTypeName
= FALSE
;
2823 bool cscannerHelp_isExpectingTypeName (void)
2825 return s_expectingTypeName
;
2827 # endif /* DEADCODE */
2829 int cscannerHelp_processTextIdentifier (char *text
)
2831 context_saveLocation ();
2832 cscannerHelp_setTokLength (size_toInt (mstring_length (text
)));
2833 return cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (text
));
2836 static bool s_continueLine
= FALSE
;
2838 int cscannerHelp_handleNewLine (void)
2840 context_incLineno ();
2842 if (s_tokLength
!= 0) {
2844 /* No error to report
2847 message ("Likely parse error: token spans multiple lines."),
2854 s_continueLine
= FALSE
;
2858 if (context_inMacro ())
2860 /* Don't use return cscannerHelp_returnToken */
2861 /* !!! evans 2002-03-13 */
2862 c_lval
.tok
= lltok_create (TENDMACRO
, fileloc_copy (g_currentloc
));
2870 void cscannerHelp_setContinueLine (void)
2872 s_continueLine
= TRUE
;
2875 void cscannerHelp_exitSpecPart (void)
2877 llassert (s_inSpecPart
);
2878 s_inSpecPart
= FALSE
;
2879 s_whichSpecPart
= BADTOK
;