Cosmetic changes (split from upcoming commit).
[splint-patched.git] / src / cscannerHelp.c
bloba8effafb948159fbbeff2a1fe8dbb7db2bde740d
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
15 **
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
25 ** 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"
32 # include "basic.h"
33 # include "cscannerHelp.h"
34 # include "cscanner.h"
35 # include "cgrammar.h"
36 # include "osd.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;
48 struct skeyword
50 /*@null@*/ /*@observer@*/ char *name;
51 int token;
52 } ;
55 ** These tokens are followed by syntax that is parsed by the
56 ** grammar proper.
59 static struct skeyword s_parsetable[] = {
60 { "modifies", QMODIFIES } ,
61 { "globals", QGLOBALS } ,
62 { "alt", QALT } ,
63 { "warn", QWARN } ,
64 { "constant", QCONSTANT } ,
65 { "function", QFUNCTION } ,
66 { "iter", QITER } ,
67 { "defines", QDEFINES } ,
68 { "uses", QUSES } ,
69 { "allocates", QALLOCATES } ,
70 { "sets", QSETS } ,
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} ,
80 { NULL, BADTOK }
81 } ;
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 } ,
93 { "out", QOUT } ,
94 { "in", QIN } ,
95 { "only", QONLY } ,
96 { "owned", QOWNED } ,
97 { "dependent", QDEPENDENT } ,
98 { "partial", QPARTIAL } ,
99 { "special", QSPECIAL } ,
100 { "truenull", QTRUENULL } ,
101 { "falsenull", QFALSENULL } ,
102 { "nullwhentrue", QTRUENULL } ,
103 { "falsewhennull", QFALSENULL } ,
104 { "keep", QKEEP } ,
105 { "kept", QKEPT } ,
106 { "notnull", QNOTNULL } ,
107 { "abstract", QABSTRACT } ,
108 { "numabstract", QNUMABSTRACT } ,
109 { "concrete", QCONCRETE } ,
110 { "mutable", QMUTABLE } ,
111 { "immutable", QIMMUTABLE } ,
112 { "unused", QUNUSED } ,
113 { "external", QEXTERNAL } ,
114 { "sef", QSEF } ,
115 { "unique", QUNIQUE } ,
116 { "returned", QRETURNED } ,
117 { "exposed", QEXPOSED } ,
118 { "refcounted", QREFCOUNTED } ,
119 { "refs", QREFS } ,
120 { "newref", QNEWREF } ,
121 { "tempref", QTEMPREF } ,
122 { "killref", QKILLREF } ,
123 { "null", QNULL } ,
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 } ,
145 { "temp", QTEMP } ,
146 { "shared", QSHARED } ,
147 { "ref", QREF } ,
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 } ,
167 { NULL, BADTOK }
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)
187 int i;
188 bool skipnext = FALSE;
190 while ((i = lminput ()) != EOF)
192 char c = (char) i;
194 if (c == '\\')
196 skipnext = TRUE;
198 else if (c == '\n')
200 if (skipnext)
202 skipnext = FALSE;
204 else
206 reader_checkUngetc (i, c_in);
207 return;
210 else
216 if (i != EOF)
218 reader_checkUngetc (i, c_in);
222 static int commentMarkerToken (cstring s)
224 int i = 0;
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;
235 i++;
238 return BADTOK;
241 static int tokenMacroCode (cstring s)
243 int i = 0;
245 while (s_keytable[i].name != NULL)
247 if (cstring_equalLit (s, s_keytable[i].name))
249 if (s_keytable[i].token == QLINTFALLTHROUGH)
251 voptgenerror
252 (FLG_WARNLINTCOMMENTS,
253 cstring_makeLiteral
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@*/ "
257 "semantic comment"),
258 g_currentloc);
259 return QFALLTHROUGH;
261 else if (s_keytable[i].token == QLINTFALLTHRU)
263 voptgenerror
264 (FLG_WARNLINTCOMMENTS,
265 cstring_makeLiteral
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@*/ "
269 "semantic comment"),
270 g_currentloc);
271 return QFALLTHROUGH;
273 else if (s_keytable[i].token == QLINTNOTREACHED)
275 voptgenerror
276 (FLG_WARNLINTCOMMENTS,
277 cstring_makeLiteral
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."),
282 g_currentloc);
284 return QNOTREACHED;
286 else if (s_keytable[i].token == QPRINTFLIKE)
288 setSpecialFunction (qual_createPrintfLike ());
289 return SKIPTOK;
291 else if (s_keytable[i].token == QLINTPRINTFLIKE)
293 voptgenerror
294 (FLG_WARNLINTCOMMENTS,
295 cstring_makeLiteral
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@*/."),
300 g_currentloc);
302 setSpecialFunction (qual_createPrintfLike ());
303 return SKIPTOK;
305 else if (s_keytable[i].token == QSCANFLIKE)
307 setSpecialFunction (qual_createScanfLike ());
308 return SKIPTOK;
310 else if (s_keytable[i].token == QMESSAGELIKE)
312 setSpecialFunction (qual_createMessageLike ());
313 return SKIPTOK;
315 else if (s_keytable[i].token == QARGSUSED)
317 voptgenerror
318 (FLG_WARNLINTCOMMENTS,
319 cstring_makeLiteral
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."),
324 g_currentloc);
326 setArgsUsed ();
327 return SKIPTOK;
329 else
331 return s_keytable[i].token;
335 i++;
338 return BADTOK;
341 static int lminput (void)
343 if (s_savechar == '\0')
345 incColumn ();
346 return (cscanner_input ());
348 else
350 int save = (int) s_savechar;
351 s_savechar = '\0';
352 return save;
356 static void lmsavechar (char c)
358 if (s_savechar == '\0')
360 s_savechar = c;
362 else
364 llbuglit ("lmsavechar: override");
368 int cscannerHelp_ninput (void)
370 int c = lminput ();
372 if (c != EOF && ((char)c == '\n'))
374 context_incLineno ();
377 return c;
380 static char macro_nextChar (void)
382 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
383 int ic;
384 char c;
386 ic = lminput ();
387 c = char_fromInt (ic);
389 if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
391 if (c == '\\')
393 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
395 ; /* skip to newline */
398 context_incLineno ();
400 if (c != '\0')
402 return macro_nextChar ();
404 else
406 return c;
409 else /* if (c == '@') */
411 llassert (FALSE);
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 == '\'')
427 in_char = !in_char;
429 else if ((in_quote || in_char) && c == '\\')
431 in_escape = !in_escape;
433 else if ((in_quote || in_char) && in_escape)
435 in_escape = FALSE;
437 else if (!in_quote && c == '/')
439 char c2;
441 if ((c2 = char_fromInt (lminput ())) == '*')
443 while (c2 != '\0')
445 while ((c2 = char_fromInt (lminput ())) != '\0'
446 && c2 != '\n' && c2 != '*')
451 if (c2 == '*')
453 while ((c2 = char_fromInt (lminput ())) != '\0'
454 && c2 == '*')
459 if (c2 == '/')
461 goto outofcomment;
464 else
466 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
469 outofcomment:
470 return macro_nextChar ();
472 else
474 /*** putchar does not work! why? puts to stdio...??! ***/
475 lmsavechar (c2);
478 else
483 return c;
487 ** keeps semantic comments
490 static char macro_nextCharC (void)
492 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
493 char c;
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 ();
506 if (c != '\0')
508 return macro_nextCharC ();
510 else
512 return c;
515 else if (!in_escape && c == '\"')
517 in_quote = !in_quote;
519 else if (!in_escape && c == '\'')
521 in_char = !in_char;
523 else if ((in_quote || in_char) && c == '\\')
525 in_escape = !in_escape;
527 else if ((in_quote || in_char) && in_escape)
529 in_escape = FALSE;
531 else if (!in_quote && c == '/')
533 char c2;
535 if ((c2 = char_fromInt (lminput ())) == '*')
537 while (c2 != '\0')
539 while ((c2 = char_fromInt (lminput ())) != '\0'
540 && c2 != '\n' && c2 != '*')
545 if (c2 == '*')
547 while ((c2 = char_fromInt (lminput ())) != '\0'
548 && c2 == '*')
553 if (c2 == '/')
555 goto outofcomment;
558 else
560 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
563 outofcomment:
564 return macro_nextCharC ();
566 else
568 lmsavechar (c2);
571 else /* normal character */
576 return c;
580 ** skips whitespace (handles line continuations)
581 ** returns first non-whitespace character
584 static char skip_whitespace (void)
586 char c;
588 while ((c = macro_nextChar ()) == ' ' || c == '\t')
593 return c;
596 void cscannerHelp_handleMacro (void)
598 cstring mac = cstring_undefined;
599 int macrocode;
600 char c;
602 while (currentColumn () > 2)
604 mac = cstring_appendChar (mac, ' ');
605 cscannerHelp_setTokLength (-1);
608 c = macro_nextCharC ();
610 if (c >= '0' && c <= '9')
612 int i;
614 for (i = 0; i < (((int) (c - '0')) + 1); i++)
616 mac = cstring_appendChar (mac, ' ');
619 else
621 BADBRANCH;
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);
636 else
638 cstring_free (mac);
641 if (c == '\n')
643 context_incLineno ();
647 bool cscannerHelp_handleSpecial (char *text)
649 char *l; /* !! = mstring_create (MAX_NAME_LENGTH); */
650 int lineno = 0;
651 char c;
652 char *ol;
653 cstring olc;
655 l = mstring_copy (text + 1);
657 while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
659 l = mstring_append(l, c);
662 ol = l;
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 */
671 int len = 0;
674 /* skip whitespace */
675 while (((c = *ptr) != '\0') && isspace (c))
677 ptr++;
681 while (((c = *ptr) != '\0') && !isspace (c))
683 len++;
685 if (len > MAX_PRAGMA_LEN)
687 break;
690 ptr++;
691 *pname++ = c;
694 *pname = '\0';
696 if (len == PRAGMA_LEN_EXPAND
697 && mstring_equal (opname, PRAGMA_EXPAND))
699 cstring exname = cstring_undefined;
700 uentry ue;
702 ptr++;
703 while (((c = *ptr) != '\0') && !isspace (c))
705 exname = cstring_appendChar (exname, c);
706 ptr++;
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))
739 char *tmp = ol;
740 cstring fname;
741 fileId fid;
743 /*@access cstring@*/
744 while (*tmp != '\"' && *tmp != '\0')
746 tmp++;
749 llassert (*tmp == '\"');
750 tmp++;
751 fname = tmp;
753 while (*tmp != '\"' && *tmp != '\0')
755 tmp++;
758 llassert (*tmp == '\"');
759 *tmp = '\0';
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.
772 char *stmp = fname;
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));
790 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);
800 # else
801 fname = osd_removePreDirs (fname);
802 fid = fileTable_lookupBase (context_fileTable (), fname);
803 # endif
805 if (!(fileId_isValid (fid)))
807 fileType ftype;
809 if (context_inXHFile ())
811 ftype = FILE_XH; /* Files included by XH files are also XH files */
813 else if (isHeaderFile (fname))
815 ftype = FILE_HEADER;
817 else
819 ftype = FILE_NORMAL;
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> */
833 else
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.
841 mstring_free (ol);
842 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
843 return FALSE;
844 } else {
845 voptgenerror
846 (FLG_UNRECOGDIRECTIVE,
847 message ("Unrecognized pre-processor directive: #%s",
848 cstring_fromChars (ol)),
849 g_currentloc);
850 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
853 sfree (ol);
854 return FALSE; /* evans 2001-12-30: was: TRUE; */
857 sfree (ol);
858 return FALSE;
861 int cscannerHelp_handleLlSpecial (void)
863 bool hasnl = FALSE;
864 int ic;
865 char c;
866 char *s = mstring_createEmpty ();
867 char *os;
868 int tok;
869 int charsread = 0;
870 fileloc loc;
872 loc = fileloc_copy (g_currentloc);
873 DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
875 while (((ic = cscannerHelp_ninput ()) != 0) && isalpha (ic))
877 c = (char) ic;
878 s = mstring_append (s, c);
879 charsread++;
882 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
883 os = s;
885 if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
887 ic = cscannerHelp_ninput ();
889 llassert (ic == (int) AFTER_COMMENT_MARKER[1]);
891 if (*s == '\0')
893 sfree (os);
894 fileloc_free (loc);
895 return QNOMODS; /* special token no modifications token */
899 DPRINTF (("Coment marker: %s", os));
900 tok = commentMarkerToken (cstring_fromChars (os));
902 if (tok != BADTOK)
904 s_tokLength = charsread;
905 sfree (os);
906 s_inSpecPart = TRUE;
907 s_whichSpecPart = tok;
908 fileloc_free (loc);
909 return tok;
912 DPRINTF (("Not a comment marker..."));
913 /* Add rest of the comment */
915 if (ic != 0 && ic != EOF)
917 c = (char) ic;
919 s = mstring_append (s, c);
920 charsread++;
922 while (((ic = cscannerHelp_ninput ()) != 0) && (ic != EOF)
923 && (ic != (int) AFTER_COMMENT_MARKER[0]))
925 c = (char) ic;
927 /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
929 if (c == '\n') {
930 hasnl = TRUE; /* This prevents tokLength from being set later. */
931 s_tokLength = 0;
933 voptgenerror
934 (FLG_SYNTAX,
935 message ("Likely parse error: syntactic comment token spans multiple lines: %s",
936 cstring_fromChars (s)),
937 loc);
940 s = mstring_append (s, c);
941 charsread++;
943 /*@-branchstate@*/
944 } /* spurious (?) warnings about s */
945 /*@=branchstate@*/
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]);
953 charsread++;
956 os = s;
958 while (*s == ' ' || *s == '\t' || *s == '\n')
960 s++;
963 if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
965 c = *s;
967 while (c == '-' || c == '+' || c == '=')
969 ynm set = ynm_fromCodeChar (c);
970 cstring thisflag;
972 s++;
974 thisflag = cstring_fromChars (s);
976 while ((c = *s) != '\0' && (c != '-') && (c != '=')
977 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
979 s++;
982 *s = '\0';
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))
997 llerror
998 (FLG_BADFLAG,
999 message
1000 ("Semantic comment attempts to restore flag %s. "
1001 "A mode flag cannot be restored.",
1002 flagname));
1004 else
1006 context_setMode (flagname);
1009 else if (flagcode_isInvalid (fflag))
1011 voptgenerror
1012 (FLG_UNRECOGFLAGCOMMENTS,
1013 message ("Unrecognized option in semantic comment: %s",
1014 flagname),
1015 loc);
1017 else if (flagcode_isGlobalFlag (fflag))
1019 voptgenerror
1020 (FLG_BADFLAG,
1021 message
1022 ("Semantic comment attempts to set global flag %s. "
1023 "A global flag cannot be set locally.",
1024 flagname),
1025 loc);
1027 else
1029 context_fileSetFlag (fflag, set, loc);
1031 if (flagcode_hasArgument (fflag))
1033 if (ynm_isMaybe (set))
1035 voptgenerror
1036 (FLG_BADFLAG,
1037 message
1038 ("Semantic comment attempts to restore flag %s. "
1039 "A flag for setting a value cannot be restored.",
1040 flagname),
1041 loc);
1043 else
1044 { /* cut-and-pastied from llmain...blecch */
1045 cstring extra = cstring_undefined;
1046 char *rest;
1047 char *orest;
1048 char rchar;
1050 *s = c;
1051 rest = mstring_copy (s);
1052 orest = rest;
1053 *s = '\0';
1055 while ((rchar = *rest) != '\0'
1056 && (isspace (rchar)))
1058 rest++;
1059 s++;
1062 while ((rchar = *rest) != '\0'
1063 && !isspace (rchar))
1065 extra = cstring_appendChar (extra, rchar);
1066 rest++;
1067 s++;
1069 s--; /* evans 2002-07-12: this was previously only in the else branch.
1070 Leads to an invalid read on the true branch.
1073 sfree (orest);
1075 if (cstring_isUndefined (extra))
1077 llerror
1078 (FLG_BADFLAG,
1079 message
1080 ("Flag %s (in semantic comment) must be followed by an argument",
1081 flagcode_unparse (fflag)));
1083 cstring_free (extra);
1085 else
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);
1099 else
1101 cstring_free (extra);
1102 BADEXIT;
1109 else
1114 *s = c;
1115 while ((c == ' ') || (c == '\t') || (c == '\n'))
1117 c = *(++s);
1121 if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
1123 DPRINTF (("Here adding comment: %s", os));
1124 context_addComment (cstring_fromCharsNew (os), loc);
1126 else
1131 else
1133 char *t = s;
1134 int macrocode;
1135 char tchar = '\0';
1136 annotationInfo ainfo;
1138 while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
1140 s++;
1143 if (*s != '\0')
1145 tchar = *s;
1146 *s = '\0';
1147 s++;
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));
1157 sfree (t);
1158 sfree (os);
1159 fileloc_free (loc);
1161 if (macrocode == SKIPTOK)
1163 return BADTOK;
1166 return macrocode;
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;
1174 s_tokLength = 0;
1175 sfree (os);
1176 sfree (t);
1177 fileloc_free (loc);
1178 return CANNOTATION;
1181 if (context_inHeader ())
1183 if (tchar != '\0')
1185 *(s-1) = tchar;
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 */
1196 else
1198 context_addComment (cstring_fromCharsNew (os), loc);
1201 else
1206 if (tchar != '\0')
1208 *(s-1) = '\0';
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');
1232 int val = -1;
1233 char *tt = t; /* don't mangle t, since it is free'd */
1234 char lc = *(++tt);
1236 if (lc >= '0' && lc <= '9')
1238 val = (int)(lc - '0');
1240 lc = *(++tt);
1241 while (lc >= '0' && lc <= '9')
1243 val *= 10;
1244 val += (int) (lc - '0');
1245 lc = *(++tt);
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"))
1269 cstring tname;
1271 while (TRUE)
1273 while (((c = *s) != '\0') && (c == ' ' || c == '\t' || c == '\n'))
1275 s++;
1278 if (c == '\0')
1280 break;
1283 tname = cstring_fromChars (s);
1285 while ((c = *s) != '\0' && c != ' '
1286 && c != '\t' && c != '\n' && c != ',')
1288 s++;
1291 *s = '\0';
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));
1308 else
1310 voptgenerror
1311 (FLG_COMMENTERROR,
1312 message
1313 ("Non-abstract type %s used in access comment",
1314 tname),
1315 loc);
1318 else
1320 if (!(context_inSuppressRegion ()
1321 || context_inSuppressZone (loc)))
1323 voptgenerror
1324 (FLG_COMMENTERROR,
1325 message
1326 ("Unrecognized type %s used in access comment",
1327 tname),
1328 loc);
1333 if (c != '\0')
1335 s++;
1338 if (c != ',' && c != ' ')
1340 break;
1344 else if (mstring_equal (t, "noaccess"))
1346 cstring tname;
1347 char lc;
1349 while (TRUE)
1351 while (((lc = *s) != '\0') && (lc == ' ' || lc == '\t' || lc == '\n'))
1353 s++;
1356 if (lc == '\0')
1358 break;
1361 tname = cstring_fromChars (s);
1363 while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
1364 && lc != '\n' && lc != ',')
1366 s++;
1369 *s = '\0';
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);
1383 else
1385 if (!(context_inSuppressRegion ()
1386 || context_inSuppressZone (loc)))
1388 uentry ue = usymtab_getTypeEntry (tuid);
1390 if (uentry_isAbstractDatatype (ue))
1392 voptgenerror
1393 (FLG_COMMENTERROR,
1394 message
1395 ("Non-accessible abstract type %s used in noaccess comment",
1396 tname),
1397 loc);
1399 else
1401 voptgenerror
1402 (FLG_COMMENTERROR,
1403 message
1404 ("Non-abstract type %s used in noaccess comment",
1405 tname),
1406 loc);
1411 else
1413 if (!(context_inSuppressRegion ()
1414 || context_inSuppressZone (loc)))
1416 voptgenerror
1417 (FLG_COMMENTERROR,
1418 message
1419 ("Unrecognized type %s used in noaccess comment",
1420 tname),
1421 loc);
1426 if (lc != '\0')
1428 s++;
1431 if (lc != ',' && lc != ' ')
1433 break;
1437 else
1439 voptgenerror (FLG_UNRECOGCOMMENTS,
1440 message ("Semantic comment unrecognized: %s",
1441 cstring_fromChars (os)),
1442 loc);
1443 /*@-branchstate@*/
1444 } /* spurious (?) warning about t */
1445 /*@=branchstate@*/
1447 sfree (t);
1450 sfree (os);
1451 fileloc_free (loc);
1452 return BADTOK;
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 == '$'))
1462 *c++ = *s++;
1465 *c = '\0';
1466 return (id);
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 ())
1483 voptgenerror
1484 (FLG_SYSTEMUNRECOG,
1485 message ("Unrecognized (possibly system) identifier: %q",
1486 uentry_getName (ce)),
1487 g_currentloc);
1490 return 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;
1519 return res;
1522 static void cscanner_setLastIdentifier (/*@keep@*/ cstring id) /*@modifies s_lastidprocessed@*/
1524 if (cstring_isDefined (s_lastidprocessed))
1526 cstring_free (s_lastidprocessed);
1529 s_lastidprocessed = id;
1532 static int
1533 cscannerHelp_processIdentifier (/*@only@*/ cstring id)
1534 /*@modifies internalState@*/
1536 uentry le;
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));
1553 if (tok != BADTOK)
1555 return tok;
1557 else
1559 tok = tokenMacroCode (id);
1561 if (tok != BADTOK)
1563 return tok;
1565 else
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;
1578 else
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;
1590 return CANNOTATION;
1592 else
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))
1606 int tok = BADTOK;
1608 if (cstring_equalLit (id, "__stdcall")
1609 || cstring_equalLit (id, "__cdecl")
1610 || cstring_equalLit (id, "__extension__"))
1612 return BADTOK;
1614 else if (cstring_equalLit (id, "__volatile__"))
1616 tok = QVOLATILE;
1618 else if (cstring_equalLit (id, "__signed"))
1620 tok = QSIGNED;
1622 else if (cstring_equalLit (id, "__unsigned"))
1624 tok = QUNSIGNED;
1626 else if (cstring_equalLit (id, "__const__"))
1628 tok = QCONST;
1630 else if (cstring_equalLit (id, "__alignof__"))
1632 tok = CALIGNOF; /* alignof is parsed like sizeof */
1634 else if (cstring_equalLit (id, "__typeof__"))
1636 tok = CTYPEOF;
1638 else if (cstring_equalLit (id, "typeof"))
1640 tok = CTYPEOF;
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));
1648 s_tokLength = 0;
1649 tok = CCONSTANT;
1650 return tok;
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"))
1658 int depth = 0;
1659 bool useparens = FALSE;
1660 bool usebraces = FALSE;
1661 bool inquote = FALSE;
1662 bool inescape = FALSE;
1663 int ic;
1665 while ((ic = cscanner_input ()) != EOF)
1667 char cc = (char) ic;
1669 if (inescape)
1671 inescape = FALSE;
1673 else if (cc == '\\')
1675 inescape = TRUE;
1677 else if (cc == '\"')
1679 inquote = !inquote;
1681 else if (!inquote)
1683 if (cc == '(')
1685 if (!useparens)
1687 if (!usebraces)
1689 useparens = TRUE;
1693 if (useparens)
1695 depth++;
1698 else if (cc == '{')
1700 if (!usebraces)
1702 if (!useparens)
1704 usebraces = TRUE;
1708 if (usebraces)
1710 depth++;
1713 else if (cc == ')' && useparens)
1715 depth--;
1716 if (depth == 0) break;
1718 else if (cc == '}' && usebraces)
1720 depth--;
1721 if (depth == 0) break;
1723 else if (cc == '}'
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
1731 ** the asm code!
1733 return TRBRACE;
1735 else
1740 else
1745 if (cc == '\n')
1747 context_incLineno ();
1749 if (cstring_equalLit (id, "__asm")
1750 && !useparens && !usebraces)
1752 break;
1757 llassert ((useparens && ic == (int) ')')
1758 || (usebraces && ic == (int) '}')
1759 || (!useparens && !usebraces));
1761 return BADTOK;
1763 else if (cstring_equalLit (id, "inline")
1764 || cstring_equalLit (id, "__inline")
1765 || cstring_equalLit (id, "_inline")
1766 || cstring_equalLit (id, "__inline__"))
1768 tok = QINLINE;
1770 else
1775 if (tok != BADTOK)
1777 return (cscannerHelp_returnToken (tok));
1781 le = usymtab_lookupSafe (id);
1783 /*@-dependenttrans@*/
1785 if (uentry_isIter (le))
1787 c_lval.entry = le;
1788 return (ITER_NAME);
1790 else if (uentry_isEndIter (le))
1792 c_lval.entry = 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);
1816 else
1818 c_lval.entry = le;
1819 return (IDENTIFIER);
1822 else if (uentry_isDatatype (le))
1824 if (!s_expectingTypeName)
1826 c_lval.cname = cstring_copy (id);
1828 return (NEW_IDENTIFIER);
1830 else
1832 c_lval.ctyp = uentry_getAbstractType (le);
1834 uentry_setUsed (le, g_currentloc);
1835 return (TYPE_NAME);
1838 else
1840 c_lval.entry = le;
1841 return (IDENTIFIER);
1844 /*@=dependenttrans@*/
1847 bool cscannerHelp_processHashIdentifier (/*@only@*/ cstring id)
1849 if (context_inMacro () || context_inIterDef () ||
1850 context_inIterEnd ())
1852 uentry le;
1854 context_clearJustPopped ();
1856 le = usymtab_lookupSafe (id);
1857 cscanner_setLastIdentifier (id);
1859 if (uentry_isParam (le) || uentry_isRefParam (le))
1861 return TRUE;
1863 else
1865 return FALSE;
1868 else
1871 ** Will be handled by handleLlSpecial
1874 cstring_free (id);
1875 return FALSE;
1879 /*@only@*/ exprNode cscannerHelp_processString (void)
1881 exprNode res;
1882 fileloc loc;
1883 char *nl = strchr (c_text, '\n');
1884 cstring ns = cstring_fromCharsNew (c_text);
1886 if (nl == NULL)
1888 loc = fileloc_copy (g_currentloc);
1889 addColumn (size_toInt (cstring_length (ns)));
1891 else
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);
1905 return (res);
1909 ** process a wide character string L"...."
1912 /*@only@*/ exprNode cscannerHelp_processWideString (void)
1914 exprNode res;
1915 fileloc loc;
1916 char *nl = strchr (c_text, '\n');
1917 cstring ns;
1919 llassert (*c_text == 'L');
1920 c_text++;
1922 ns = cstring_fromCharsNew (c_text);
1924 if (nl == NULL)
1926 loc = fileloc_copy (g_currentloc);
1927 addColumn (size_toInt (cstring_length (ns)));
1929 else
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);
1942 return (res);
1945 char cscannerHelp_processChar (void)
1947 char fchar;
1948 char next;
1950 llassert (*c_text != '\0');
1951 fchar = *(c_text + 1);
1952 if (fchar != '\\') return fchar;
1954 next = *(c_text + 2);
1956 switch (next)
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);
1971 return (ret);
1974 long cscannerHelp_processHex (void)
1976 int index = 2;
1977 long val = 0;
1979 llassert (c_text[0] == '0'
1980 && (c_text[1] == 'X' || c_text[1] == 'x'));
1982 while (c_text[index] != '\0') {
1983 int tval;
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') {
1993 index++;
1994 while (c_text[index] != '\0') {
1995 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
1997 } else {
1998 voptgenerror
1999 (FLG_SYNTAX,
2000 message ("Invalid character (%c) following specifier in hex constant: %s",
2001 c, cstring_fromChars (c_text)),
2002 g_currentloc);
2004 index++;
2007 break;
2008 } else {
2009 voptgenerror
2010 (FLG_SYNTAX,
2011 message ("Invalid character (%c) in hex constant: %s",
2012 c, cstring_fromChars (c_text)),
2013 g_currentloc);
2014 break;
2017 val = (val * 16) + tval;
2018 index++;
2021 DPRINTF (("Hex constant: %s = %ld", c_text, val));
2022 return val;
2025 long cscannerHelp_processOctal (void)
2027 int index = 1;
2028 long val = 0;
2030 llassert (c_text[0] == '0' && c_text[1] != 'X' && c_text[1] != 'x');
2032 while (c_text[index] != '\0') {
2033 int tval;
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') {
2039 index++;
2040 while (c_text[index] != '\0') {
2041 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2043 } else {
2044 voptgenerror
2045 (FLG_SYNTAX,
2046 message ("Invalid character (%c) following specifier in octal constant: %s",
2047 c, cstring_fromChars (c_text)),
2048 g_currentloc);
2050 index++;
2053 break;
2054 } else {
2055 voptgenerror
2056 (FLG_SYNTAX,
2057 message ("Invalid character (%c) in octal constant: %s",
2058 c, cstring_fromChars (c_text)),
2059 g_currentloc);
2060 break;
2063 val = (val * 8) + tval;
2064 index++;
2067 DPRINTF (("Octal constant: %s = %ld", c_text, val));
2068 return val;
2071 long cscannerHelp_processDec (void)
2073 return (atol (c_text));
2076 int cscannerHelp_processSpec (int tok)
2078 size_t length = strlen (c_text);
2080 if (s_inSpecPart)
2083 /*drl 12/11/2002
2084 patched to fix assert failures in constraint code.
2085 Added the else if test so that splint does not treat MaxSet and MaxRead
2086 as identifies*/
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. */
2116 else
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)
2154 uentry e2;
2155 ctype ct;
2156 int noparams = 0;
2157 cstring fname = cstring_undefined;
2158 bool res = TRUE;
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"));
2177 fileloc_free (loc);
2178 return FALSE;
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')
2191 char oldc = c;
2193 if (c != '\n')
2195 while (c == ' ' || c == '\t')
2197 c = macro_nextChar ();
2199 cscanner_unput ((int) c);
2202 if (c == '\n')
2204 emptyMacro = TRUE;
2205 cscanner_unput ((int) c);
2208 c = oldc;
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)))
2221 if (optgenerror
2222 (FLG_MACROREDEF,
2223 message ("Macro %s already defined", fname),
2224 loc))
2226 uentry_showWhereDefined (e2);
2227 uentry_clearDefined (e2);
2230 if (uentry_isFunction (e2))
2232 uentry_setType (e2, ctype_unknown);
2233 ct = ctype_unknown;
2234 unknownm = TRUE;
2235 context_enterUnknownMacro (e2);
2237 else
2239 context_enterConstantMacro (e2);
2242 else if (uentry_isForward (e2) && uentry_isFunction (e2))
2244 unknownm = TRUE;
2246 voptgenerror
2247 (FLG_MACROFCNDECL,
2248 message
2249 ("Parameterized macro has no prototype or specification: %s ",
2250 fname),
2251 loc);
2253 ct = ctype_unknown;
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))
2261 isiter = TRUE;
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))
2275 if (hasParams)
2277 voptgenerror
2278 (FLG_INCONDEFS,
2279 message ("Constant %s implemented as parameterized macro",
2280 fname),
2281 g_currentloc);
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);
2290 else
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))
2303 if (!emptyMacro)
2305 voptgenerror
2306 (FLG_MACROCONSTDECL,
2307 message
2308 ("Macro constant %q not declared",
2309 uentry_getName (e2)),
2310 loc);
2313 else if (!fileloc_withinLines (oloc, loc, 2))
2314 { /* bogus! will give errors if there is too much whitespace */
2315 voptgenerror
2316 (FLG_MACROCONSTDIST,
2317 message
2318 ("Macro constant name %s matches name in "
2319 "distant constant declaration. This constant "
2320 "is declared at %q", fname,
2321 fileloc_unparse (oloc)),
2322 loc);
2324 else
2326 /* No warning */
2330 context_enterConstantMacro (e2);
2331 cstring_free (fname);
2332 fileloc_free (loc);
2333 return res;
2336 else if (ctype_isFunction (ct))
2338 isspecfcn = TRUE;
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))
2347 if (hasParams)
2349 voptgenerror
2350 (FLG_INCONDEFS,
2351 message ("Variable %s implemented as parameterized macro",
2352 fname),
2353 loc);
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);
2362 else
2364 uentry ucons = uentry_makeConstant (fname,
2365 ctype_unknown,
2366 loc);
2367 if (uentry_isExpandedMacro (e2))
2369 ; /* okay */
2371 else
2373 if (optgenerror
2374 (FLG_INCONDEFS,
2375 message ("Variable %s implemented by a macro",
2376 fname),
2377 loc))
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);
2389 return res;
2392 else if (uentry_isDatatype (e2))
2394 vgenhinterror
2395 (FLG_SYNTAX,
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."),
2400 g_currentloc);
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);
2406 res = FALSE;
2408 else
2410 llcontbug
2411 (message ("Unexpanded macro not function or constant: %q",
2412 uentry_unparse (e2)));
2413 uentry_setType (e2, ctype_unknown);
2415 if (hasParams)
2417 uentry_makeVarFunction (e2);
2418 uentry_setDefined (e2, g_currentloc);
2419 uentry_setFunctionDefined (e2, g_currentloc);
2420 context_enterUnknownMacro (e2);
2424 else
2426 uentry ce;
2428 /* evans 2001-09-09 - if it has params, assume a function */
2429 if (hasParams)
2431 voptgenerror
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.",
2436 fname),
2437 loc);
2439 ce = uentry_makeFunction (fname, ctype_unknown,
2440 typeId_invalid,
2441 globSet_undefined,
2442 sRefSet_undefined,
2443 warnClause_undefined,
2444 fileloc_undefined);
2445 uentry_setUsed (ce, loc); /* perhaps bogus? */
2446 e2 = usymtab_supEntryReturn (ce);
2447 context_enterUnknownMacro (e2);
2449 else
2451 voptgenerror
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.)",
2457 fname),
2458 loc);
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);
2466 fileloc_free (loc);
2467 return res;
2471 /* in macros, ( must follow immediatetly after name */
2473 if (hasParams)
2475 int paramno = 0;
2477 c = skip_whitespace ();
2479 while (c != ')' && c != '\0')
2481 uentry param;
2482 bool suppress = context_inSuppressRegion ();
2483 cstring paramname = cstring_undefined;
2486 ** save the parameter location
2489 decColumn ();
2490 context_saveLocation ();
2491 incColumn ();
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 ();
2501 if (c == ',')
2503 c = macro_nextChar ();
2504 if (c == ' ' || c == '\t') c = skip_whitespace ();
2507 if (c == '\0')
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);
2519 sRef sr;
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);
2540 else
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));
2551 else
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);
2565 skipparam = FALSE;
2566 fileloc_free (sloc);
2569 if (!skipparam)
2571 llassert (!uentry_isElipsisMarker (param));
2573 if (!suppress)
2575 sRef_makeUnsafe (uentry_getSref (param));
2578 pn = uentryList_add (pn, uentry_copy (param));
2579 usymtab_supEntry (param);
2581 else
2583 /* don't add param */
2584 uentry_free (param);
2587 if (c == ',')
2589 (void) macro_nextChar ();
2590 c = skip_whitespace ();
2593 paramno++;
2596 if (c == ')')
2598 if (isspecfcn || isiter)
2600 if (paramno != noparams && noparams >= 0)
2602 cscannerHelp_advanceLine ();
2604 voptgenerror
2605 (FLG_INCONDEFS,
2606 message ("Macro %s specified with %d args, defined with %d",
2607 fname, noparams, paramno),
2608 g_currentloc);
2610 uentry_showWhereSpecified (e2);
2611 uentry_resetParams (e2, pn);
2614 else
2616 uentry_resetParams (e2, pn);
2620 else
2623 ** the form should be:
2625 ** # define newname oldname
2626 ** where oldname refers to a function matching the specification
2627 ** of newname.
2630 if (unknownm)
2632 sRef_setGlobalScope ();
2633 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
2634 sRef_clearGlobalScope ();
2636 else
2638 context_setMacroMissingParams ();
2643 /* context_setuentryList (pn); */
2644 usymtab_enterScope ();
2646 fileloc_free (loc);
2647 cstring_free (fname);
2649 return res;
2652 void cscannerHelp_setTokLength (int len)
2654 addColumn (len);
2655 s_tokLength = 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)
2666 s_tokLength = 0;
2667 beginLine ();
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));
2674 } else {
2675 c_lval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, s_tokLength));
2678 s_tokLength = 0;
2679 return (t);
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));
2691 s_tokLength = 0;
2692 return (CCONSTANT);
2695 int cscannerHelp_returnInt (ctype ct, long val)
2697 ctype c = ct;
2699 if (ctype_equal (ct, ctype_int))
2701 if (val == 0)
2703 c = context_typeofZero ();
2705 else if (val == 1)
2707 c = context_typeofOne ();
2709 else
2715 c_lval.expr = exprNode_numLiteral (c, cstring_fromChars (c_text),
2716 fileloc_decColumn (g_currentloc, s_tokLength),
2717 val);
2718 s_tokLength = 0;
2719 return (CCONSTANT);
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));
2726 s_tokLength = 0;
2727 return (CCONSTANT);
2730 int cscannerHelp_returnChar (char c)
2732 c_lval.expr = exprNode_charLiteral (c, cstring_fromChars (c_text),
2733 fileloc_decColumn (g_currentloc, s_tokLength));
2734 s_tokLength = 0;
2735 return (CCONSTANT);
2738 int cscannerHelp_returnType (int tok, ctype ct)
2740 c_lval.ctyp = ct;
2741 s_tokLength = 0;
2742 return tok;
2745 int cscannerHelp_returnExpr (exprNode e)
2747 c_lval.expr = e;
2748 s_tokLength = 0;
2749 return (CCONSTANT);
2752 void cscannerHelp_setExpectingTypeName (void)
2754 s_expectingTypeName = TRUE;
2757 void cscannerHelp_clearExpectingTypeName (void)
2759 s_expectingTypeName = FALSE;
2762 # ifdef DEADCODE
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) {
2783 s_tokLength = 0;
2784 /* No error to report
2785 voptgenerror
2786 (FLG_SYNTAX,
2787 message ("Likely parse error: token spans multiple lines."),
2788 g_currentloc);
2792 if (s_continueLine)
2794 s_continueLine = FALSE;
2796 else
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));
2803 return TENDMACRO;
2807 return BADTOK;
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;