Some consistency changes to library & headers flags.
[splint-patched.git] / src / cscannerHelp.c
blob47b1f263c07c86438556e8d81faab554a3e583b0
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 { "requires", QPRECLAUSE } ,
75 { "ensures", QPOSTCLAUSE } ,
76 { NULL, BADTOK }
77 } ;
80 ** These tokens are either stand-alone tokens, or followed by
81 ** token-specific text.
84 static struct skeyword s_keytable[] = {
85 { "anytype", QANYTYPE } ,
86 { "integraltype", QINTEGRALTYPE } ,
87 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,
88 { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,
89 { "out", QOUT } ,
90 { "in", QIN } ,
91 { "only", QONLY } ,
92 { "owned", QOWNED } ,
93 { "dependent", QDEPENDENT } ,
94 { "partial", QPARTIAL } ,
95 { "special", QSPECIAL } ,
96 { "truenull", QTRUENULL } ,
97 { "falsenull", QFALSENULL } ,
98 { "nullwhentrue", QTRUENULL } ,
99 { "falsewhennull", QFALSENULL } ,
100 { "keep", QKEEP } ,
101 { "kept", QKEPT } ,
102 { "notnull", QNOTNULL } ,
103 { "abstract", QABSTRACT } ,
104 { "numabstract", QNUMABSTRACT } ,
105 { "concrete", QCONCRETE } ,
106 { "mutable", QMUTABLE } ,
107 { "immutable", QIMMUTABLE } ,
108 { "unused", QUNUSED } ,
109 { "external", QEXTERNAL } ,
110 { "sef", QSEF } ,
111 { "unique", QUNIQUE } ,
112 { "returned", QRETURNED } ,
113 { "exposed", QEXPOSED } ,
114 { "refcounted", QREFCOUNTED } ,
115 { "refs", QREFS } ,
116 { "newref", QNEWREF } ,
117 { "tempref", QTEMPREF } ,
118 { "killref", QKILLREF } ,
119 { "null", QNULL } ,
120 { "relnull", QRELNULL } ,
121 { "nullterminated", QNULLTERMINATED },
122 { "isnull", QISNULL },
123 { "MaxSet", QMAXSET},
124 { "MaxRead", QMAXREAD},
125 { "maxSet", QMAXSET},
126 { "maxRead", QMAXREAD},
127 { "reldef", QRELDEF } ,
128 { "observer", QOBSERVER } ,
129 { "exits", QEXITS } ,
130 { "noreturn", QEXITS } ,
131 { "mayexit", QMAYEXIT } ,
132 { "maynotreturn", QMAYEXIT } ,
133 { "trueexit", QTRUEEXIT } ,
134 { "falseexit", QFALSEEXIT } ,
135 { "noreturnwhentrue", QTRUEEXIT } ,
136 { "noreturnwhenfalse", QFALSEEXIT } ,
137 { "neverexit", QNEVEREXIT } ,
138 { "alwaysreturns", QNEVEREXIT } ,
139 { "temp", QTEMP } ,
140 { "shared", QSHARED } ,
141 { "ref", QREF } ,
142 { "unchecked", QUNCHECKED } ,
143 { "checked", QCHECKED } ,
144 { "checkmod", QCHECKMOD } ,
145 { "checkedstrict", QCHECKEDSTRICT } ,
146 { "innercontinue", QINNERCONTINUE } ,
147 { "innerbreak", QINNERBREAK } ,
148 { "loopbreak", QLOOPBREAK } ,
149 { "switchbreak", QSWITCHBREAK } ,
150 { "safebreak", QSAFEBREAK } ,
151 { "fallthrough", QFALLTHROUGH } ,
152 { "l_fallthrou", QLINTFALLTHROUGH } ,
153 { "l_fallth", QLINTFALLTHRU } ,
154 { "notreached", QNOTREACHED } ,
155 { "l_notreach", QLINTNOTREACHED } ,
156 { "printflike", QPRINTFLIKE } ,
157 { "l_printfli", QLINTPRINTFLIKE } ,
158 { "scanflike", QSCANFLIKE } ,
159 { "messagelike", QMESSAGELIKE } ,
160 { "l_argsus", QARGSUSED } ,
161 { NULL, BADTOK }
164 static bool cscannerHelp_isSpecTokenRegularId (int p_tok) /*@*/;
165 static void cscannerHelp_advanceLine (void) /*@modifies g_currentloc, internalState@*/ ;
168 ** would be better if these weren't hard coded...
171 static bool isArtificial (cstring s)
173 return (cstring_equalLit (s, "modifies")
174 || cstring_equalLit (s, "globals")
175 || cstring_equalLit (s, "warn")
176 || cstring_equalLit (s, "alt"));
179 void cscannerHelp_swallowMacro (void)
181 int i;
182 bool skipnext = FALSE;
184 while ((i = lminput ()) != EOF)
186 char c = (char) i;
188 if (c == '\\')
190 skipnext = TRUE;
192 else if (c == '\n')
194 if (skipnext)
196 skipnext = FALSE;
198 else
200 reader_checkUngetc (i, c_in);
201 return;
204 else
210 if (i != EOF)
212 reader_checkUngetc (i, c_in);
216 static int commentMarkerToken (cstring s)
218 int i = 0;
220 while (s_parsetable[i].name != NULL)
222 DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name));
224 if (cstring_equalLit (s, s_parsetable[i].name))
226 return s_parsetable[i].token;
229 i++;
232 return BADTOK;
235 static int tokenMacroCode (cstring s)
237 int i = 0;
239 while (s_keytable[i].name != NULL)
241 if (cstring_equalLit (s, s_keytable[i].name))
243 if (s_keytable[i].token == QLINTFALLTHROUGH)
245 voptgenerror
246 (FLG_WARNLINTCOMMENTS,
247 cstring_makeLiteral
248 ("Traditional lint comment /*FALLTHROUGH*/ used. "
249 "Splint interprets this in the same way as most Unix lints, but it is "
250 "preferable to replace it with the /*@fallthrough@*/ "
251 "semantic comment"),
252 g_currentloc);
253 return QFALLTHROUGH;
255 else if (s_keytable[i].token == QLINTFALLTHRU)
257 voptgenerror
258 (FLG_WARNLINTCOMMENTS,
259 cstring_makeLiteral
260 ("Traditional lint comment /*FALLTHRU*/ used. "
261 "Splint interprets this in the same way as most Unix lints, but it is "
262 "preferable to replace it with the /*@fallthrough@*/ "
263 "semantic comment"),
264 g_currentloc);
265 return QFALLTHROUGH;
267 else if (s_keytable[i].token == QLINTNOTREACHED)
269 voptgenerror
270 (FLG_WARNLINTCOMMENTS,
271 cstring_makeLiteral
272 ("Traditional lint comment /*NOTREACHED*/ used. "
273 "Splint interprets this in the same way as most Unix lints, but it is "
274 "preferable to replace it with the /*@notreached@*/ "
275 "semantic comment."),
276 g_currentloc);
278 return QNOTREACHED;
280 else if (s_keytable[i].token == QPRINTFLIKE)
282 setSpecialFunction (qual_createPrintfLike ());
283 return SKIPTOK;
285 else if (s_keytable[i].token == QLINTPRINTFLIKE)
287 voptgenerror
288 (FLG_WARNLINTCOMMENTS,
289 cstring_makeLiteral
290 ("Traditional lint comment /*PRINTFLIKE*/ used. "
291 "Splint interprets this in the same way as most Unix lints, but it is "
292 "preferable to replace it with either /*@printflike@*/, "
293 "/*@scanflike@*/ or /*@messagelike@*/."),
294 g_currentloc);
296 setSpecialFunction (qual_createPrintfLike ());
297 return SKIPTOK;
299 else if (s_keytable[i].token == QSCANFLIKE)
301 setSpecialFunction (qual_createScanfLike ());
302 return SKIPTOK;
304 else if (s_keytable[i].token == QMESSAGELIKE)
306 setSpecialFunction (qual_createMessageLike ());
307 return SKIPTOK;
309 else if (s_keytable[i].token == QARGSUSED)
311 voptgenerror
312 (FLG_WARNLINTCOMMENTS,
313 cstring_makeLiteral
314 ("Traditional lint comment /*ARGSUSED*/ used. "
315 "Splint interprets this in the same way as most Unix lints, but it is "
316 "preferable to use /*@unused@*/ annotations on "
317 "the unused parameters."),
318 g_currentloc);
320 setArgsUsed ();
321 return SKIPTOK;
323 else
325 return s_keytable[i].token;
329 i++;
332 return BADTOK;
335 static int lminput (void)
337 if (s_savechar == '\0')
339 incColumn ();
340 return (cscanner_input ());
342 else
344 int save = (int) s_savechar;
345 s_savechar = '\0';
346 return save;
350 static void lmsavechar (char c)
352 if (s_savechar == '\0')
354 s_savechar = c;
356 else
358 llbuglit ("lmsavechar: override");
362 int cscannerHelp_ninput (void)
364 int c = lminput ();
366 if (c != EOF && ((char)c == '\n'))
368 context_incLineno ();
371 return c;
374 static char macro_nextChar (void)
376 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
377 int ic;
378 char c;
380 ic = lminput ();
381 c = char_fromInt (ic);
383 if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
385 if (c == '\\')
387 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
389 ; /* skip to newline */
392 context_incLineno ();
394 if (c != '\0')
396 return macro_nextChar ();
398 else
400 return c;
403 else /* if (c == '@') */
405 llassert (FALSE);
407 if (cscannerHelp_handleLlSpecial () != BADTOK)
409 llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
412 return macro_nextChar ();
415 else if (!in_escape && c == '\"')
417 in_quote = !in_quote;
419 else if (!in_escape && c == '\'')
421 in_char = !in_char;
423 else if ((in_quote || in_char) && c == '\\')
425 in_escape = !in_escape;
427 else if ((in_quote || in_char) && in_escape)
429 in_escape = FALSE;
431 else if (!in_quote && c == '/')
433 char c2;
435 if ((c2 = char_fromInt (lminput ())) == '*')
437 while (c2 != '\0')
439 while ((c2 = char_fromInt (lminput ())) != '\0'
440 && c2 != '\n' && c2 != '*')
445 if (c2 == '*')
447 while ((c2 = char_fromInt (lminput ())) != '\0'
448 && c2 == '*')
453 if (c2 == '/')
455 goto outofcomment;
458 else
460 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
463 outofcomment:
464 return macro_nextChar ();
466 else
468 /*** putchar does not work! why? puts to stdio...??! ***/
469 lmsavechar (c2);
472 else
477 return c;
481 ** keeps semantic comments
484 static char macro_nextCharC (void)
486 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
487 char c;
489 c = char_fromInt (lminput ());
491 if (!in_quote && !in_char && c == '\\')
493 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
495 ; /* skip to newline */
498 context_incLineno ();
500 if (c != '\0')
502 return macro_nextCharC ();
504 else
506 return c;
509 else if (!in_escape && c == '\"')
511 in_quote = !in_quote;
513 else if (!in_escape && c == '\'')
515 in_char = !in_char;
517 else if ((in_quote || in_char) && c == '\\')
519 in_escape = !in_escape;
521 else if ((in_quote || in_char) && in_escape)
523 in_escape = FALSE;
525 else if (!in_quote && c == '/')
527 char c2;
529 if ((c2 = char_fromInt (lminput ())) == '*')
531 while (c2 != '\0')
533 while ((c2 = char_fromInt (lminput ())) != '\0'
534 && c2 != '\n' && c2 != '*')
539 if (c2 == '*')
541 while ((c2 = char_fromInt (lminput ())) != '\0'
542 && c2 == '*')
547 if (c2 == '/')
549 goto outofcomment;
552 else
554 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
557 outofcomment:
558 return macro_nextCharC ();
560 else
562 lmsavechar (c2);
565 else /* normal character */
570 return c;
574 ** skips whitespace (handles line continuations)
575 ** returns first non-whitespace character
578 static char skip_whitespace (void)
580 char c;
582 while ((c = macro_nextChar ()) == ' ' || c == '\t')
587 return c;
590 void cscannerHelp_handleMacro (void)
592 cstring mac = cstring_undefined;
593 int macrocode;
594 char c;
596 while (currentColumn () > 2)
598 mac = cstring_appendChar (mac, ' ');
599 cscannerHelp_setTokLength (-1);
602 c = macro_nextCharC ();
604 if (c >= '0' && c <= '9')
606 int i;
608 for (i = 0; i < (((int) (c - '0')) + 1); i++)
610 mac = cstring_appendChar (mac, ' ');
613 else
615 BADBRANCH;
618 while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
620 mac = cstring_appendChar (mac, c);
623 macrocode = tokenMacroCode (mac);
625 if (macrocode == BADTOK && !isArtificial (mac))
627 context_addMacroCache (mac);
629 else
631 cstring_free (mac);
634 if (c == '\n')
636 context_incLineno ();
640 bool cscannerHelp_handleSpecial (char *text)
642 char *l; /* !! = mstring_create (MAX_NAME_LENGTH); */
643 int lineno = 0;
644 char c;
645 char *ol;
646 cstring olc;
648 l = mstring_copy (text + 1);
650 while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
652 l = mstring_append(l, c);
655 ol = l;
657 olc = cstring_fromChars (ol);
659 if (cstring_equalPrefixLit (olc, "pragma"))
661 char *pname = mstring_create (size_fromInt (MAX_PRAGMA_LEN));
662 char *opname = pname;
663 char *ptr = ol + 6; /* pragma is six characters, plus space */
664 int len = 0;
667 /* skip whitespace */
668 while (((c = *ptr) != '\0') && isspace (c))
670 ptr++;
674 while (((c = *ptr) != '\0') && !isspace (c))
676 len++;
678 if (len > MAX_PRAGMA_LEN)
680 break;
683 ptr++;
684 *pname++ = c;
687 *pname = '\0';
689 if (len == PRAGMA_LEN_EXPAND
690 && mstring_equal (opname, PRAGMA_EXPAND))
692 cstring exname = cstring_undefined;
693 uentry ue;
695 ptr++;
696 while (((c = *ptr) != '\0') && !isspace (c))
698 exname = cstring_appendChar (exname, c);
699 ptr++;
703 ue = usymtab_lookupExposeGlob (exname);
705 if (uentry_isExpandedMacro (ue))
707 if (fileloc_isPreproc (uentry_whereDefined (ue)))
709 fileloc_setColumn (g_currentloc, 1);
710 uentry_setDefined (ue, g_currentloc);
714 cstring_free (exname);
717 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: pragment increments line */
719 else if (cstring_equalPrefixLit (olc, "ident"))
721 /* Some pre-processors will leave these in the code. Ignore rest of line */
722 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: ident increments line */
726 ** Yuk...Win32 filenames can have spaces in them...we need to read
727 ** to the matching end quote.
729 else if ((sscanf (ol, "line %d \"", &lineno) == 1)
730 || (sscanf (ol, " %d \"", &lineno) == 1))
732 char *tmp = ol;
733 cstring fname;
734 fileId fid;
736 /*@access cstring@*/
737 while (*tmp != '\"' && *tmp != '\0')
739 tmp++;
742 llassert (*tmp == '\"');
743 tmp++;
744 fname = tmp;
746 while (*tmp != '\"' && *tmp != '\0')
748 tmp++;
751 llassert (*tmp == '\"');
752 *tmp = '\0';
754 # if defined(OS2) || defined(WIN32)
757 ** DOS-like path delimiters get delivered in pairs, something like
758 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
759 ** remove the pre dirs yet as we usually specify tmp paths relative
760 ** to the current directory, so tmp files would not get found in
761 ** the hash table. If this method fails we try it again later.
765 char *stmp = fname;
768 ** Skip past the drive marker.
771 if (strchr (stmp, ':') != NULL)
773 stmp = strchr (stmp, ':') + 1;
776 while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
778 if (*(stmp+1) == CONNECTCHAR)
780 memmove (stmp, stmp+1, strlen (stmp));
783 stmp++;
786 fid = fileTable_lookupBase (context_fileTable (), fname);
787 if (!(fileId_isValid (fid)))
789 fname = osd_removePreDirs (fname);
790 fid = fileTable_lookupBase (context_fileTable (), fname);
793 # else
794 fname = osd_removePreDirs (fname);
795 fid = fileTable_lookupBase (context_fileTable (), fname);
796 # endif
798 if (!(fileId_isValid (fid)))
800 fileType ftype;
802 if (context_inXHFile ())
804 ftype = FILE_XH; /* Files included by XH files are also XH files */
806 else if (fileLib_isHeader (fname))
808 ftype = FILE_HEADER;
810 else
812 ftype = FILE_NORMAL;
815 fid = fileTable_addFile (context_fileTable (), ftype, fname);
818 setFileLine (fid, lineno);
819 /*@noaccess cstring@*/
821 else if ((sscanf (ol, "line %d", &lineno) == 1)
822 || (sscanf (ol, " %d", &lineno) == 1))
824 setLine (lineno); /* next line is <cr> */
826 else
828 if (mstring_equal (ol, "")) {
829 DPRINTF (("Empty pp command!"));
831 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
832 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
834 mstring_free (ol);
835 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
836 return FALSE;
837 } else {
838 voptgenerror
839 (FLG_UNRECOGDIRECTIVE,
840 message ("Unrecognized pre-processor directive: #%s",
841 cstring_fromChars (ol)),
842 g_currentloc);
843 (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
846 sfree (ol);
847 return FALSE; /* evans 2001-12-30: was: TRUE; */
850 sfree (ol);
851 return FALSE;
854 int cscannerHelp_handleLlSpecial (void)
856 bool hasnl = FALSE;
857 int ic;
858 char c;
859 char *s = mstring_createEmpty ();
860 char *os;
861 int tok;
862 int charsread = 0;
863 fileloc loc;
865 loc = fileloc_copy (g_currentloc);
866 DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
868 while (((ic = cscannerHelp_ninput ()) != 0) && isalpha (ic))
870 c = (char) ic;
871 s = mstring_append (s, c);
872 charsread++;
875 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
876 os = s;
878 if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
880 ic = cscannerHelp_ninput ();
882 llassert (ic == (int) AFTER_COMMENT_MARKER[1]);
884 if (*s == '\0')
886 sfree (os);
887 fileloc_free (loc);
888 return QNOMODS; /* special token no modifications token */
892 DPRINTF (("Coment marker: %s", os));
893 tok = commentMarkerToken (cstring_fromChars (os));
895 if (tok != BADTOK)
897 s_tokLength = charsread;
898 sfree (os);
899 fileloc_free (loc);
901 s_inSpecPart = TRUE;
902 s_whichSpecPart = tok;
903 return tok;
906 DPRINTF (("Not a comment marker..."));
907 /* Add rest of the comment */
909 if (ic != 0 && ic != EOF)
911 c = (char) ic;
913 s = mstring_append (s, c);
914 charsread++;
916 while (((ic = cscannerHelp_ninput ()) != 0) && (ic != EOF)
917 && (ic != (int) AFTER_COMMENT_MARKER[0]))
919 c = (char) ic;
921 /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
923 if (c == '\n') {
924 hasnl = TRUE; /* This prevents tokLength from being set later. */
925 s_tokLength = 0;
927 voptgenerror
928 (FLG_SYNTAX,
929 message ("Likely parse error: syntactic comment token spans multiple lines: %s",
930 cstring_fromChars (s)),
931 loc);
934 s = mstring_append (s, c);
935 charsread++;
937 /*@-branchstate@*/
938 } /* spurious (?) warnings about s */
939 /*@=branchstate@*/
941 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
943 if (ic == (int) AFTER_COMMENT_MARKER[0])
945 int nc = cscannerHelp_ninput ();
946 llassert ((char) nc == AFTER_COMMENT_MARKER[1]);
947 charsread++;
950 os = s;
952 while (*s == ' ' || *s == '\t' || *s == '\n')
954 s++;
957 if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
959 c = *s;
961 while (c == '-' || c == '+' || c == '=')
963 ynm set = ynm_fromCodeChar (c);
964 cstring thisflag;
966 s++;
968 thisflag = cstring_fromChars (s);
970 while ((c = *s) != '\0' && (c != '-') && (c != '=')
971 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
973 s++;
976 *s = '\0';
978 if (!context_getFlag (FLG_NOCOMMENTS))
980 cstring flagname = thisflag;
981 flagcode fflag = flags_identifyFlag (flagname);
983 if (flagcode_isSkip (fflag))
987 else if (flagcode_isModeName (fflag))
989 if (ynm_isMaybe (set))
991 llerror
992 (FLG_BADFLAG,
993 message
994 ("Semantic comment attempts to restore flag %s. "
995 "A mode flag cannot be restored.",
996 flagname));
998 else
1000 context_setMode (flagname);
1003 else if (flagcode_isInvalid (fflag))
1005 voptgenerror
1006 (FLG_UNRECOGFLAGCOMMENTS,
1007 message ("Unrecognized option in semantic comment: %s",
1008 flagname),
1009 loc);
1011 else if (flagcode_isGlobalFlag (fflag))
1013 voptgenerror
1014 (FLG_BADFLAG,
1015 message
1016 ("Semantic comment attempts to set global flag %s. "
1017 "A global flag cannot be set locally.",
1018 flagname),
1019 loc);
1021 else
1023 context_fileSetFlag (fflag, set, loc);
1025 if (flagcode_hasArgument (fflag))
1027 if (ynm_isMaybe (set))
1029 voptgenerror
1030 (FLG_BADFLAG,
1031 message
1032 ("Semantic comment attempts to restore flag %s. "
1033 "A flag for setting a value cannot be restored.",
1034 flagname),
1035 loc);
1037 else
1038 { /* cut-and-pastied from llmain...blecch */
1039 cstring extra = cstring_undefined;
1040 char *rest;
1041 char *orest;
1042 char rchar;
1044 *s = c;
1045 rest = mstring_copy (s);
1046 orest = rest;
1047 *s = '\0';
1049 while ((rchar = *rest) != '\0'
1050 && (isspace (rchar)))
1052 rest++;
1053 s++;
1056 while ((rchar = *rest) != '\0'
1057 && !isspace (rchar))
1059 extra = cstring_appendChar (extra, rchar);
1060 rest++;
1061 s++;
1063 s--; /* evans 2002-07-12: this was previously only in the else branch.
1064 Leads to an invalid read on the true branch.
1067 sfree (orest);
1069 if (cstring_isUndefined (extra))
1071 llerror
1072 (FLG_BADFLAG,
1073 message
1074 ("Flag %s (in semantic comment) must be followed by an argument",
1075 flagcode_unparse (fflag)));
1077 cstring_free (extra);
1079 else
1081 if (flagcode_hasNumber (fflag))
1083 flags_setValueFlag (fflag, extra);
1085 else if (flagcode_hasChar (fflag))
1087 flags_setValueFlag (fflag, extra);
1089 else if (flagcode_hasString (fflag))
1091 flags_setStringFlag (fflag, extra);
1093 else
1095 cstring_free (extra);
1096 BADEXIT;
1103 else
1108 *s = c;
1109 while ((c == ' ') || (c == '\t') || (c == '\n'))
1111 c = *(++s);
1115 if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
1117 DPRINTF (("Here adding comment: %s", os));
1118 context_addComment (cstring_fromCharsNew (os), loc);
1120 else
1125 else
1127 char *t = s;
1128 int macrocode;
1129 char tchar = '\0';
1130 annotationInfo ainfo;
1132 while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
1134 s++;
1137 if (*s != '\0')
1139 tchar = *s;
1140 *s = '\0';
1141 s++;
1144 t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
1145 macrocode = tokenMacroCode (cstring_fromChars (t));
1147 if (macrocode != BADTOK)
1149 s_tokLength = hasnl ? 0 : size_toInt (mstring_length (t));
1151 sfree (t);
1152 sfree (os);
1153 fileloc_free (loc);
1155 if (macrocode == SKIPTOK)
1157 return BADTOK;
1160 return macrocode;
1163 ainfo = context_lookupAnnotation (cstring_fromChars (os));
1165 if (annotationInfo_isDefined (ainfo)) {
1166 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
1167 c_lval.annotation = ainfo;
1168 s_tokLength = 0;
1169 sfree (os);
1170 sfree (t);
1171 fileloc_free (loc);
1172 return CANNOTATION;
1175 if (context_inHeader ())
1177 if (tchar != '\0')
1179 *(s-1) = tchar;
1182 if ((context_inMacro () || context_inGlobalContext ())
1183 && macrocode != SKIPTOK
1184 && !isArtificial (cstring_fromChars (os)))
1186 if (context_processingMacros ())
1188 /* evans 2002-02-24: don't add comments when procssing macros */
1190 else
1192 context_addComment (cstring_fromCharsNew (os), loc);
1195 else
1200 if (tchar != '\0')
1202 *(s-1) = '\0';
1206 if (mstring_equal (t, "ignore"))
1208 if (!context_getFlag (FLG_NOCOMMENTS))
1210 context_enterSuppressRegion (loc);
1213 else if ((*t == 'i' || *t == 't')
1214 && (*(t + 1) == '\0'))
1216 if (!context_getFlag (FLG_NOCOMMENTS)
1217 && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
1219 context_enterSuppressLine (-1, loc); /* infinite suppression */
1222 else if (((*t == 'i') || (*t == 't'))
1223 && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
1225 bool tmpcomment = (*t == 't');
1226 int val = -1;
1227 char *tt = t; /* don't mangle t, since it is free'd */
1228 char lc = *(++tt);
1230 if (lc >= '0' && lc <= '9')
1232 val = (int)(lc - '0');
1234 lc = *(++tt);
1235 while (lc >= '0' && lc <= '9')
1237 val *= 10;
1238 val += (int) (lc - '0');
1239 lc = *(++tt);
1243 if (!context_getFlag (FLG_NOCOMMENTS)
1244 && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
1246 DPRINTF (("Here: enter suppress: %s", fileloc_unparse (loc)));
1247 context_enterSuppressLine (val, loc);
1250 else if (mstring_equal (t, "end"))
1252 if (!context_getFlag (FLG_NOCOMMENTS))
1254 context_exitSuppressRegion (loc);
1257 else if (mstring_equal (t, "notfunction"))
1259 ; /* handled by pcpp */
1261 else if (mstring_equal (t, "access"))
1263 cstring tname;
1265 while (TRUE)
1267 while (((c = *s) != '\0') && (c == ' ' || c == '\t' || c == '\n'))
1269 s++;
1272 if (c == '\0')
1274 break;
1277 tname = cstring_fromChars (s);
1279 while ((c = *s) != '\0' && c != ' '
1280 && c != '\t' && c != '\n' && c != ',')
1282 s++;
1285 *s = '\0';
1287 DPRINTF (("Access %s", tname));
1289 if (!context_getFlag (FLG_NOCOMMENTS)
1290 && !context_getFlag (FLG_NOACCESS))
1292 if (usymtab_existsType (tname))
1294 typeId uid = usymtab_getTypeId (tname);
1295 uentry ue = usymtab_getTypeEntry (uid);
1297 if (uentry_isAbstractDatatype (ue))
1299 context_addFileAccessType (uid);
1300 DPRINTF (("Adding access to: %s / %d", tname, uid));
1302 else
1304 voptgenerror
1305 (FLG_COMMENTERROR,
1306 message
1307 ("Non-abstract type %s used in access comment",
1308 tname),
1309 loc);
1312 else
1314 if (!(context_inSuppressRegion ()
1315 || context_inSuppressZone (loc)))
1317 voptgenerror
1318 (FLG_COMMENTERROR,
1319 message
1320 ("Unrecognized type %s used in access comment",
1321 tname),
1322 loc);
1327 if (c != '\0')
1329 s++;
1332 if (c != ',' && c != ' ')
1334 break;
1338 else if (mstring_equal (t, "noaccess"))
1340 cstring tname;
1341 char lc;
1343 while (TRUE)
1345 while (((lc = *s) != '\0') && (lc == ' ' || lc == '\t' || lc == '\n'))
1347 s++;
1350 if (lc == '\0')
1352 break;
1355 tname = cstring_fromChars (s);
1357 while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
1358 && lc != '\n' && lc != ',')
1360 s++;
1363 *s = '\0';
1365 if (!context_getFlag (FLG_NOCOMMENTS)
1366 && !context_getFlag (FLG_NOACCESS))
1368 if (usymtab_existsType (tname))
1370 typeId tuid = usymtab_getTypeId (tname);
1372 if (context_couldHaveAccess (tuid))
1374 DPRINTF (("Removing access: %s", tname));
1375 context_removeFileAccessType (tuid);
1377 else
1379 if (!(context_inSuppressRegion ()
1380 || context_inSuppressZone (loc)))
1382 uentry ue = usymtab_getTypeEntry (tuid);
1384 if (uentry_isAbstractDatatype (ue))
1386 voptgenerror
1387 (FLG_COMMENTERROR,
1388 message
1389 ("Non-accessible abstract type %s used in noaccess comment",
1390 tname),
1391 loc);
1393 else
1395 voptgenerror
1396 (FLG_COMMENTERROR,
1397 message
1398 ("Non-abstract type %s used in noaccess comment",
1399 tname),
1400 loc);
1405 else
1407 if (!(context_inSuppressRegion ()
1408 || context_inSuppressZone (loc)))
1410 voptgenerror
1411 (FLG_COMMENTERROR,
1412 message
1413 ("Unrecognized type %s used in noaccess comment",
1414 tname),
1415 loc);
1420 if (lc != '\0')
1422 s++;
1425 if (lc != ',' && lc != ' ')
1427 break;
1431 else
1433 voptgenerror (FLG_UNRECOGCOMMENTS,
1434 message ("Semantic comment unrecognized: %s",
1435 cstring_fromChars (os)),
1436 loc);
1437 /*@-branchstate@*/
1438 } /* spurious (?) warning about t */
1439 /*@=branchstate@*/
1441 sfree (t);
1444 sfree (os);
1445 fileloc_free (loc);
1446 return BADTOK;
1449 /*@only@*/ cstring cscannerHelp_makeIdentifier (char *s)
1451 char *c = mstring_create (strlen (s));
1452 cstring id = cstring_fromChars (c);
1454 while (isalnum (*s) || (*s == '_') || (*s == '$'))
1456 *c++ = *s++;
1459 *c = '\0';
1460 return (id);
1463 # ifdef DEADCODE
1464 /*@observer@*/ /*@dependent@*/ uentry cscannerHelp_coerceId (cstring cn)
1466 if (!(usymtab_exists (cn)))
1468 fileloc loc = fileloc_createExternal ();
1471 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
1474 uentry ce = uentry_makeUnrecognized (cn, loc);
1476 if (!context_inIterEnd ())
1478 voptgenerror
1479 (FLG_SYSTEMUNRECOG,
1480 message ("Unrecognized (possibly system) identifier: %q",
1481 uentry_getName (ce)),
1482 g_currentloc);
1485 return ce;
1488 return (usymtab_lookup (cn));
1492 ** like, cscannerHelp_coerceId, but doesn't supercede for iters
1495 /*@observer@*/ uentry cscannerHelp_coerceIterId (cstring cn)
1497 if (!(usymtab_exists (cn)))
1499 return uentry_undefined;
1502 return (usymtab_lookup (cn));
1504 # endif /* DEADCODE */
1507 ** Need to keep this in case there is a declaration that isn't processed until
1508 ** the scope exits. Would be good to rearrange the symbol table so this doesn't
1509 ** happen, and save all the cstring copying.
1512 /*@observer@*/ cstring cscannerHelp_observeLastIdentifier (void)
1514 cstring res = s_lastidprocessed;
1515 return res;
1518 static void cscanner_setLastIdentifier (/*@keep@*/ cstring id) /*@modifies s_lastidprocessed@*/
1520 if (cstring_isDefined (s_lastidprocessed))
1522 cstring_free (s_lastidprocessed);
1525 s_lastidprocessed = id;
1528 static int
1529 cscannerHelp_processIdentifier (/*@only@*/ cstring id)
1530 /*@modifies internalState@*/
1532 uentry le;
1534 if (context_getFlag (FLG_GRAMMAR))
1536 lldiagmsg (message ("Process identifier: %s", id));
1539 context_clearJustPopped ();
1540 cscanner_setLastIdentifier (id);
1542 DPRINTF (("Context: %s", context_unparse ()));
1544 if (context_inFunctionHeader ())
1546 int tok;
1547 annotationInfo ainfo;
1549 DPRINTF (("in function decl: %s", id));
1551 tok = commentMarkerToken (id);
1552 if (tok != BADTOK)
1554 s_inSpecPart = TRUE;
1555 s_whichSpecPart = tok;
1556 return tok;
1559 tok = tokenMacroCode (id);
1560 if (tok != BADTOK && !cscannerHelp_isSpecTokenRegularId(tok))
1562 return tok;
1565 if (s_expectingMetaStateName)
1567 metaStateInfo msinfo = context_lookupMetaStateInfo (id);
1568 if (metaStateInfo_isDefined (msinfo))
1570 c_lval.msinfo = msinfo;
1571 return METASTATE_NAME;
1573 else
1575 DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id)));
1579 ainfo = context_lookupAnnotation (id);
1580 if (annotationInfo_isDefined (ainfo))
1582 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
1583 c_lval.annotation = ainfo;
1584 return CANNOTATION;
1586 else
1588 DPRINTF (("Not annotation: %s", id));
1592 DPRINTF (("Here!"));
1594 if (context_getFlag (FLG_GNUEXTENSIONS))
1596 int tok = BADTOK;
1598 if (cstring_equalLit (id, "__stdcall")
1599 || cstring_equalLit (id, "__cdecl")
1600 || cstring_equalLit (id, "__extension__"))
1602 return BADTOK;
1604 else if (cstring_equalLit (id, "__volatile__"))
1606 tok = QVOLATILE;
1608 else if (cstring_equalLit (id, "__const__"))
1610 tok = QCONST;
1612 else if (cstring_equalLit (id, "__alignof__"))
1614 tok = CALIGNOF; /* alignof is parsed like sizeof */
1616 else if (cstring_equalLit (id, "__typeof__")
1617 || cstring_equalLit (id, "typeof"))
1619 tok = CTYPEOF;
1621 else if (cstring_equalLit (id, "__FUNCTION__")
1622 || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
1624 return cscannerHelp_returnFunctionName (id);
1626 else if (cstring_equalLit (id, "__attribute__")
1627 || cstring_equalLit (id, "__asm__")
1628 || cstring_equalLit (id, "_asm")
1629 || cstring_equalLit (id, "__asm")
1630 || cstring_equalLit (id, "__declspec"))
1632 int depth = 0;
1633 bool useparens = FALSE;
1634 bool usebraces = FALSE;
1635 bool inquote = FALSE;
1636 bool inescape = FALSE;
1637 int ic;
1639 while ((ic = cscanner_input ()) != EOF)
1641 char cc = (char) ic;
1643 if (inescape)
1645 inescape = FALSE;
1647 else if (cc == '\\')
1649 inescape = TRUE;
1651 else if (cc == '\"')
1653 inquote = !inquote;
1655 else if (!inquote)
1657 if (cc == '(')
1659 if (!useparens)
1661 if (!usebraces)
1663 useparens = TRUE;
1667 if (useparens)
1669 depth++;
1672 else if (cc == '{')
1674 if (!usebraces)
1676 if (!useparens)
1678 usebraces = TRUE;
1682 if (usebraces)
1684 depth++;
1687 else if (cc == ')' && useparens)
1689 depth--;
1690 if (depth == 0) break;
1692 else if (cc == '}' && usebraces)
1694 depth--;
1695 if (depth == 0) break;
1697 else if (cc == '}'
1698 && !usebraces && !useparens
1699 && cstring_equalLit (id, "__asm"))
1702 ** We need this because some MS VC++ include files
1703 ** have __asm mov ... }
1704 ** Its a kludge, but otherwise would need to parse
1705 ** the asm code!
1707 return TRBRACE;
1709 else
1714 else
1719 if (cc == '\n')
1721 context_incLineno ();
1723 if (cstring_equalLit (id, "__asm")
1724 && !useparens && !usebraces)
1726 break;
1731 llassert ((useparens && ic == (int) ')')
1732 || (usebraces && ic == (int) '}')
1733 || (!useparens && !usebraces));
1735 return BADTOK;
1737 else if (cstring_equalLit (id, "__inline__")
1738 || cstring_equalLit (id, "__inline")
1739 || cstring_equalLit (id, "_inline"))
1741 tok = QINLINE;
1743 else
1748 if (tok != BADTOK)
1750 return (cscannerHelp_returnToken (tok));
1754 le = usymtab_lookupSafe (id);
1756 /*@-dependenttrans@*/
1758 if (uentry_isIter (le))
1760 c_lval.entry = le;
1761 return (ITER_NAME);
1763 else if (uentry_isEndIter (le))
1765 c_lval.entry = le;
1766 return (ITER_ENDNAME);
1768 else if (uentry_isUndefined (le))
1770 c_lval.cname = cstring_copy (id);
1771 return (NEW_IDENTIFIER);
1773 else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
1775 if (uentry_isDatatype (le))
1777 c_lval.cname = cstring_copy (id);
1778 return (NEW_IDENTIFIER);
1780 else
1782 c_lval.entry = le;
1783 return (IDENTIFIER);
1786 else if (uentry_isDatatype (le))
1788 if (!s_expectingTypeName)
1790 c_lval.cname = cstring_copy (id);
1792 return (NEW_IDENTIFIER);
1794 else
1796 c_lval.ctyp = uentry_getAbstractType (le);
1798 uentry_setUsed (le, g_currentloc);
1799 return (TYPE_NAME);
1802 else
1804 c_lval.entry = le;
1805 return (IDENTIFIER);
1808 /*@=dependenttrans@*/
1811 bool cscannerHelp_processHashIdentifier (/*@only@*/ cstring id)
1813 if (context_inMacro () || context_inIterDef () ||
1814 context_inIterEnd ())
1816 uentry le;
1818 context_clearJustPopped ();
1820 le = usymtab_lookupSafe (id);
1821 cscanner_setLastIdentifier (id);
1823 if (uentry_isParam (le) || uentry_isRefParam (le))
1825 return TRUE;
1827 else
1829 return FALSE;
1832 else
1835 ** Will be handled by handleLlSpecial
1838 cstring_free (id);
1839 return FALSE;
1844 * states & input classes needed for constant string processing automata;
1846 * FIXME:
1847 * should be defined inside process_stringLiteral(), but Splint has problems
1848 * with dumping when enumeration data types are defined inside procedures.
1851 enum str_state {
1852 str_init = 0,
1853 str_inside,
1854 str_escape,
1855 str_white,
1856 str_ok,
1857 str_errnul, /* special treatement for null character error */
1858 str_errfmt
1861 enum ch_input {
1862 ch_null = 0,
1863 ch_quote,
1864 ch_escape,
1865 ch_white,
1866 ch_other
1869 static /*@only@*/ /*@notnull@*/ cstring
1870 process_stringLiteral (const /*@notnull@*/ char* in, size_t inlen)
1873 * in expected to be of the form "..."[(( \t\n)*"...")*]
1874 * have to:
1875 * - strip leading & trailing '\"' of each individual constant string;
1876 * - handle possible null characters inside constant string;
1877 * - if there are more then one constant strings, merge them [strip white
1878 * space between them].
1881 size_t outlen, i;
1882 int col;
1883 char* out;
1885 enum str_state state;
1886 /*@+enumint@*/
1887 static const enum str_state automata[str_ok+1][ch_other+1] = {
1888 /* null quote escape white other */
1889 /* init */ { str_errfmt, str_inside, str_errfmt, str_errfmt, str_errfmt},
1890 /* inside */ { str_errnul, str_ok, str_escape, str_inside, str_inside},
1891 /* escape */ { str_errnul, str_inside, str_inside, str_inside, str_inside},
1892 /* white */ { str_errfmt, str_inside, str_errfmt, str_white, str_errfmt},
1893 /* ok */ { str_errfmt, str_inside, str_errfmt, str_white, str_errfmt}
1895 /*@=enumint@*/
1897 llassertfatal (in != NULL);
1899 out = mstring_create (inlen);
1900 outlen = i = 0;
1901 state = str_init;
1902 col = 0;
1903 while (i < inlen
1904 /* no reason to continue once in error state */
1905 && !(state == str_errnul || state == str_errfmt))
1907 enum str_state newstate;
1908 enum ch_input chi;
1910 ++col;
1911 switch (in[i]) {
1912 case '\0': chi = ch_null; /*@switchbreak@*/ break;
1913 case '\"': chi = ch_quote; /*@switchbreak@*/ break;
1914 case '\\': chi = ch_escape; /*@switchbreak@*/ break;
1915 case '\n': col = 0; context_incLineno ();
1916 /*@fallthrough@*/
1917 case ' ' :
1918 case '\t': chi = ch_white; /*@switchbreak@*/ break;
1919 default : chi = ch_other; /*@switchbreak@*/ break;
1921 /*@+enumindex@*/
1922 newstate = automata [state][chi];
1923 /*@=enumindex@*/
1924 if ((newstate == str_inside || newstate == str_escape) &&
1925 (state == str_inside || state == str_escape))
1927 out[outlen] = in[i];
1928 ++outlen;
1931 state = newstate;
1932 ++i;
1934 out[outlen] = '\0';
1935 addColumn (col);
1937 if (!(state == str_ok || state == str_errnul))
1939 llbug (message ("String literal has unexpected format"));
1941 else
1943 if (state == str_errnul)
1945 /* FIXME: should add a flag contolling this, and transform message
1946 * into warning ... */
1947 llgenmsg (message ("Null character(s) present in string literal"),
1948 g_currentloc);
1951 if (context_getFlag (FLG_STRINGLITERALLEN) &&
1952 outlen > size_fromInt (context_getValue (FLG_STRINGLITERALLEN)))
1954 voptgenerror (FLG_STRINGLITERALLEN,
1955 message
1956 ("String literal length (%d) exceeds maximum "
1957 "length (%d): \"%s\"",
1958 size_toInt (outlen),
1959 context_getValue (FLG_STRINGLITERALLEN),
1960 cstring_fromChars (out)),
1961 g_currentloc);
1965 return cstring_fromChars (out);
1968 /*@only@*/ exprNode cscannerHelp_processString (void)
1970 fileloc loc = fileloc_copy (g_currentloc);
1971 return exprNode_stringLiteral (process_stringLiteral (c_text, c_leng), loc);
1975 ** process a wide character string L"...."
1978 /*@only@*/ exprNode cscannerHelp_processWideString (void)
1980 fileloc loc = fileloc_copy (g_currentloc);
1981 llassert (*c_text == 'L');
1982 return exprNode_wideStringLiteral (process_stringLiteral (c_text+1, c_leng-1), loc);
1985 char cscannerHelp_processChar (void)
1987 char fchar;
1988 char next;
1990 llassert (*c_text != '\0');
1991 fchar = *(c_text + 1);
1992 if (fchar != '\\') return fchar;
1994 next = *(c_text + 2);
1996 switch (next)
1998 case 'n': return '\n';
1999 case 't': return '\t';
2000 case '\"': return '\"';
2001 case '\'': return '\'';
2002 case '\\': return '\\';
2003 default: return '\0';
2007 double cscannerHelp_processFloat (void)
2009 double ret = atof (c_text);
2011 return (ret);
2014 long cscannerHelp_processHex (void)
2016 int index = 2;
2017 long val = 0;
2019 llassert (c_text[0] == '0'
2020 && (c_text[1] == 'X' || c_text[1] == 'x'));
2022 while (c_text[index] != '\0') {
2023 int tval;
2024 char c = c_text[index];
2026 if (c >= '0' && c <= '9') {
2027 tval = (int) c - (int) '0';
2028 } else if (c >= 'A' && c <= 'F') {
2029 tval = (int) c - (int) 'A' + 10;
2030 } else if (c >= 'a' && c <= 'f') {
2031 tval = (int) c - (int) 'a' + 10;
2032 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2033 index++;
2034 while (c_text[index] != '\0') {
2035 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2037 } else {
2038 voptgenerror
2039 (FLG_SYNTAX,
2040 message ("Invalid character (%c) following specifier in hex constant: %s",
2041 c, cstring_fromChars (c_text)),
2042 g_currentloc);
2044 index++;
2047 break;
2048 } else {
2049 voptgenerror
2050 (FLG_SYNTAX,
2051 message ("Invalid character (%c) in hex constant: %s",
2052 c, cstring_fromChars (c_text)),
2053 g_currentloc);
2054 break;
2057 val = (val << 4) + tval;
2058 index++;
2061 DPRINTF (("Hex constant: %s = %ld", c_text, val));
2062 return val;
2065 long cscannerHelp_processOctal (void)
2067 int index = 1;
2068 long val = 0;
2070 llassert (c_text[0] == '0' && c_text[1] != 'X' && c_text[1] != 'x');
2072 while (c_text[index] != '\0') {
2073 int tval;
2074 char c = c_text[index];
2076 if (c >= '0' && c <= '7') {
2077 tval = (int) c - (int) '0';
2078 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2079 index++;
2080 while (c_text[index] != '\0') {
2081 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2083 } else {
2084 voptgenerror
2085 (FLG_SYNTAX,
2086 message ("Invalid character (%c) following specifier in octal constant: %s",
2087 c, cstring_fromChars (c_text)),
2088 g_currentloc);
2090 index++;
2093 break;
2094 } else {
2095 voptgenerror
2096 (FLG_SYNTAX,
2097 message ("Invalid character (%c) in octal constant: %s",
2098 c, cstring_fromChars (c_text)),
2099 g_currentloc);
2100 break;
2103 val = (val * 8) + tval;
2104 index++;
2107 DPRINTF (("Octal constant: %s = %ld", c_text, val));
2108 return val;
2111 long cscannerHelp_processDec (void)
2113 return (atol (c_text));
2116 /* Allow specificiation keywords to be used as identifiers in certain contexts. */
2117 static bool cscannerHelp_isSpecTokenRegularId (int tok)
2119 if (!s_inSpecPart)
2121 return TRUE;
2124 if ( s_whichSpecPart == QMODIFIES
2125 || s_whichSpecPart == QDEFINES
2126 || s_whichSpecPart == QUSES
2127 || s_whichSpecPart == QALLOCATES
2128 || s_whichSpecPart == QSETS
2129 || s_whichSpecPart == QRELEASES
2130 || s_whichSpecPart == QWARN)
2132 return TRUE;
2135 if (s_whichSpecPart == QGLOBALS)
2137 if (!(tok == QKILLED || tok == QUNDEF || tok == QOUT || tok == QIN || tok == QPARTIAL))
2139 return TRUE;
2143 if (s_whichSpecPart == QPRECLAUSE || s_whichSpecPart == QPOSTCLAUSE)
2145 if (!(tok == QMAXSET || tok == QMAXREAD
2146 /* uncomment the additional tests when minSet and minRead are supported */
2147 /* || tok == QMINREAD || tok == QMINSET */
2149 || tok == QOBSERVER || tok == QEXPOSED
2150 || tok == QONLY || tok == QSHARED
2151 || tok == QOWNED || tok == QDEPENDENT
2152 || tok == QUNIQUE
2154 || tok == QISNULL || tok == QNULL
2155 || tok == QNOTNULL || tok == QRELNULL
2156 || tok == QNULLTERMINATED
2158 /* || tok == QYIELD */
2159 /* || tok == QTEMP */
2160 /* || tok == QKEEP */
2161 /* || tok == QKEPT */
2164 return TRUE;
2168 /* Specification parts not handled (they require a more complex solution
2169 * then this simple hack): QCONSTANT, QFUNCTION, QITER & QALT. */
2171 return FALSE;
2174 int cscannerHelp_processSpec (int tok)
2176 size_t length = strlen (c_text);
2178 if (!cscannerHelp_isSpecTokenRegularId (tok))
2180 cscannerHelp_setTokLengthT (length);
2181 return cscannerHelp_returnToken (tok);
2184 context_saveLocation ();
2185 cscannerHelp_setTokLengthT (length);
2186 return (cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (c_text)));
2189 void cscannerHelp_expectingMetaStateName (void)
2191 llassert (!s_expectingMetaStateName);
2192 llassert (context_inFunctionHeader ());
2193 s_expectingMetaStateName = TRUE;
2196 void cscannerHelp_clearExpectingMetaStateName (void)
2198 llassert (s_expectingMetaStateName);
2199 s_expectingMetaStateName = FALSE;
2202 bool cscannerHelp_processMacro (void)
2204 uentry e2;
2205 ctype ct;
2206 int noparams = 0;
2207 cstring fname = cstring_undefined;
2208 bool res = TRUE;
2209 bool isspecfcn = FALSE;
2210 bool isiter = FALSE;
2211 bool skipparam = FALSE;
2212 bool unknownm = FALSE;
2213 bool hasParams = FALSE;
2214 bool emptyMacro = FALSE;
2215 char c = skip_whitespace ();
2216 fileloc loc = fileloc_noColumn (g_currentloc);
2218 /* are both of these necessary? what do they mean? */
2219 uentryList specparams = uentryList_undefined;
2220 uentryList pn = uentryList_undefined;
2222 context_resetMacroMissingParams ();
2224 if (c == '\0' || c == '\n')
2226 llcontbug (cstring_makeLiteral ("Bad macro"));
2227 fileloc_free (loc);
2228 return FALSE;
2231 fname = cstring_appendChar (fname, c);
2233 while ((c = macro_nextChar ()) != '(' && c != '\0'
2234 && c != ' ' && c != '\t' && c != '\n')
2236 fname = cstring_appendChar (fname, c);
2239 if (c == ' ' || c == '\t' || c == '\n')
2241 char oldc = c;
2243 if (c != '\n')
2245 while (c == ' ' || c == '\t')
2247 c = macro_nextChar ();
2249 cscanner_unput ((int) c);
2252 if (c == '\n')
2254 emptyMacro = TRUE;
2255 cscanner_unput ((int) c);
2258 c = oldc;
2261 hasParams = (c == '(');
2263 if (usymtab_exists (fname))
2265 e2 = usymtab_lookupExpose (fname);
2266 ct = uentry_getType (e2);
2268 if (uentry_isCodeDefined (e2)
2269 && fileloc_isUser (uentry_whereDefined (e2)))
2271 if (optgenerror
2272 (FLG_MACROREDEF,
2273 message ("Macro %s already defined", fname),
2274 loc))
2276 uentry_showWhereDefined (e2);
2277 uentry_clearDefined (e2);
2280 if (uentry_isFunction (e2))
2282 uentry_setType (e2, ctype_unknown);
2283 ct = ctype_unknown;
2284 unknownm = TRUE;
2285 context_enterUnknownMacro (e2);
2287 else
2289 context_enterConstantMacro (e2);
2292 else if (uentry_isForward (e2) && uentry_isFunction (e2))
2294 unknownm = TRUE;
2296 voptgenerror
2297 (FLG_MACROFCNDECL,
2298 message
2299 ("Parameterized macro has no prototype or specification: %s ",
2300 fname),
2301 loc);
2303 ct = ctype_unknown;
2304 uentry_setType (e2, ctype_unknown);
2305 uentry_setFunctionDefined (e2, loc);
2306 uentry_setUsed (e2, fileloc_undefined);
2307 context_enterUnknownMacro (e2);
2309 else if (uentry_isIter (e2))
2311 isiter = TRUE;
2312 specparams = uentry_getParams (e2);
2313 noparams = uentryList_size (specparams);
2314 uentry_setDefined (e2, loc);
2315 context_enterIterDef (e2);
2317 else if (uentry_isEndIter (e2))
2319 uentry_setDefined (e2, loc);
2320 context_enterIterEnd (e2); /* don't care about it now */
2321 /* but should parse like an iter! */
2323 else if (uentry_isEitherConstant (e2))
2325 if (hasParams)
2327 voptgenerror
2328 (FLG_INCONDEFS,
2329 message ("Constant %s implemented as parameterized macro",
2330 fname),
2331 g_currentloc);
2333 uentry_showWhereSpecified (e2);
2334 uentry_setType (e2, ctype_unknown);
2335 uentry_makeConstantFunction (e2);
2336 uentry_setDefined (e2, g_currentloc);
2337 uentry_setFunctionDefined (e2, g_currentloc);
2338 context_enterUnknownMacro (e2);
2340 else
2342 if (!uentry_isSpecified (e2))
2344 fileloc oloc = uentry_whereDeclared (e2);
2346 if (fileloc_isLib (oloc))
2350 else if (fileloc_isUndefined (oloc)
2351 || fileloc_isPreproc (oloc))
2353 if (!emptyMacro)
2355 voptgenerror
2356 (FLG_MACROCONSTDECL,
2357 message
2358 ("Macro constant %q not declared",
2359 uentry_getName (e2)),
2360 loc);
2363 else if (!fileloc_withinLines (oloc, loc, 2))
2364 { /* bogus! will give errors if there is too much whitespace */
2365 voptgenerror
2366 (FLG_MACROCONSTDIST,
2367 message
2368 ("Macro constant name %s matches name in "
2369 "distant constant declaration. This constant "
2370 "is declared at %q", fname,
2371 fileloc_unparse (oloc)),
2372 loc);
2374 else
2376 /* No warning */
2380 context_enterConstantMacro (e2);
2381 cstring_free (fname);
2382 fileloc_free (loc);
2383 return res;
2386 else if (ctype_isFunction (ct))
2388 isspecfcn = TRUE;
2389 specparams = ctype_argsFunction (ct);
2390 noparams = uentryList_size (specparams);
2392 uentry_setFunctionDefined (e2, loc);
2393 context_enterMacro (e2);
2395 else if (uentry_isVar (e2))
2397 if (hasParams)
2399 voptgenerror
2400 (FLG_INCONDEFS,
2401 message ("Variable %s implemented as parameterized macro",
2402 fname),
2403 loc);
2405 uentry_showWhereSpecified (e2);
2406 uentry_setType (e2, ctype_unknown);
2407 uentry_makeVarFunction (e2);
2408 uentry_setDefined (e2, g_currentloc);
2409 uentry_setFunctionDefined (e2, g_currentloc);
2410 context_enterUnknownMacro (e2);
2412 else
2414 uentry ucons = uentry_makeConstant (fname,
2415 ctype_unknown,
2416 loc);
2417 if (uentry_isExpandedMacro (e2))
2419 ; /* okay */
2421 else
2423 if (optgenerror
2424 (FLG_INCONDEFS,
2425 message ("Variable %s implemented by a macro",
2426 fname),
2427 loc))
2429 uentry_showWhereSpecified (e2);
2433 uentry_setDefined (e2, loc);
2434 uentry_setUsed (ucons, loc);
2436 context_enterConstantMacro (ucons);
2437 uentry_markOwned (ucons);
2438 cstring_free (fname);
2439 return res;
2442 else if (uentry_isDatatype (e2))
2444 vgenhinterror
2445 (FLG_SYNTAX,
2446 message ("Type implemented as macro: %x",
2447 uentry_getName (e2)),
2448 message ("A type is implemented using a macro definition. A "
2449 "typedef should be used instead."),
2450 g_currentloc);
2452 cscannerHelp_swallowMacro ();
2453 /* Must exit scope (not sure why a new scope was entered?) */
2454 usymtab_quietExitScope (g_currentloc);
2455 uentry_setDefined (e2, g_currentloc);
2456 res = FALSE;
2458 else
2460 llcontbug
2461 (message ("Unexpanded macro not function or constant: %q",
2462 uentry_unparse (e2)));
2463 uentry_setType (e2, ctype_unknown);
2465 if (hasParams)
2467 uentry_makeVarFunction (e2);
2468 uentry_setDefined (e2, g_currentloc);
2469 uentry_setFunctionDefined (e2, g_currentloc);
2470 context_enterUnknownMacro (e2);
2474 else
2476 uentry ce;
2478 /* evans 2001-09-09 - if it has params, assume a function */
2479 if (hasParams)
2481 voptgenerror
2482 (FLG_MACROMATCHNAME,
2483 message ("Unexpanded macro %s does not match name of a declared "
2484 "function. The name used in the control "
2485 "comment on the previous line should match.",
2486 fname),
2487 loc);
2489 ce = uentry_makeFunction (fname, ctype_unknown,
2490 typeId_invalid,
2491 globSet_undefined,
2492 sRefSet_undefined,
2493 warnClause_undefined,
2494 fileloc_undefined);
2495 uentry_setUsed (ce, loc); /* perhaps bogus? */
2496 e2 = usymtab_supEntryReturn (ce);
2497 context_enterUnknownMacro (e2);
2499 else
2501 voptgenerror
2502 (FLG_MACROMATCHNAME,
2503 message ("Unexpanded macro %s does not match name of a constant "
2504 "or iter declaration. The name used in the control "
2505 "comment on the previous line should match. "
2506 "(Assuming macro defines a constant.)",
2507 fname),
2508 loc);
2510 ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
2511 uentry_setUsed (ce, loc); /* perhaps bogus? */
2512 e2 = usymtab_supEntryReturn (ce);
2514 context_enterConstantMacro (e2);
2515 cstring_free (fname);
2516 fileloc_free (loc);
2517 return res;
2521 /* in macros, ( must follow immediatetly after name */
2523 if (hasParams)
2525 int paramno = 0;
2527 c = skip_whitespace ();
2529 while (c != ')' && c != '\0')
2531 uentry param;
2532 bool suppress = context_inSuppressRegion ();
2533 cstring paramname = cstring_undefined;
2536 ** save the parameter location
2539 decColumn ();
2540 context_saveLocation ();
2541 incColumn ();
2543 while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
2545 paramname = cstring_appendChar (paramname, c);
2546 c = macro_nextChar ();
2549 if (c == ' ' || c == '\t') c = skip_whitespace ();
2551 if (c == ',')
2553 c = macro_nextChar ();
2554 if (c == ' ' || c == '\t') c = skip_whitespace ();
2557 if (c == '\0')
2559 llfatalerror (cstring_makeLiteral
2560 ("Bad macro syntax: uentryList"));
2563 if ((isspecfcn || isiter) && (paramno < noparams)
2564 && !uentry_isElipsisMarker (uentryList_getN
2565 (specparams, paramno)))
2567 fileloc sloc = context_getSaveLocation ();
2568 uentry decl = uentryList_getN (specparams, paramno);
2569 sRef sr;
2571 param = uentry_nameCopy (paramname, decl);
2573 uentry_setParam (param);
2574 sr = sRef_makeParam (paramno, uentry_getType (param),
2575 stateInfo_makeLoc (sloc, SA_DECLARED));
2577 if (sRef_getNullState (sr) == NS_ABSNULL)
2579 ctype pt = ctype_realType (uentry_getType (param));
2581 if (ctype_isUser (pt))
2583 uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
2585 if (uentry_isValid (te))
2587 sRef_setStateFromUentry (sr, te);
2590 else
2592 sRef_setNullState (sr, NS_UNKNOWN, sloc);
2596 uentry_setSref (param, sr);
2597 uentry_setDeclaredForceOnly (param, sloc);
2599 skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
2601 else
2603 fileloc sloc = context_getSaveLocation ();
2605 param = uentry_makeVariableSrefParam
2606 (paramname, ctype_unknown, fileloc_copy (sloc),
2607 sRef_makeParam (paramno, ctype_unknown,
2608 stateInfo_makeLoc (sloc, SA_DECLARED)));
2609 DPRINTF (("Unknown param: %s", uentry_unparseFull (param)));
2610 cstring_free (paramname);
2612 sRef_setPosNull (uentry_getSref (param), sloc);
2613 uentry_setDeclaredForce (param, sloc);
2615 skipparam = FALSE;
2616 fileloc_free (sloc);
2619 if (!skipparam)
2621 llassert (!uentry_isElipsisMarker (param));
2623 if (!suppress)
2625 sRef_makeUnsafe (uentry_getSref (param));
2628 pn = uentryList_add (pn, uentry_copy (param));
2629 usymtab_supEntry (param);
2631 else
2633 /* don't add param */
2634 uentry_free (param);
2637 if (c == ',')
2639 (void) macro_nextChar ();
2640 c = skip_whitespace ();
2643 paramno++;
2646 if (c == ')')
2648 if (isspecfcn || isiter)
2650 if (paramno != noparams && noparams >= 0)
2652 cscannerHelp_advanceLine ();
2654 voptgenerror
2655 (FLG_INCONDEFS,
2656 message ("Macro %s specified with %d args, defined with %d",
2657 fname, noparams, paramno),
2658 g_currentloc);
2660 uentry_showWhereSpecified (e2);
2661 uentry_resetParams (e2, pn);
2664 else
2666 uentry_resetParams (e2, pn);
2670 else
2673 ** the form should be:
2675 ** # define newname oldname
2676 ** where oldname refers to a function matching the specification
2677 ** of newname.
2680 if (unknownm)
2682 sRef_setGlobalScope ();
2683 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
2684 sRef_clearGlobalScope ();
2686 else
2688 context_setMacroMissingParams ();
2693 /* context_setuentryList (pn); */
2694 usymtab_enterScope ();
2696 fileloc_free (loc);
2697 cstring_free (fname);
2699 return res;
2702 void cscannerHelp_setTokLength (int len)
2704 addColumn (len);
2705 s_tokLength = len;
2706 DPRINTF (("Set tok length: %d", len));
2709 void cscannerHelp_setTokLengthT (size_t len)
2711 cscannerHelp_setTokLength (size_toInt (len));
2714 static void cscannerHelp_advanceLine (void)
2716 s_tokLength = 0;
2717 beginLine ();
2720 int cscannerHelp_returnToken (int t)
2722 if (s_tokLength > fileloc_column (g_currentloc)) {
2723 c_lval.tok = lltok_create (t, fileloc_copy (g_currentloc));
2724 } else {
2725 c_lval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, s_tokLength));
2728 s_tokLength = 0;
2729 return (t);
2732 int cscannerHelp_returnTokenLength (int t, int length)
2734 cscannerHelp_setTokLength (length);
2735 return cscannerHelp_returnToken (t);
2738 int cscannerHelp_returnString (cstring s)
2740 c_lval.expr = exprNode_stringLiteral (s, fileloc_decColumn (g_currentloc, s_tokLength));
2741 s_tokLength = 0;
2742 return (CCONSTANT);
2745 int cscannerHelp_returnInt (ctype ct, long val)
2747 ctype c = ct;
2749 if (ctype_equal (ct, ctype_int))
2751 if (val == 0)
2753 c = context_typeofZero ();
2755 else if (val == 1)
2757 c = context_typeofOne ();
2759 else
2765 c_lval.expr = exprNode_numLiteral (c, cstring_fromChars (c_text),
2766 fileloc_decColumn (g_currentloc, s_tokLength),
2767 val);
2768 s_tokLength = 0;
2769 return (CCONSTANT);
2772 int cscannerHelp_returnFloat (ctype ct, double f)
2774 c_lval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (c_text),
2775 fileloc_decColumn (g_currentloc, s_tokLength));
2776 s_tokLength = 0;
2777 return (CCONSTANT);
2780 int cscannerHelp_returnChar (char c)
2782 c_lval.expr = exprNode_charLiteral (c, cstring_fromChars (c_text),
2783 fileloc_decColumn (g_currentloc, s_tokLength));
2784 s_tokLength = 0;
2785 return (CCONSTANT);
2788 int cscannerHelp_returnType (int tok, ctype ct)
2790 c_lval.ctyp = ct;
2791 s_tokLength = 0;
2792 return tok;
2795 int cscannerHelp_returnExpr (exprNode e)
2797 c_lval.expr = e;
2798 s_tokLength = 0;
2799 return (CCONSTANT);
2802 /* Should hold the name of the current function as string; instead it just
2803 * saves the (literal) value of the token ... */
2804 int cscannerHelp_returnFunctionName (cstring id)
2806 c_lval.expr = exprNode_makeConstantString (id,
2807 fileloc_decColumn (g_currentloc, s_tokLength));
2808 s_tokLength = 0;
2809 return CCONSTANT;
2812 void cscannerHelp_setExpectingTypeName (void)
2814 s_expectingTypeName = TRUE;
2817 void cscannerHelp_clearExpectingTypeName (void)
2819 s_expectingTypeName = FALSE;
2822 # ifdef DEADCODE
2823 bool cscannerHelp_isExpectingTypeName (void)
2825 return s_expectingTypeName;
2827 # endif /* DEADCODE */
2829 int cscannerHelp_processTextIdentifier (char *text)
2831 context_saveLocation ();
2832 cscannerHelp_setTokLength (size_toInt (mstring_length (text)));
2833 return cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (text));
2836 static bool s_continueLine = FALSE;
2838 int cscannerHelp_handleNewLine (void)
2840 context_incLineno ();
2842 if (s_tokLength != 0) {
2843 s_tokLength = 0;
2844 /* No error to report
2845 voptgenerror
2846 (FLG_SYNTAX,
2847 message ("Likely parse error: token spans multiple lines."),
2848 g_currentloc);
2852 if (s_continueLine)
2854 s_continueLine = FALSE;
2856 else
2858 if (context_inMacro ())
2860 /* Don't use return cscannerHelp_returnToken */
2861 /* !!! evans 2002-03-13 */
2862 c_lval.tok = lltok_create (TENDMACRO, fileloc_copy (g_currentloc));
2863 return TENDMACRO;
2867 return BADTOK;
2870 void cscannerHelp_setContinueLine (void)
2872 s_continueLine = TRUE;
2875 void cscannerHelp_exitSpecPart (void)
2877 llassert (s_inSpecPart);
2878 s_inSpecPart = FALSE;
2879 s_whichSpecPart = BADTOK;