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 { "setBufferSize", QSETBUFFERSIZE
},
75 { "setStringLength", QSETSTRINGLENGTH
},
76 { "testinRange", QTESTINRANGE
},
77 { "requires", QPRECLAUSE
} ,
78 { "ensures", QPOSTCLAUSE
} ,
79 { "invariant", QINVARIANT
} ,
84 ** These tokens are either stand-alone tokens, or followed by
85 ** token-specific text.
88 static struct skeyword s_keytable
[] = {
89 { "anytype", QANYTYPE
} ,
90 { "integraltype", QINTEGRALTYPE
} ,
91 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE
} ,
92 { "signedintegraltype", QSIGNEDINTEGRALTYPE
} ,
97 { "dependent", QDEPENDENT
} ,
98 { "partial", QPARTIAL
} ,
99 { "special", QSPECIAL
} ,
100 { "truenull", QTRUENULL
} ,
101 { "falsenull", QFALSENULL
} ,
102 { "nullwhentrue", QTRUENULL
} ,
103 { "falsewhennull", QFALSENULL
} ,
106 { "notnull", QNOTNULL
} ,
107 { "abstract", QABSTRACT
} ,
108 { "numabstract", QNUMABSTRACT
} ,
109 { "concrete", QCONCRETE
} ,
110 { "mutable", QMUTABLE
} ,
111 { "immutable", QIMMUTABLE
} ,
112 { "unused", QUNUSED
} ,
113 { "external", QEXTERNAL
} ,
115 { "unique", QUNIQUE
} ,
116 { "returned", QRETURNED
} ,
117 { "exposed", QEXPOSED
} ,
118 { "refcounted", QREFCOUNTED
} ,
120 { "newref", QNEWREF
} ,
121 { "tempref", QTEMPREF
} ,
122 { "killref", QKILLREF
} ,
124 { "relnull", QRELNULL
} ,
125 { "nullterminated", QNULLTERMINATED
},
126 { "setBufferSize", QSETBUFFERSIZE
},
127 { "testInRange", QTESTINRANGE
},
128 { "isnull", QISNULL
},
129 { "MaxSet", QMAXSET
},
130 { "MaxRead", QMAXREAD
},
131 { "maxSet", QMAXSET
},
132 { "maxRead", QMAXREAD
},
133 { "reldef", QRELDEF
} ,
134 { "observer", QOBSERVER
} ,
135 { "exits", QEXITS
} ,
136 { "noreturn", QEXITS
} ,
137 { "mayexit", QMAYEXIT
} ,
138 { "maynotreturn", QMAYEXIT
} ,
139 { "trueexit", QTRUEEXIT
} ,
140 { "falseexit", QFALSEEXIT
} ,
141 { "noreturnwhentrue", QTRUEEXIT
} ,
142 { "noreturnwhenfalse", QFALSEEXIT
} ,
143 { "neverexit", QNEVEREXIT
} ,
144 { "alwaysreturns", QNEVEREXIT
} ,
146 { "shared", QSHARED
} ,
148 { "unchecked", QUNCHECKED
} ,
149 { "checked", QCHECKED
} ,
150 { "checkmod", QCHECKMOD
} ,
151 { "checkedstrict", QCHECKEDSTRICT
} ,
152 { "innercontinue", QINNERCONTINUE
} ,
153 { "innerbreak", QINNERBREAK
} ,
154 { "loopbreak", QLOOPBREAK
} ,
155 { "switchbreak", QSWITCHBREAK
} ,
156 { "safebreak", QSAFEBREAK
} ,
157 { "fallthrough", QFALLTHROUGH
} ,
158 { "l_fallthrou", QLINTFALLTHROUGH
} ,
159 { "l_fallth", QLINTFALLTHRU
} ,
160 { "notreached", QNOTREACHED
} ,
161 { "l_notreach", QLINTNOTREACHED
} ,
162 { "printflike", QPRINTFLIKE
} ,
163 { "l_printfli", QLINTPRINTFLIKE
} ,
164 { "scanflike", QSCANFLIKE
} ,
165 { "messagelike", QMESSAGELIKE
} ,
166 { "l_argsus", QARGSUSED
} ,
170 static bool cscannerHelp_isConstraintToken (int p_tok
) /*@*/ ;
171 static void cscannerHelp_advanceLine (void) /*@modifies g_currentloc, internalState@*/ ;
174 ** would be better if these weren't hard coded...
177 static bool isArtificial (cstring s
)
179 return (cstring_equalLit (s
, "modifies")
180 || cstring_equalLit (s
, "globals")
181 || cstring_equalLit (s
, "warn")
182 || cstring_equalLit (s
, "alt"));
185 void cscannerHelp_swallowMacro (void)
188 bool skipnext
= FALSE
;
190 while ((i
= lminput ()) != EOF
)
206 reader_checkUngetc (i
, c_in
);
218 reader_checkUngetc (i
, c_in
);
222 static int commentMarkerToken (cstring s
)
226 while (s_parsetable
[i
].name
!= NULL
)
228 DPRINTF (("Try :%s:%s:", s
, s_parsetable
[i
].name
));
230 if (cstring_equalLit (s
, s_parsetable
[i
].name
))
232 return s_parsetable
[i
].token
;
241 static int tokenMacroCode (cstring s
)
245 while (s_keytable
[i
].name
!= NULL
)
247 if (cstring_equalLit (s
, s_keytable
[i
].name
))
249 if (s_keytable
[i
].token
== QLINTFALLTHROUGH
)
252 (FLG_WARNLINTCOMMENTS
,
254 ("Traditional lint comment /*FALLTHROUGH*/ used. "
255 "Splint interprets this in the same way as most Unix lints, but it is "
256 "preferable to replace it with the /*@fallthrough@*/ "
261 else if (s_keytable
[i
].token
== QLINTFALLTHRU
)
264 (FLG_WARNLINTCOMMENTS
,
266 ("Traditional lint comment /*FALLTHRU*/ used. "
267 "Splint interprets this in the same way as most Unix lints, but it is "
268 "preferable to replace it with the /*@fallthrough@*/ "
273 else if (s_keytable
[i
].token
== QLINTNOTREACHED
)
276 (FLG_WARNLINTCOMMENTS
,
278 ("Traditional lint comment /*NOTREACHED*/ used. "
279 "Splint interprets this in the same way as most Unix lints, but it is "
280 "preferable to replace it with the /*@notreached@*/ "
281 "semantic comment."),
286 else if (s_keytable
[i
].token
== QPRINTFLIKE
)
288 setSpecialFunction (qual_createPrintfLike ());
291 else if (s_keytable
[i
].token
== QLINTPRINTFLIKE
)
294 (FLG_WARNLINTCOMMENTS
,
296 ("Traditional lint comment /*PRINTFLIKE*/ used. "
297 "Splint interprets this in the same way as most Unix lints, but it is "
298 "preferable to replace it with either /*@printflike@*/, "
299 "/*@scanflike@*/ or /*@messagelike@*/."),
302 setSpecialFunction (qual_createPrintfLike ());
305 else if (s_keytable
[i
].token
== QSCANFLIKE
)
307 setSpecialFunction (qual_createScanfLike ());
310 else if (s_keytable
[i
].token
== QMESSAGELIKE
)
312 setSpecialFunction (qual_createMessageLike ());
315 else if (s_keytable
[i
].token
== QARGSUSED
)
318 (FLG_WARNLINTCOMMENTS
,
320 ("Traditional lint comment /*ARGSUSED*/ used. "
321 "Splint interprets this in the same way as most Unix lints, but it is "
322 "preferable to use /*@unused@*/ annotations on "
323 "the unused parameters."),
331 return s_keytable
[i
].token
;
341 static int lminput (void)
343 if (s_savechar
== '\0')
346 return (cscanner_input ());
350 int save
= (int) s_savechar
;
356 static void lmsavechar (char c
)
358 if (s_savechar
== '\0')
364 llbuglit ("lmsavechar: override");
368 int cscannerHelp_ninput (void)
372 if (c
!= EOF
&& ((char)c
== '\n'))
374 context_incLineno ();
380 static char macro_nextChar (void)
382 static bool in_quote
= FALSE
, in_escape
= FALSE
, in_char
= FALSE
;
387 c
= char_fromInt (ic
);
389 if (!in_quote
&& !in_char
&& (c
== '\\' || c
== BEFORE_COMMENT_MARKER
[0]))
393 while ((c
= char_fromInt (lminput ())) != '\0' && c
!= '\n')
395 ; /* skip to newline */
398 context_incLineno ();
402 return macro_nextChar ();
409 else /* if (c == '@') */
413 if (cscannerHelp_handleLlSpecial () != BADTOK
)
415 llerrorlit (FLG_SYNTAX
, "Macro cannot use special syntax");
418 return macro_nextChar ();
421 else if (!in_escape
&& c
== '\"')
423 in_quote
= !in_quote
;
425 else if (!in_escape
&& c
== '\'')
429 else if ((in_quote
|| in_char
) && c
== '\\')
431 in_escape
= !in_escape
;
433 else if ((in_quote
|| in_char
) && in_escape
)
437 else if (!in_quote
&& c
== '/')
441 if ((c2
= char_fromInt (lminput ())) == '*')
445 while ((c2
= char_fromInt (lminput ())) != '\0'
446 && c2
!= '\n' && c2
!= '*')
453 while ((c2
= char_fromInt (lminput ())) != '\0'
466 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
470 return macro_nextChar ();
474 /*** putchar does not work! why? puts to stdio...??! ***/
487 ** keeps semantic comments
490 static char macro_nextCharC (void)
492 static bool in_quote
= FALSE
, in_escape
= FALSE
, in_char
= FALSE
;
495 c
= char_fromInt (lminput ());
497 if (!in_quote
&& !in_char
&& c
== '\\')
499 while ((c
= char_fromInt (lminput ())) != '\0' && c
!= '\n')
501 ; /* skip to newline */
504 context_incLineno ();
508 return macro_nextCharC ();
515 else if (!in_escape
&& c
== '\"')
517 in_quote
= !in_quote
;
519 else if (!in_escape
&& c
== '\'')
523 else if ((in_quote
|| in_char
) && c
== '\\')
525 in_escape
= !in_escape
;
527 else if ((in_quote
|| in_char
) && in_escape
)
531 else if (!in_quote
&& c
== '/')
535 if ((c2
= char_fromInt (lminput ())) == '*')
539 while ((c2
= char_fromInt (lminput ())) != '\0'
540 && c2
!= '\n' && c2
!= '*')
547 while ((c2
= char_fromInt (lminput ())) != '\0'
560 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
564 return macro_nextCharC ();
571 else /* normal character */
580 ** skips whitespace (handles line continuations)
581 ** returns first non-whitespace character
584 static char skip_whitespace (void)
588 while ((c
= macro_nextChar ()) == ' ' || c
== '\t')
596 void cscannerHelp_handleMacro (void)
598 cstring mac
= cstring_undefined
;
602 while (currentColumn () > 2)
604 mac
= cstring_appendChar (mac
, ' ');
605 cscannerHelp_setTokLength (-1);
608 c
= macro_nextCharC ();
610 if (c
>= '0' && c
<= '9')
614 for (i
= 0; i
< (((int) (c
- '0')) + 1); i
++)
616 mac
= cstring_appendChar (mac
, ' ');
624 while (((c
= macro_nextCharC ()) != '\0') && (c
!= '\n'))
626 mac
= cstring_appendChar (mac
, c
);
630 macrocode
= tokenMacroCode (mac
);
632 if (macrocode
== BADTOK
&& !isArtificial (mac
))
634 context_addMacroCache (mac
);
643 context_incLineno ();
647 bool cscannerHelp_handleSpecial (char *text
)
649 char *l
; /* !! = mstring_create (MAX_NAME_LENGTH); */
655 l
= mstring_copy (text
+ 1);
657 while ((c
= char_fromInt (lminput ())) != '\n' && c
!= '\0')
659 l
= mstring_append(l
, c
);
664 olc
= cstring_fromChars (ol
);
666 if (cstring_equalPrefixLit (olc
, "pragma"))
668 char *pname
= mstring_create (size_fromInt (MAX_PRAGMA_LEN
));
669 char *opname
= pname
;
670 char *ptr
= ol
+ 6; /* pragma is six characters, plus space */
674 /* skip whitespace */
675 while (((c
= *ptr
) != '\0') && isspace (c
))
681 while (((c
= *ptr
) != '\0') && !isspace (c
))
685 if (len
> MAX_PRAGMA_LEN
)
696 if (len
== PRAGMA_LEN_EXPAND
697 && mstring_equal (opname
, PRAGMA_EXPAND
))
699 cstring exname
= cstring_undefined
;
703 while (((c
= *ptr
) != '\0') && !isspace (c
))
705 exname
= cstring_appendChar (exname
, c
);
710 ue
= usymtab_lookupExposeGlob (exname
);
712 if (uentry_isExpandedMacro (ue
))
714 if (fileloc_isPreproc (uentry_whereDefined (ue
)))
716 fileloc_setColumn (g_currentloc
, 1);
717 uentry_setDefined (ue
, g_currentloc
);
721 cstring_free (exname
);
724 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: pragment increments line */
726 else if (cstring_equalPrefixLit (olc
, "ident"))
728 /* Some pre-processors will leave these in the code. Ignore rest of line */
729 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: ident increments line */
733 ** Yuk...Win32 filenames can have spaces in them...we need to read
734 ** to the matching end quote.
736 else if ((sscanf (ol
, "line %d \"", &lineno
) == 1)
737 || (sscanf (ol
, " %d \"", &lineno
) == 1))
744 while (*tmp
!= '\"' && *tmp
!= '\0')
749 llassert (*tmp
== '\"');
753 while (*tmp
!= '\"' && *tmp
!= '\0')
758 llassert (*tmp
== '\"');
761 # if defined(OS2) || defined(WIN32)
764 ** DOS-like path delimiters get delivered in pairs, something like
765 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
766 ** remove the pre dirs yet as we usually specify tmp paths relative
767 ** to the current directory, so tmp files would not get found in
768 ** the hash table. If this method fails we try it again later.
775 ** Skip past the drive marker.
778 if (strchr (stmp
, ':') != NULL
)
780 stmp
= strchr (stmp
, ':') + 1;
783 while ((stmp
= strchr (stmp
, CONNECTCHAR
)) != NULL
)
785 if (*(stmp
+1) == CONNECTCHAR
)
787 memmove (stmp
, stmp
+1, strlen (stmp
));
793 fid
= fileTable_lookupBase (context_fileTable (), fname
);
794 if (!(fileId_isValid (fid
)))
796 fname
= osd_removePreDirs (fname
);
797 fid
= fileTable_lookupBase (context_fileTable (), fname
);
801 fname
= osd_removePreDirs (fname
);
802 fid
= fileTable_lookupBase (context_fileTable (), fname
);
805 if (!(fileId_isValid (fid
)))
809 if (context_inXHFile ())
811 ftype
= FILE_XH
; /* Files included by XH files are also XH files */
813 else if (isHeaderFile (fname
))
822 fid
= fileTable_addFile (context_fileTable (), ftype
, 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 c_lval
.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
));
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 (void)
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
;
1533 cscannerHelp_processIdentifier (/*@only@*/ cstring id
)
1534 /*@modifies internalState@*/
1538 if (context_getFlag (FLG_GRAMMAR
))
1540 lldiagmsg (message ("Process identifier: %s", id
));
1543 context_clearJustPopped ();
1544 cscanner_setLastIdentifier (id
);
1546 DPRINTF (("Context: %s", context_unparse ()));
1548 if (context_inFunctionHeader ())
1550 int tok
= commentMarkerToken (id
);
1551 DPRINTF (("in function decl: %s", id
));
1559 tok
= tokenMacroCode (id
);
1567 annotationInfo ainfo
;
1569 if (s_expectingMetaStateName
)
1571 metaStateInfo msinfo
= context_lookupMetaStateInfo (id
);
1573 if (metaStateInfo_isDefined (msinfo
))
1575 c_lval
.msinfo
= msinfo
;
1576 return METASTATE_NAME
;
1580 DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id
)));
1584 ainfo
= context_lookupAnnotation (id
);
1586 if (annotationInfo_isDefined (ainfo
))
1588 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo
)));
1589 c_lval
.annotation
= ainfo
;
1594 DPRINTF (("Not annotation: %s", id
));
1600 DPRINTF (("Here!"));
1602 /* Consider handling: Defined by C99 as static const char __func__[] */
1604 if (context_getFlag (FLG_GNUEXTENSIONS
))
1608 if (cstring_equalLit (id
, "__stdcall")
1609 || cstring_equalLit (id
, "__cdecl")
1610 || cstring_equalLit (id
, "__extension__"))
1614 else if (cstring_equalLit (id
, "__volatile__"))
1618 else if (cstring_equalLit (id
, "__signed"))
1622 else if (cstring_equalLit (id
, "__unsigned"))
1626 else if (cstring_equalLit (id
, "__const__"))
1630 else if (cstring_equalLit (id
, "__alignof__"))
1632 tok
= CALIGNOF
; /* alignof is parsed like sizeof */
1634 else if (cstring_equalLit (id
, "__typeof__"))
1638 else if (cstring_equalLit (id
, "typeof"))
1642 else if (cstring_equalLit (id
, "__FUNCTION__")
1643 || cstring_equalLit (id
, "__PRETTY_FUNCTION__"))
1645 /* These tokens hold the name of the current function as strings */
1646 /* evans 2001-12-30: changed from exprNode_stringLiteral; bug reported by Jim Zelenka. */
1647 c_lval
.expr
= exprNode_makeConstantString (id
, fileloc_copy (g_currentloc
));
1652 else if (cstring_equalLit (id
, "__attribute__")
1653 || cstring_equalLit (id
, "__asm__")
1654 || cstring_equalLit (id
, "_asm")
1655 || cstring_equalLit (id
, "__asm")
1656 || cstring_equalLit (id
, "__declspec"))
1659 bool useparens
= FALSE
;
1660 bool usebraces
= FALSE
;
1661 bool inquote
= FALSE
;
1662 bool inescape
= FALSE
;
1665 while ((ic
= cscanner_input ()) != EOF
)
1667 char cc
= (char) ic
;
1673 else if (cc
== '\\')
1677 else if (cc
== '\"')
1713 else if (cc
== ')' && useparens
)
1716 if (depth
== 0) break;
1718 else if (cc
== '}' && usebraces
)
1721 if (depth
== 0) break;
1724 && !usebraces
&& !useparens
1725 && cstring_equalLit (id
, "__asm"))
1728 ** We need this because some MS VC++ include files
1729 ** have __asm mov ... }
1730 ** Its a kludge, but otherwise would need to parse
1747 context_incLineno ();
1749 if (cstring_equalLit (id
, "__asm")
1750 && !useparens
&& !usebraces
)
1757 llassert ((useparens
&& ic
== (int) ')')
1758 || (usebraces
&& ic
== (int) '}')
1759 || (!useparens
&& !usebraces
));
1763 else if (cstring_equalLit (id
, "inline")
1764 || cstring_equalLit (id
, "__inline")
1765 || cstring_equalLit (id
, "_inline")
1766 || cstring_equalLit (id
, "__inline__"))
1777 return (cscannerHelp_returnToken (tok
));
1781 le
= usymtab_lookupSafe (id
);
1783 /*@-dependenttrans@*/
1785 if (uentry_isIter (le
))
1790 else if (uentry_isEndIter (le
))
1793 return (ITER_ENDNAME
);
1795 else if (uentry_isUndefined (le
))
1797 c_lval
.cname
= cstring_copy (id
);
1799 /* avoid parse errors for certain system built ins */
1801 if (s_expectingTypeName
&& (cstring_firstChar (id
) == '_')
1802 && (cstring_secondChar (id
) == '_'))
1804 return (TYPE_NAME_OR_ID
);
1807 return (NEW_IDENTIFIER
);
1809 else if (!uentry_isDeclared (le
) && !uentry_isCodeDefined (le
))
1811 if (uentry_isDatatype (le
))
1813 c_lval
.cname
= cstring_copy (id
);
1814 return (NEW_IDENTIFIER
);
1819 return (IDENTIFIER
);
1822 else if (uentry_isDatatype (le
))
1824 if (!s_expectingTypeName
)
1826 c_lval
.cname
= cstring_copy (id
);
1828 return (NEW_IDENTIFIER
);
1832 c_lval
.ctyp
= uentry_getAbstractType (le
);
1834 uentry_setUsed (le
, g_currentloc
);
1841 return (IDENTIFIER
);
1844 /*@=dependenttrans@*/
1847 bool cscannerHelp_processHashIdentifier (/*@only@*/ cstring id
)
1849 if (context_inMacro () || context_inIterDef () ||
1850 context_inIterEnd ())
1854 context_clearJustPopped ();
1856 le
= usymtab_lookupSafe (id
);
1857 cscanner_setLastIdentifier (id
);
1859 if (uentry_isParam (le
) || uentry_isRefParam (le
))
1871 ** Will be handled by handleLlSpecial
1879 /*@only@*/ exprNode
cscannerHelp_processString (void)
1883 char *nl
= strchr (c_text
, '\n');
1884 cstring ns
= cstring_fromCharsNew (c_text
);
1888 loc
= fileloc_copy (g_currentloc
);
1889 addColumn (size_toInt (cstring_length (ns
)));
1893 loc
= fileloc_copy (g_currentloc
);
1895 context_incLineno ();
1897 while ((nl
= strchr ((nl
+ 1), '\n')) != NULL
)
1899 context_incLineno ();
1904 res
= exprNode_stringLiteral (ns
, loc
);
1909 ** process a wide character string L"...."
1912 /*@only@*/ exprNode
cscannerHelp_processWideString (void)
1916 char *nl
= strchr (c_text
, '\n');
1919 llassert (*c_text
== 'L');
1922 ns
= cstring_fromCharsNew (c_text
);
1926 loc
= fileloc_copy (g_currentloc
);
1927 addColumn (size_toInt (cstring_length (ns
)));
1931 loc
= fileloc_copy (g_currentloc
);
1933 context_incLineno ();
1935 while ((nl
= strchr ((nl
+ 1), '\n')) != NULL
)
1937 context_incLineno ();
1941 res
= exprNode_wideStringLiteral (ns
, loc
);
1945 char cscannerHelp_processChar (void)
1950 llassert (*c_text
!= '\0');
1951 fchar
= *(c_text
+ 1);
1952 if (fchar
!= '\\') return fchar
;
1954 next
= *(c_text
+ 2);
1958 case 'n': return '\n';
1959 case 't': return '\t';
1960 case '\"': return '\"';
1961 case '\'': return '\'';
1962 case '\\': return '\\';
1963 default: return '\0';
1967 double cscannerHelp_processFloat (void)
1969 double ret
= atof (c_text
);
1974 long cscannerHelp_processHex (void)
1979 llassert (c_text
[0] == '0'
1980 && (c_text
[1] == 'X' || c_text
[1] == 'x'));
1982 while (c_text
[index
] != '\0') {
1984 char c
= c_text
[index
];
1986 if (c
>= '0' && c
<= '9') {
1987 tval
= (int) c
- (int) '0';
1988 } else if (c
>= 'A' && c
<= 'F') {
1989 tval
= (int) c
- (int) 'A' + 10;
1990 } else if (c
>= 'a' && c
<= 'f') {
1991 tval
= (int) c
- (int) 'a' + 10;
1992 } else if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
1994 while (c_text
[index
] != '\0') {
1995 if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2000 message ("Invalid character (%c) following specifier in hex constant: %s",
2001 c
, cstring_fromChars (c_text
)),
2011 message ("Invalid character (%c) in hex constant: %s",
2012 c
, cstring_fromChars (c_text
)),
2017 val
= (val
* 16) + tval
;
2021 DPRINTF (("Hex constant: %s = %ld", c_text
, val
));
2025 long cscannerHelp_processOctal (void)
2030 llassert (c_text
[0] == '0' && c_text
[1] != 'X' && c_text
[1] != 'x');
2032 while (c_text
[index
] != '\0') {
2034 char c
= c_text
[index
];
2036 if (c
>= '0' && c
<= '7') {
2037 tval
= (int) c
- (int) '0';
2038 } else if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2040 while (c_text
[index
] != '\0') {
2041 if (c
== 'U' || c
== 'L' || c
== 'u' || c
== 'l') {
2046 message ("Invalid character (%c) following specifier in octal constant: %s",
2047 c
, cstring_fromChars (c_text
)),
2057 message ("Invalid character (%c) in octal constant: %s",
2058 c
, cstring_fromChars (c_text
)),
2063 val
= (val
* 8) + tval
;
2067 DPRINTF (("Octal constant: %s = %ld", c_text
, val
));
2071 long cscannerHelp_processDec (void)
2073 return (atol (c_text
));
2076 int cscannerHelp_processSpec (int tok
)
2078 size_t length
= strlen (c_text
);
2084 patched to fix assert failures in constraint code.
2085 Added the else if test so that splint does not treat MaxSet and MaxRead
2088 if (s_whichSpecPart
== QMODIFIES
2089 || s_whichSpecPart
== QDEFINES
2090 || s_whichSpecPart
== QUSES
2091 || s_whichSpecPart
== QALLOCATES
2092 || s_whichSpecPart
== QSETS
2093 || s_whichSpecPart
== QRELEASES
)
2096 DPRINTF((message("Treating specification keyword %s as an identifier. (This corresponds to"
2097 " token %d and we're in the specification denoted by %d)",
2098 c_text
, tok
, s_whichSpecPart
)
2101 ; /* Allow specificiation keywords to be used as identifiers in these contexts. */
2103 else if ((s_whichSpecPart
== QPRECLAUSE
2104 || s_whichSpecPart
== QPOSTCLAUSE
2105 || s_whichSpecPart
== QINVARIANT
)
2106 && (!cscannerHelp_isConstraintToken(tok
))
2109 DPRINTF((message("Treating specification keyword %s as an identifier. (This corresponds to"
2110 " token %d and we're in the specification denoted by %d)",
2111 c_text
, tok
, s_whichSpecPart
)
2114 /* Allow specificiation keywords to be used as identifiers in these contexts. */
2118 cscannerHelp_setTokLengthT (length
);
2119 return cscannerHelp_returnToken (tok
);
2123 context_saveLocation ();
2124 cscannerHelp_setTokLengthT (length
);
2125 return (cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (c_text
)));
2128 void cscannerHelp_expectingMetaStateName (void)
2130 llassert (!s_expectingMetaStateName
);
2131 llassert (context_inFunctionHeader ());
2132 s_expectingMetaStateName
= TRUE
;
2135 void cscannerHelp_clearExpectingMetaStateName (void)
2137 llassert (s_expectingMetaStateName
);
2138 s_expectingMetaStateName
= FALSE
;
2141 static bool cscannerHelp_isConstraintToken (int tok
)
2142 /* drl added 12/11/2002
2143 Tell whether a token has special meaning
2144 within a function constraint
2147 return (tok
== QMAXSET
|| tok
== QMAXREAD
);
2148 /* || tok == QMINREAD || tok == QMINSET */
2149 /* uncomment the additional if statement tests when minSet and minRead are supported */
2152 bool cscannerHelp_processMacro (void)
2157 cstring fname
= cstring_undefined
;
2159 bool isspecfcn
= FALSE
;
2160 bool isiter
= FALSE
;
2161 bool skipparam
= FALSE
;
2162 bool unknownm
= FALSE
;
2163 bool hasParams
= FALSE
;
2164 bool emptyMacro
= FALSE
;
2165 char c
= skip_whitespace ();
2166 fileloc loc
= fileloc_noColumn (g_currentloc
);
2168 /* are both of these necessary? what do they mean? */
2169 uentryList specparams
= uentryList_undefined
;
2170 uentryList pn
= uentryList_undefined
;
2172 context_resetMacroMissingParams ();
2174 if (c
== '\0' || c
== '\n')
2176 llcontbug (cstring_makeLiteral ("Bad macro"));
2181 fname
= cstring_appendChar (fname
, c
);
2183 while ((c
= macro_nextChar ()) != '(' && c
!= '\0'
2184 && c
!= ' ' && c
!= '\t' && c
!= '\n')
2186 fname
= cstring_appendChar (fname
, c
);
2189 if (c
== ' ' || c
== '\t' || c
== '\n')
2195 while (c
== ' ' || c
== '\t')
2197 c
= macro_nextChar ();
2199 cscanner_unput ((int) c
);
2205 cscanner_unput ((int) c
);
2211 hasParams
= (c
== '(');
2213 if (usymtab_exists (fname
))
2215 e2
= usymtab_lookupExpose (fname
);
2216 ct
= uentry_getType (e2
);
2218 if (uentry_isCodeDefined (e2
)
2219 && fileloc_isUser (uentry_whereDefined (e2
)))
2223 message ("Macro %s already defined", fname
),
2226 uentry_showWhereDefined (e2
);
2227 uentry_clearDefined (e2
);
2230 if (uentry_isFunction (e2
))
2232 uentry_setType (e2
, ctype_unknown
);
2235 context_enterUnknownMacro (e2
);
2239 context_enterConstantMacro (e2
);
2242 else if (uentry_isForward (e2
) && uentry_isFunction (e2
))
2249 ("Parameterized macro has no prototype or specification: %s ",
2254 uentry_setType (e2
, ctype_unknown
);
2255 uentry_setFunctionDefined (e2
, loc
);
2256 uentry_setUsed (e2
, fileloc_undefined
);
2257 context_enterUnknownMacro (e2
);
2259 else if (uentry_isIter (e2
))
2262 specparams
= uentry_getParams (e2
);
2263 noparams
= uentryList_size (specparams
);
2264 uentry_setDefined (e2
, loc
);
2265 context_enterIterDef (e2
);
2267 else if (uentry_isEndIter (e2
))
2269 uentry_setDefined (e2
, loc
);
2270 context_enterIterEnd (e2
); /* don't care about it now */
2271 /* but should parse like an iter! */
2273 else if (uentry_isConstant (e2
))
2279 message ("Constant %s implemented as parameterized macro",
2283 uentry_showWhereSpecified (e2
);
2284 uentry_setType (e2
, ctype_unknown
);
2285 uentry_makeConstantFunction (e2
);
2286 uentry_setDefined (e2
, g_currentloc
);
2287 uentry_setFunctionDefined (e2
, g_currentloc
);
2288 context_enterUnknownMacro (e2
);
2292 if (!uentry_isSpecified (e2
))
2294 fileloc oloc
= uentry_whereDeclared (e2
);
2296 if (fileloc_isLib (oloc
))
2300 else if (fileloc_isUndefined (oloc
)
2301 || fileloc_isPreproc (oloc
))
2306 (FLG_MACROCONSTDECL
,
2308 ("Macro constant %q not declared",
2309 uentry_getName (e2
)),
2313 else if (!fileloc_withinLines (oloc
, loc
, 2))
2314 { /* bogus! will give errors if there is too much whitespace */
2316 (FLG_MACROCONSTDIST
,
2318 ("Macro constant name %s matches name in "
2319 "distant constant declaration. This constant "
2320 "is declared at %q", fname
,
2321 fileloc_unparse (oloc
)),
2330 context_enterConstantMacro (e2
);
2331 cstring_free (fname
);
2336 else if (ctype_isFunction (ct
))
2339 specparams
= ctype_argsFunction (ct
);
2340 noparams
= uentryList_size (specparams
);
2342 uentry_setFunctionDefined (e2
, loc
);
2343 context_enterMacro (e2
);
2345 else if (uentry_isVar (e2
))
2351 message ("Variable %s implemented as parameterized macro",
2355 uentry_showWhereSpecified (e2
);
2356 uentry_setType (e2
, ctype_unknown
);
2357 uentry_makeVarFunction (e2
);
2358 uentry_setDefined (e2
, g_currentloc
);
2359 uentry_setFunctionDefined (e2
, g_currentloc
);
2360 context_enterUnknownMacro (e2
);
2364 uentry ucons
= uentry_makeConstant (fname
,
2367 if (uentry_isExpandedMacro (e2
))
2375 message ("Variable %s implemented by a macro",
2379 uentry_showWhereSpecified (e2
);
2383 uentry_setDefined (e2
, loc
);
2384 uentry_setUsed (ucons
, loc
);
2386 context_enterConstantMacro (ucons
);
2387 uentry_markOwned (ucons
);
2388 cstring_free (fname
);
2392 else if (uentry_isDatatype (e2
))
2396 message ("Type implemented as macro: %x",
2397 uentry_getName (e2
)),
2398 message ("A type is implemented using a macro definition. A "
2399 "typedef should be used instead."),
2402 cscannerHelp_swallowMacro ();
2403 /* Must exit scope (not sure why a new scope was entered?) */
2404 usymtab_quietExitScope (g_currentloc
);
2405 uentry_setDefined (e2
, g_currentloc
);
2411 (message ("Unexpanded macro not function or constant: %q",
2412 uentry_unparse (e2
)));
2413 uentry_setType (e2
, ctype_unknown
);
2417 uentry_makeVarFunction (e2
);
2418 uentry_setDefined (e2
, g_currentloc
);
2419 uentry_setFunctionDefined (e2
, g_currentloc
);
2420 context_enterUnknownMacro (e2
);
2428 /* evans 2001-09-09 - if it has params, assume a function */
2432 (FLG_MACROMATCHNAME
,
2433 message ("Unexpanded macro %s does not match name of a declared "
2434 "function. The name used in the control "
2435 "comment on the previous line should match.",
2439 ce
= uentry_makeFunction (fname
, ctype_unknown
,
2443 warnClause_undefined
,
2445 uentry_setUsed (ce
, loc
); /* perhaps bogus? */
2446 e2
= usymtab_supEntryReturn (ce
);
2447 context_enterUnknownMacro (e2
);
2452 (FLG_MACROMATCHNAME
,
2453 message ("Unexpanded macro %s does not match name of a constant "
2454 "or iter declaration. The name used in the control "
2455 "comment on the previous line should match. "
2456 "(Assuming macro defines a constant.)",
2460 ce
= uentry_makeConstant (fname
, ctype_unknown
, fileloc_undefined
);
2461 uentry_setUsed (ce
, loc
); /* perhaps bogus? */
2462 e2
= usymtab_supEntryReturn (ce
);
2464 context_enterConstantMacro (e2
);
2465 cstring_free (fname
);
2471 /* in macros, ( must follow immediatetly after name */
2477 c
= skip_whitespace ();
2479 while (c
!= ')' && c
!= '\0')
2482 bool suppress
= context_inSuppressRegion ();
2483 cstring paramname
= cstring_undefined
;
2486 ** save the parameter location
2490 context_saveLocation ();
2493 while (c
!= ' ' && c
!= '\t' && c
!= ',' && c
!= '\0' && c
!= ')')
2495 paramname
= cstring_appendChar (paramname
, c
);
2496 c
= macro_nextChar ();
2499 if (c
== ' ' || c
== '\t') c
= skip_whitespace ();
2503 c
= macro_nextChar ();
2504 if (c
== ' ' || c
== '\t') c
= skip_whitespace ();
2509 llfatalerror (cstring_makeLiteral
2510 ("Bad macro syntax: uentryList"));
2513 if ((isspecfcn
|| isiter
) && (paramno
< noparams
)
2514 && !uentry_isElipsisMarker (uentryList_getN
2515 (specparams
, paramno
)))
2517 fileloc sloc
= context_getSaveLocation ();
2518 uentry decl
= uentryList_getN (specparams
, paramno
);
2521 param
= uentry_nameCopy (paramname
, decl
);
2523 uentry_setParam (param
);
2524 sr
= sRef_makeParam (paramno
, uentry_getType (param
),
2525 stateInfo_makeLoc (sloc
, SA_DECLARED
));
2527 if (sRef_getNullState (sr
) == NS_ABSNULL
)
2529 ctype pt
= ctype_realType (uentry_getType (param
));
2531 if (ctype_isUser (pt
))
2533 uentry te
= usymtab_getTypeEntrySafe (ctype_typeId (pt
));
2535 if (uentry_isValid (te
))
2537 sRef_setStateFromUentry (sr
, te
);
2542 sRef_setNullState (sr
, NS_UNKNOWN
, sloc
);
2546 uentry_setSref (param
, sr
);
2547 uentry_setDeclaredForceOnly (param
, sloc
);
2549 skipparam
= isiter
&& uentry_isOut (uentryList_getN (specparams
, paramno
));
2553 fileloc sloc
= context_getSaveLocation ();
2555 param
= uentry_makeVariableSrefParam
2556 (paramname
, ctype_unknown
, fileloc_copy (sloc
),
2557 sRef_makeParam (paramno
, ctype_unknown
,
2558 stateInfo_makeLoc (sloc
, SA_DECLARED
)));
2559 DPRINTF (("Unknown param: %s", uentry_unparseFull (param
)));
2560 cstring_free (paramname
);
2562 sRef_setPosNull (uentry_getSref (param
), sloc
);
2563 uentry_setDeclaredForce (param
, sloc
);
2566 fileloc_free (sloc
);
2571 llassert (!uentry_isElipsisMarker (param
));
2575 sRef_makeUnsafe (uentry_getSref (param
));
2578 pn
= uentryList_add (pn
, uentry_copy (param
));
2579 usymtab_supEntry (param
);
2583 /* don't add param */
2584 uentry_free (param
);
2589 (void) macro_nextChar ();
2590 c
= skip_whitespace ();
2598 if (isspecfcn
|| isiter
)
2600 if (paramno
!= noparams
&& noparams
>= 0)
2602 cscannerHelp_advanceLine ();
2606 message ("Macro %s specified with %d args, defined with %d",
2607 fname
, noparams
, paramno
),
2610 uentry_showWhereSpecified (e2
);
2611 uentry_resetParams (e2
, pn
);
2616 uentry_resetParams (e2
, pn
);
2623 ** the form should be:
2625 ** # define newname oldname
2626 ** where oldname refers to a function matching the specification
2632 sRef_setGlobalScope ();
2633 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname
, ctype_unknown
));
2634 sRef_clearGlobalScope ();
2638 context_setMacroMissingParams ();
2643 /* context_setuentryList (pn); */
2644 usymtab_enterScope ();
2647 cstring_free (fname
);
2652 void cscannerHelp_setTokLength (int len
)
2656 DPRINTF (("Set tok length: %d", len
));
2659 void cscannerHelp_setTokLengthT (size_t len
)
2661 cscannerHelp_setTokLength (size_toInt (len
));
2664 static void cscannerHelp_advanceLine (void)
2670 int cscannerHelp_returnToken (int t
)
2672 if (s_tokLength
> fileloc_column (g_currentloc
)) {
2673 c_lval
.tok
= lltok_create (t
, fileloc_copy (g_currentloc
));
2675 c_lval
.tok
= lltok_create (t
, fileloc_decColumn (g_currentloc
, s_tokLength
));
2682 int cscannerHelp_returnTokenLength (int t
, int length
)
2684 cscannerHelp_setTokLength (length
);
2685 return cscannerHelp_returnToken (t
);
2688 int cscannerHelp_returnString (cstring s
)
2690 c_lval
.expr
= exprNode_stringLiteral (s
, fileloc_decColumn (g_currentloc
, s_tokLength
));
2695 int cscannerHelp_returnInt (ctype ct
, long val
)
2699 if (ctype_equal (ct
, ctype_int
))
2703 c
= context_typeofZero ();
2707 c
= context_typeofOne ();
2715 c_lval
.expr
= exprNode_numLiteral (c
, cstring_fromChars (c_text
),
2716 fileloc_decColumn (g_currentloc
, s_tokLength
),
2722 int cscannerHelp_returnFloat (ctype ct
, double f
)
2724 c_lval
.expr
= exprNode_floatLiteral (f
, ct
, cstring_fromChars (c_text
),
2725 fileloc_decColumn (g_currentloc
, s_tokLength
));
2730 int cscannerHelp_returnChar (char c
)
2732 c_lval
.expr
= exprNode_charLiteral (c
, cstring_fromChars (c_text
),
2733 fileloc_decColumn (g_currentloc
, s_tokLength
));
2738 int cscannerHelp_returnType (int tok
, ctype ct
)
2745 int cscannerHelp_returnExpr (exprNode e
)
2752 void cscannerHelp_setExpectingTypeName (void)
2754 s_expectingTypeName
= TRUE
;
2757 void cscannerHelp_clearExpectingTypeName (void)
2759 s_expectingTypeName
= FALSE
;
2763 bool cscannerHelp_isExpectingTypeName (void)
2765 return s_expectingTypeName
;
2767 # endif /* DEADCODE */
2769 int cscannerHelp_processTextIdentifier (char *text
)
2771 context_saveLocation ();
2772 cscannerHelp_setTokLength (size_toInt (mstring_length (text
)));
2773 return cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (text
));
2776 static bool s_continueLine
= FALSE
;
2778 int cscannerHelp_handleNewLine (void)
2780 context_incLineno ();
2782 if (s_tokLength
!= 0) {
2784 /* No error to report
2787 message ("Likely parse error: token spans multiple lines."),
2794 s_continueLine
= FALSE
;
2798 if (context_inMacro ())
2800 /* Don't use return cscannerHelp_returnToken */
2801 /* !!! evans 2002-03-13 */
2802 c_lval
.tok
= lltok_create (TENDMACRO
, fileloc_copy (g_currentloc
));
2810 void cscannerHelp_setContinueLine (void)
2812 s_continueLine
= TRUE
;
2815 void cscannerHelp_exitSpecPart (void)
2817 llassert (s_inSpecPart
);
2818 s_inSpecPart
= FALSE
;
2819 s_whichSpecPart
= BADTOK
;