2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on splint: splint@cs.virginia.edu
21 ** To report a bug: splint-bug@cs.virginia.edu
22 ** For more information: http://www.splint.org
28 ** Based on a C lexer by Nate Osgood
29 ** from hacrat@catfish.lcs.mit.edu Mon Jun 14 13:06:32 1993
32 ** Modified by Herbert 08/19/97:
33 ** - added #include for IBM's OS/2 compiler.
34 ** - fixed weird bug with lookup of tmp files (OS/2 and MSDOS only).
37 ** Modified by Mike Smith
38 ** Corrected missing 'line' in scanf() calls in handleSpecial().
39 ** Without this, I get an error when Splint hits a '#line' directive
40 ** in the pre-pre-processed source files. For safety, I have made these
41 ** conditional on OS2 and MSDOS because I don't understand why noone else
42 ** has seen this problem.
44 ** Modified by Mike Smith, 4th June 1997
45 ** Finally resolved the #line problem. The scanf() calls have been fixed to
46 ** allow the following #line forms:-
48 ** #line 123 "filename"
53 ** The last two are generated by the GNU pre-processor, apparently
64 ULSuffix ({U}{L}|{L}{U})
67 # include "splintMacros.nf"
68 # if defined(OS2) && defined(__IBMC__)
69 /* needed for isatty()... */
74 ** Win32 doesn't have unistd.h
85 # include "cgrammar.h"
86 # include "cgrammar_tokens.h"
89 static bool lastWasString = FALSE;
90 static char savechar = '\0';
93 # define yyinput() (incColumn (), getc (yyin))
95 static /*@owned@*/ cstring s_lastidprocessed = cstring_undefined;
96 static int lminput (void);
97 static int tokLength = 0;
98 static bool s_inSpecPart = FALSE;
99 static int s_whichSpecPart;
100 static bool continueLine = FALSE;
102 static int ninput (void);
103 static char processChar (void);
104 static double processFloat (void);
105 static /*@only@*/ exprNode processString (void) ;
106 static /*@only@*/ exprNode processWideString (void) ;
107 static long processDec (void);
108 static long processHex (void);
109 static long processOctal (void);
110 static int processIdentifier (/*@only@*/ cstring)
111 /*@globals s_lastidprocessed@*/ ;
112 static bool processHashIdentifier (/*@only@*/ cstring)
113 /*@globals s_lastidprocessed@*/ ;
115 static int processSpec (int);
116 static bool handleSpecial (char *);
117 static int handleLlSpecial (void);
118 static void handleMacro (void);
119 static bool processMacro (void);
120 static /*@only@*/ cstring makeIdentifier (char *);
122 /* yes, this is exported! */
123 bool g_expectingTypeName = TRUE; /* beginning of file can be type name! */
125 static bool expectingMetaStateName = FALSE;
127 static int returnInt (ctype, long);
128 static int returnFloat (ctype, double);
129 static int returnChar (char);
130 static void setTokLength (int) /*@modifies g_currentloc@*/ ;
131 static void setTokLengthT (size_t) /*@modifies g_currentloc@*/ ;
133 static void advanceLine (void)
140 # define RETURN_INT(c,i) \
141 do { lastWasString = FALSE; \
142 return (returnInt (c, i)); } while (FALSE)
144 # define RETURN_FLOAT(c,f) \
145 do { lastWasString = FALSE; \
146 return (returnFloat (c, f)); \
149 # define RETURN_CHAR(c) \
150 do { lastWasString = FALSE; \
151 return (returnChar (c)); \
154 # define RETURN_TOK(t) \
155 do { yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, tokLength)); \
157 lastWasString = FALSE; \
158 return (t); } while (FALSE)
160 # define RETURN_TYPE(t, ct) \
161 do { yylval.ctyp = ct; tokLength = 0; return (t); } while (FALSE)
163 /* don't fileloc_decColumn (g_currentloc, tokLength));
164 the string could have \n's in it!
167 # define RETURN_STRING(c) \
168 do { yylval.expr = exprNode_stringLiteral (c, fileloc_decColumn (g_currentloc, tokLength)); \
170 lastWasString = TRUE; \
171 return (CCONSTANT); } while (FALSE)
173 # define RETURN_EXPR(e) \
174 do { yylval.expr = e; \
176 lastWasString = TRUE; \
177 return (CCONSTANT); } while (FALSE)
181 static void setTokLength (int len)
185 DPRINTF (("Set tok length: %d", len));
188 static void setTokLengthT (size_t len)
190 setTokLength (size_toInt (len));
193 # include "flex.head"
195 /*@-unrecog@*/ /*@i5343@*/
201 "/*" { llfatalerror (cstring_makeLiteral ("Comment in pre-processor output")); }
203 "#"{Letter}({Letter}|{Digit})* {
204 context_saveLocation ();
205 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
207 if (processHashIdentifier (makeIdentifier (yytext + 1)))
211 /* was nothing! */ /*@i32@*/
212 RETURN_STRING (cstring_makeLiteral ("\"\""));
216 RETURN_STRING (cstring_makeLiteral ("\"\""));
221 if (handleSpecial (yytext))
228 "#" { if (handleSpecial (yytext))
230 setTokLength (1); RETURN_TOK (0);
233 "..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); }
234 "break" { setTokLength (5); RETURN_TOK (BREAK); }
235 "case" { setTokLength (4); RETURN_TOK (CASE); }
236 "continue" { setTokLength (8); RETURN_TOK (CONTINUE); }
237 "default" { setTokLength (7); RETURN_TOK (DEFAULT); }
238 "do" { setTokLength (2); RETURN_TOK (DO); }
239 "else" { setTokLength (4); RETURN_TOK (CELSE); }
240 "for" { setTokLength (3); RETURN_TOK (CFOR); }
241 "goto" { setTokLength (4); RETURN_TOK (GOTO); }
242 "if" { setTokLength (2); RETURN_TOK (CIF); }
243 "return" { setTokLength (6); RETURN_TOK (RETURN); }
244 "sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); }
245 "offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); }
246 "switch" { setTokLength (6); RETURN_TOK (SWITCH); }
247 "while" { setTokLength (5); RETURN_TOK (WHILE); }
248 "va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); }
249 "va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); }
251 /* gcc extension...this might not be appropriate */
252 setTokLength (6); RETURN_TOK (QINLINE); }
254 "struct" { setTokLength (6); RETURN_TOK (CSTRUCT); }
255 "typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); }
257 "union" { setTokLength (5); RETURN_TOK (CUNION); }
258 "enum" { setTokLength (4); RETURN_TOK (CENUM); }
260 "void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); }
261 "int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); }
262 "double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); }
263 "char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); }
264 "float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); }
266 "long" { setTokLength (4); RETURN_TOK (QLONG); }
267 "short" { setTokLength (5); RETURN_TOK (QSHORT); }
268 "unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); }
269 "signed" { setTokLength (6); RETURN_TOK (QSIGNED); }
271 "volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); }
272 "const" { setTokLength (5); RETURN_TOK (QCONST); }
273 "restrict" { setTokLength (8); RETURN_TOK (QRESTRICT); }
275 /* some systems expect this! [gack!] */
276 "__const" { setTokLength (7); RETURN_TOK (QCONST); }
278 "extern" { setTokLength (6); RETURN_TOK (QEXTERN); }
279 "auto" { setTokLength (4); RETURN_TOK (QAUTO); }
280 "register" { setTokLength (8); RETURN_TOK (QREGISTER); }
281 "static" { setTokLength (6); RETURN_TOK (QSTATIC); }
283 \"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
284 L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processWideString ()); }
285 "out" { return (processSpec (QOUT)); }
286 "in" { return (processSpec (QIN)); }
287 "partial" { return (processSpec (QPARTIAL)); }
288 "special" { return (processSpec (QSPECIAL)); }
289 "anytype" { return (processSpec (QANYTYPE)); }
290 "integraltype" { return (processSpec (QINTEGRALTYPE)); }
291 "unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); }
292 "signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); }
293 "keep" { return (processSpec (QKEEP)); }
294 "null" { return (processSpec (QNULL)); }
295 "notnull" { return (processSpec (QNOTNULL)); }
296 "isnull" { return (processSpec (QISNULL)); }
297 "truenull" { return (processSpec (QTRUENULL)); }
298 "falsenull" { return (processSpec (QFALSENULL)); }
299 "nullwhentrue" { return (processSpec (QTRUENULL)); }
300 "nullwhenfalse" { return (processSpec (QFALSENULL)); }
301 "relnull" { return (processSpec (QRELNULL)); }
302 "reldef" { return (processSpec (QRELDEF)); }
303 "exposed" { return (processSpec (QEXPOSED)); }
304 "newref" { return (processSpec (QNEWREF)); }
305 "tempref" { return (processSpec (QTEMPREF)); }
306 "killref" { return (processSpec (QKILLREF)); }
307 "refcounted" { return (processSpec (QREFCOUNTED)); }
308 "checked" { return (processSpec (QCHECKED)); }
309 "checkmod" { return (processSpec (QCHECKMOD)); }
310 "checkedstrict" { return (processSpec (QCHECKEDSTRICT)); }
311 "unchecked" { return (processSpec (QUNCHECKED)); }
312 "only" { return (processSpec (QONLY)); }
313 "owned" { return (processSpec (QOWNED)); }
314 "observer" { return (processSpec (QOBSERVER)); }
315 "dependent" { return (processSpec (QDEPENDENT)); }
316 "unused" { return (processSpec (QUNUSED)); }
317 "external" { return (processSpec (QEXTERNAL)); }
318 "sef" { return (processSpec (QSEF)); }
319 "shared" { return (processSpec (QSHARED)); }
320 "yield" { return (processSpec (QYIELD)); }
321 "undef" { return (processSpec (QUNDEF)); }
322 "killed" { return (processSpec (QKILLED)); }
323 "nullterminated" { return (processSpec (QNULLTERMINATED));}
324 "MaxSet" { return (processSpec (QMAXSET));}
325 "MaxRead" { return (processSpec (QMAXREAD));}
326 "maxSet" { return (processSpec (QMAXSET));}
327 "maxRead" { return (processSpec (QMAXREAD));}
329 {Letter}({Letter}|{Digit})* { int tok;
330 context_saveLocation ();
331 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
332 tok = processIdentifier (makeIdentifier (yytext));
338 0[xX]{H}+ { setTokLengthT (mstring_length (yytext));
339 RETURN_INT (ctype_int, processHex ()); /* evs 2000-05-17 was ctype_uint */
341 0[xX]{H}+{L} { setTokLengthT (mstring_length (yytext));
342 RETURN_INT (ctype_lint, processHex ()); }
343 0[xX]{H}+{L}{L} { setTokLengthT (mstring_length (yytext));
344 RETURN_INT (ctype_llint, processHex ()); }
345 0[xX]{H}+{U} { setTokLengthT (mstring_length (yytext));
346 RETURN_INT (ctype_uint, processHex ()); }
347 0[xX]{H}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
348 RETURN_INT (ctype_ulint, processHex ()); }
349 0[xX]{H}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
350 RETURN_INT (ctype_ullint, processHex ()); }
351 0[xX]{H}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
352 RETURN_INT (ctype_ullint, processHex ()); }
353 0{Digit}+ { setTokLengthT (mstring_length (yytext));
354 RETURN_INT (ctype_int, processOctal ()); }
355 0{Digit}+{U} { setTokLengthT (mstring_length (yytext));
356 RETURN_INT (ctype_uint, processOctal ()); }
357 0{Digit}+{L} { setTokLengthT (mstring_length (yytext));
358 RETURN_INT (ctype_lint, processOctal ()); }
359 0{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
360 RETURN_INT (ctype_llint, processOctal ()); }
361 0{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
362 RETURN_INT (ctype_ulint, processOctal ()); }
363 0{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
364 RETURN_INT (ctype_ullint, processOctal ()); }
365 0{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
366 RETURN_INT (ctype_ullint, processOctal ()); }
367 {Digit}+ { setTokLengthT (mstring_length (yytext));
368 RETURN_INT (ctype_int, processDec ()); }
369 {Digit}+{U} { setTokLengthT (mstring_length (yytext));
370 RETURN_INT (ctype_uint, processDec ()); }
371 {Digit}+{L} { setTokLengthT (mstring_length (yytext));
372 RETURN_INT (ctype_lint, processDec ()); }
373 {Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
374 RETURN_INT (ctype_llint, processDec ()); }
375 {Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
376 RETURN_INT (ctype_ulint, processDec ()); }
377 {Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
378 RETURN_INT (ctype_ullint, processDec ()); }
379 {Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
380 RETURN_INT (ctype_ullint, processDec ()); }
381 '(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
382 RETURN_CHAR (processChar ()); }
383 L'(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
384 RETURN_CHAR (processChar ()); }
385 {Digit}+{E}[fF] { setTokLengthT (mstring_length (yytext));
386 RETURN_FLOAT (ctype_float, processFloat ()); }
387 {Digit}+{E}[lL] { setTokLengthT (mstring_length (yytext));
388 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
389 {Digit}+{E} { setTokLengthT (mstring_length (yytext));
390 RETURN_FLOAT (ctype_double, processFloat ()); }
392 {Digit}*"."{Digit}+({E})?[fF] { setTokLengthT (mstring_length (yytext));
393 RETURN_FLOAT (ctype_float, processFloat ()); }
394 {Digit}*"."{Digit}+({E})?[lL] { setTokLengthT (mstring_length (yytext));
395 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
396 {Digit}*"."{Digit}+({E})? { setTokLengthT (mstring_length (yytext));
397 RETURN_FLOAT (ctype_double, processFloat ()); }
399 {Digit}+"."{Digit}*({E})?[fF] { setTokLengthT (mstring_length (yytext));
400 RETURN_FLOAT (ctype_float, processFloat ()); }
401 {Digit}+"."{Digit}*({E})?[lL] { setTokLengthT (mstring_length (yytext));
402 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
403 {Digit}+"."{Digit}*({E})? { setTokLengthT (mstring_length (yytext));
404 RETURN_FLOAT (ctype_double, processFloat ()); }
406 ">>=" { setTokLength (3); RETURN_TOK (RIGHT_ASSIGN); }
407 "<<=" { setTokLength (3); RETURN_TOK (LEFT_ASSIGN); }
408 "+=" { setTokLength (2); RETURN_TOK (ADD_ASSIGN); }
409 "-=" { setTokLength (2); RETURN_TOK (SUB_ASSIGN); }
410 "*=" { setTokLength (2); RETURN_TOK (MUL_ASSIGN); }
411 "/=" { setTokLength (2); RETURN_TOK (DIV_ASSIGN); }
412 "%=" { setTokLength (2); RETURN_TOK (MOD_ASSIGN); }
413 "&=" { setTokLength (2); RETURN_TOK (AND_ASSIGN); }
414 "^=" { setTokLength (2); RETURN_TOK (XOR_ASSIGN); }
415 "|=" { setTokLength (2); RETURN_TOK (OR_ASSIGN); }
416 ">>" { setTokLength (2); RETURN_TOK (RIGHT_OP); }
417 "<<" { setTokLength (2); RETURN_TOK (LEFT_OP); }
418 "++" { setTokLength (2); RETURN_TOK (INC_OP); }
419 "--" { setTokLength (2); RETURN_TOK (DEC_OP); }
420 "->" { setTokLength (2); RETURN_TOK (ARROW_OP); }
421 "&&" { setTokLength (2); RETURN_TOK (AND_OP); }
422 "||" { setTokLength (2); RETURN_TOK (OR_OP); }
423 "<=" { setTokLength (2); RETURN_TOK (LE_OP); }
424 ">=" { setTokLength (2); RETURN_TOK (GE_OP); }
425 "==" { setTokLength (2); RETURN_TOK (EQ_OP); }
426 "!=" { setTokLength (2); RETURN_TOK (NE_OP); }
427 ";" { setTokLength (1); RETURN_TOK (TSEMI); }
428 "{" { setTokLength (1); RETURN_TOK (TLBRACE); }
429 "}" { setTokLength (1); RETURN_TOK (TRBRACE); }
430 "," { setTokLength (1); RETURN_TOK (TCOMMA); }
431 ":" { setTokLength (1); RETURN_TOK (TCOLON); }
432 "=" { setTokLength (1); RETURN_TOK (TASSIGN); }
433 "(" { setTokLength (1); RETURN_TOK (TLPAREN); }
434 ")" { setTokLength (1); RETURN_TOK (TRPAREN); }
435 "[" { setTokLength (1); RETURN_TOK (TLSQBR); }
436 "]" { setTokLength (1); RETURN_TOK (TRSQBR); }
437 "." { setTokLength (1); RETURN_TOK (TDOT); }
438 "&" { setTokLength (1); RETURN_TOK (TAMPERSAND); }
439 "!" { setTokLength (1); RETURN_TOK (TEXCL); }
442 "~" { setTokLength (1); RETURN_TOK (TTILDE); }
443 "-" { setTokLength (1); RETURN_TOK (TMINUS); }
444 "+" { setTokLength (1); RETURN_TOK (TPLUS); }
445 "*" { setTokLength (1); RETURN_TOK (TMULT); }
446 "/" { setTokLength (1); RETURN_TOK (TDIV); }
447 "%" { setTokLength (1); RETURN_TOK (TPERCENT); }
448 "<" { setTokLength (1); RETURN_TOK (TLT); }
449 ">" { setTokLength (1); RETURN_TOK (TGT); }
450 "^" { setTokLength (1); RETURN_TOK (TCIRC); }
451 "|" { setTokLength (1); RETURN_TOK (TBAR); }
452 "?" { setTokLength (1); RETURN_TOK (TQUEST); }
455 "/\\" { setTokLength (1); RETURN_TOK (TCAND); }
458 [ \t\v\f] { incColumn (); }
459 \n { context_incLineno ();
460 if (tokLength != 0) {
462 /* No error to report
465 message ("Likely parse error: token spans multiple lines."),
472 continueLine = FALSE;
476 if (context_inMacro ())
478 /* Don't use RETURN_TOK */
479 yylval.tok = lltok_create (TENDMACRO, fileloc_copy (g_currentloc)); /* !!! evans 2002-03-13 */
480 lastWasString = FALSE;
485 "@@MR@@" { setTokLength (6);
487 if (processMacro ()) {
488 if (context_inIterDef ())
490 RETURN_TOK (LLMACROITER);
492 if (context_inIterEnd ())
494 RETURN_TOK (LLMACROEND);
496 if (context_inMacro ())
498 RETURN_TOK (LLMACRO);
502 "@QLMR" { if (context_inHeader () || context_inFunction ())
508 int nspchar = ninput ();
512 ** This is a hack to get the column number correct.
515 llassert (nspchar >= '0' && nspchar <= '9');
517 nspaces = nspchar - '0';
519 setTokLength (5 + nspaces);
523 DPRINTF (("Here we are: %s", context_unparse ()));
525 if (context_inIterDef ())
527 RETURN_TOK (LLMACROITER);
529 if (context_inIterEnd ())
531 RETURN_TOK (LLMACROEND);
533 if (context_inMacro ())
535 RETURN_TOK (LLMACRO);
540 "@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); }
541 "@.FA" { setTokLength (4); lldiagmsg (message ("Access types: %q", typeIdSet_unparse (context_fileAccessTypes ()))); }
542 "@.F" { setTokLength (3);
543 lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc)));
545 "@.L" { setTokLength (3); usymtab_printLocal (); }
546 "@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); }
547 "@.C" { setTokLength (3); lldiagmsg (context_unparse ()); }
548 "@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); }
549 "@.G" { setTokLength (3); usymtab_printGuards (); }
550 "@.S" { setTokLength (3); usymtab_printOut (); }
551 "@.X" { setTokLength (3); usymtab_printAll (); }
552 "@.Z" { setTokLength (3); usymtab_printComplete (); }
553 "@.T" { setTokLength (3); usymtab_printTypes (); }
554 "@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); }
555 "@.M" { setTokLength (3);
556 lldiagmsg (message ("Can modify: %q",
557 sRefSet_unparse (context_modList ())));
559 "%{" { /* BEFORE_COMMENT_MARKER */
561 incColumn (); incColumn ();
562 tok = handleLlSpecial ();
566 if (tok == CANNOTATION) {
569 /* Beware - this bashes yylval! */
574 "%}" { /* AFTER_COMMENT_MARKER */
576 s_inSpecPart = FALSE;
577 s_whichSpecPart = BADTOK;
578 RETURN_TOK (QENDMACRO); }
579 "\\" { incColumn (); continueLine = TRUE; }
581 if ((int) *yytext == 13 ) {
586 message ("Invalid character (ascii: %d), skipping character",
594 ** Resets flags set by flex.head.
617 /*@=evalorderuncon@*/
620 /*@=loopswitchbreak@*/
621 /*@=switchswitchbreak@*/
629 /*@=elseifcomplete@*/
633 /*@=immediatetrans@*/
635 /*@=matchanyintegral@*/
647 /*@null@*/ /*@observer@*/ char *name;
652 ** These tokens are followed by syntax that is parsed by the
656 static struct skeyword s_parsetable[] = {
657 { "modifies", QMODIFIES } ,
658 { "globals", QGLOBALS } ,
661 { "constant", QCONSTANT } ,
662 { "function", QFUNCTION } ,
664 { "defines", QDEFINES } ,
666 { "allocates", QALLOCATES } ,
668 { "releases", QRELEASES } ,
669 { "pre", QPRECLAUSE } ,
670 { "post", QPOSTCLAUSE } ,
671 { "setBufferSize", QSETBUFFERSIZE},
672 { "setStringLength", QSETSTRINGLENGTH},
673 { "testinRange", QTESTINRANGE},
674 { "requires", QPRECLAUSE } ,
675 { "ensures", QPOSTCLAUSE } ,
676 { "invariant", QINVARIANT} ,
681 ** These tokens are either stand-alone tokens, or followed by
682 ** token-specific text.
685 static struct skeyword s_keytable[] = {
686 { "anytype", QANYTYPE } ,
687 { "integraltype", QINTEGRALTYPE } ,
688 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,
689 { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,
693 { "owned", QOWNED } ,
694 { "dependent", QDEPENDENT } ,
695 { "partial", QPARTIAL } ,
696 { "special", QSPECIAL } ,
697 { "truenull", QTRUENULL } ,
698 { "falsenull", QFALSENULL } ,
699 { "nullwhentrue", QTRUENULL } ,
700 { "falsewhennull", QFALSENULL } ,
703 { "notnull", QNOTNULL } ,
704 { "abstract", QABSTRACT } ,
705 { "numabstract", QNUMABSTRACT } ,
706 { "concrete", QCONCRETE } ,
707 { "mutable", QMUTABLE } ,
708 { "immutable", QIMMUTABLE } ,
709 { "unused", QUNUSED } ,
710 { "external", QEXTERNAL } ,
712 { "unique", QUNIQUE } ,
713 { "returned", QRETURNED } ,
714 { "exposed", QEXPOSED } ,
715 { "refcounted", QREFCOUNTED } ,
717 { "newref", QNEWREF } ,
718 { "tempref", QTEMPREF } ,
719 { "killref", QKILLREF } ,
721 { "relnull", QRELNULL } ,
722 { "nullterminated", QNULLTERMINATED },
723 { "setBufferSize", QSETBUFFERSIZE },
724 { "testInRange", QTESTINRANGE},
725 { "isnull", QISNULL },
726 { "MaxSet", QMAXSET},
727 { "MaxRead", QMAXREAD},
728 { "maxSet", QMAXSET},
729 { "maxRead", QMAXREAD},
730 { "reldef", QRELDEF } ,
731 { "observer", QOBSERVER } ,
732 { "exits", QEXITS } ,
733 { "noreturn", QEXITS } ,
734 { "mayexit", QMAYEXIT } ,
735 { "maynotreturn", QMAYEXIT } ,
736 { "trueexit", QTRUEEXIT } ,
737 { "falseexit", QFALSEEXIT } ,
738 { "noreturnwhentrue", QTRUEEXIT } ,
739 { "noreturnwhenfalse", QFALSEEXIT } ,
740 { "neverexit", QNEVEREXIT } ,
741 { "alwaysreturns", QNEVEREXIT } ,
743 { "shared", QSHARED } ,
745 { "unchecked", QUNCHECKED } ,
746 { "checked", QCHECKED } ,
747 { "checkmod", QCHECKMOD } ,
748 { "checkedstrict", QCHECKEDSTRICT } ,
749 { "innercontinue", QINNERCONTINUE } ,
750 { "innerbreak", QINNERBREAK } ,
751 { "loopbreak", QLOOPBREAK } ,
752 { "switchbreak", QSWITCHBREAK } ,
753 { "safebreak", QSAFEBREAK } ,
754 { "fallthrough", QFALLTHROUGH } ,
755 { "l_fallthrou", QLINTFALLTHROUGH } ,
756 { "l_fallth", QLINTFALLTHRU } ,
757 { "notreached", QNOTREACHED } ,
758 { "l_notreach", QLINTNOTREACHED } ,
759 { "printflike", QPRINTFLIKE } ,
760 { "l_printfli", QLINTPRINTFLIKE } ,
761 { "scanflike", QSCANFLIKE } ,
762 { "messagelike", QMESSAGELIKE } ,
763 { "l_argsus", QARGSUSED } ,
768 ** would be better if these weren't hard coded...
771 static bool isArtificial (cstring s)
773 return (cstring_equalLit (s, "modifies")
774 || cstring_equalLit (s, "globals")
775 || cstring_equalLit (s, "warn")
776 || cstring_equalLit (s, "alt"));
779 void cscanner_swallowMacro (void)
782 bool skipnext = FALSE;
784 while ((i = lminput ()) != EOF)
800 reader_checkUngetc (i, yyin);
812 reader_checkUngetc (i, yyin);
816 static int commentMarkerToken (cstring s)
820 while (s_parsetable[i].name != NULL)
822 DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name));
824 if (cstring_equalLit (s, s_parsetable[i].name))
826 return s_parsetable[i].token;
835 static int tokenMacroCode (cstring s)
839 while (s_keytable[i].name != NULL)
841 if (cstring_equalLit (s, s_keytable[i].name))
843 if (s_keytable[i].token == QLINTFALLTHROUGH)
846 (FLG_WARNLINTCOMMENTS,
848 ("Traditional lint comment /*FALLTHROUGH*/ used. "
849 "Splint interprets this in the same way as most Unix lints, but it is "
850 "preferable to replace it with the /*@fallthrough@*/ "
855 else if (s_keytable[i].token == QLINTFALLTHRU)
858 (FLG_WARNLINTCOMMENTS,
860 ("Traditional lint comment /*FALLTHRU*/ used. "
861 "Splint interprets this in the same way as most Unix lints, but it is "
862 "preferable to replace it with the /*@fallthrough@*/ "
867 else if (s_keytable[i].token == QLINTNOTREACHED)
870 (FLG_WARNLINTCOMMENTS,
872 ("Traditional lint comment /*NOTREACHED*/ used. "
873 "Splint interprets this in the same way as most Unix lints, but it is "
874 "preferable to replace it with the /*@notreached@*/ "
875 "semantic comment."),
880 else if (s_keytable[i].token == QPRINTFLIKE)
882 setSpecialFunction (qual_createPrintfLike ());
885 else if (s_keytable[i].token == QLINTPRINTFLIKE)
888 (FLG_WARNLINTCOMMENTS,
890 ("Traditional lint comment /*PRINTFLIKE*/ used. "
891 "Splint interprets this in the same way as most Unix lints, but it is "
892 "preferable to replace it with either /*@printflike@*/, "
893 "/*@scanflike@*/ or /*@messagelike@*/."),
896 setSpecialFunction (qual_createPrintfLike ());
899 else if (s_keytable[i].token == QSCANFLIKE)
901 setSpecialFunction (qual_createScanfLike ());
904 else if (s_keytable[i].token == QMESSAGELIKE)
906 setSpecialFunction (qual_createMessageLike ());
909 else if (s_keytable[i].token == QARGSUSED)
912 (FLG_WARNLINTCOMMENTS,
914 ("Traditional lint comment /*ARGSUSED*/ used. "
915 "Splint interprets this in the same way as most Unix lints, but it is "
916 "preferable to use /*@unused@*/ annotations on "
917 "the unused parameters."),
925 return s_keytable[i].token;
935 static int lminput ()
937 if (savechar == '\0')
944 int save = (int) savechar;
950 static void lmsavechar (char c)
952 if (savechar == '\0') savechar = c;
955 llbuglit ("lmsavechar: override");
959 static int returnFloat (ctype ct, double f)
961 yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext),
962 fileloc_decColumn (g_currentloc, tokLength));
967 static int returnInt (ctype ct, long i)
971 if (ctype_equal (ct, ctype_int))
975 c = context_typeofZero ();
979 c = context_typeofOne ();
987 yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext),
988 fileloc_decColumn (g_currentloc, tokLength), i);
993 static int returnChar (char c)
995 yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext),
996 fileloc_decColumn (g_currentloc, tokLength));
1001 static int ninput ()
1005 if (c != EOF && ((char)c == '\n'))
1007 context_incLineno ();
1013 static char macro_nextChar (void)
1015 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
1020 c = char_fromInt (ic);
1022 if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
1026 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
1028 ; /* skip to newline */
1031 context_incLineno ();
1035 return macro_nextChar ();
1042 else /* if (c == '@') */
1044 llassert (FALSE); /*@i23@*/
1045 if (handleLlSpecial () != BADTOK)
1047 llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
1050 return macro_nextChar ();
1053 else if (!in_escape && c == '\"')
1055 in_quote = !in_quote;
1057 else if (!in_escape && c == '\'')
1061 else if ((in_quote || in_char) && c == '\\')
1063 in_escape = !in_escape;
1065 else if ((in_quote || in_char) && in_escape)
1069 else if (!in_quote && c == '/')
1073 if ((c2 = char_fromInt (lminput ())) == '*')
1077 while ((c2 = char_fromInt (lminput ())) != '\0'
1078 && c2 != '\n' && c2 != '*')
1085 while ((c2 = char_fromInt (lminput ())) != '\0'
1098 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1102 return macro_nextChar ();
1106 /*** putchar does not work! why? puts to stdio...??! ***/
1119 ** keeps semantic comments
1122 static char macro_nextCharC (void)
1124 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
1127 c = char_fromInt (lminput ());
1129 if (!in_quote && !in_char && c == '\\')
1131 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
1133 ; /* skip to newline */
1136 context_incLineno ();
1140 return macro_nextCharC ();
1147 else if (!in_escape && c == '\"')
1149 in_quote = !in_quote;
1151 else if (!in_escape && c == '\'')
1155 else if ((in_quote || in_char) && c == '\\')
1157 in_escape = !in_escape;
1159 else if ((in_quote || in_char) && in_escape)
1163 else if (!in_quote && c == '/')
1167 if ((c2 = char_fromInt (lminput ())) == '*')
1171 while ((c2 = char_fromInt (lminput ())) != '\0'
1172 && c2 != '\n' && c2 != '*')
1179 while ((c2 = char_fromInt (lminput ())) != '\0'
1192 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1196 return macro_nextCharC ();
1203 else /* normal character */
1212 ** skips whitespace (handles line continuations)
1213 ** returns first non-whitespace character
1216 static char skip_whitespace (void)
1220 while ((c = macro_nextChar ()) == ' ' || c == '\t')
1228 static void handleMacro ()
1230 cstring mac = cstring_undefined;
1234 while (currentColumn () > 2)
1236 mac = cstring_appendChar (mac, ' ');
1240 c = macro_nextCharC ();
1242 if (c >= '0' && c <= '9')
1246 for (i = 0; i < (((int) (c - '0')) + 1); i++)
1248 mac = cstring_appendChar (mac, ' ');
1256 while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
1258 mac = cstring_appendChar (mac, c);
1262 macrocode = tokenMacroCode (mac);
1264 if (macrocode == BADTOK && !isArtificial (mac))
1266 context_addMacroCache (mac);
1275 context_incLineno ();
1279 static bool processMacro (void)
1284 cstring fname = cstring_undefined;
1286 bool isspecfcn = FALSE;
1287 bool isiter = FALSE;
1288 bool skipparam = FALSE;
1289 bool isenditer = FALSE;
1290 bool unknownm = FALSE;
1291 bool hasParams = FALSE;
1292 bool emptyMacro = FALSE;
1293 char c = skip_whitespace ();
1294 fileloc loc = fileloc_noColumn (g_currentloc);
1296 /* are both of these necessary? what do they mean? */
1297 uentryList specparams = uentryList_undefined;
1298 uentryList pn = uentryList_undefined;
1300 context_resetMacroMissingParams ();
1302 if (c == '\0' || c == '\n')
1304 llcontbug (cstring_makeLiteral ("Bad macro"));
1309 fname = cstring_appendChar (fname, c);
1311 while ((c = macro_nextChar ()) != '(' && c != '\0'
1312 && c != ' ' && c != '\t' && c != '\n')
1314 fname = cstring_appendChar (fname, c);
1317 if (c == ' ' || c == '\t' || c == '\n')
1323 while (c == ' ' || c == '\t')
1325 c = macro_nextChar ();
1339 hasParams = (c == '(');
1341 if (usymtab_exists (fname))
1343 e2 = usymtab_lookupExpose (fname);
1344 ct = uentry_getType (e2);
1346 if (uentry_isCodeDefined (e2)
1347 && fileloc_isUser (uentry_whereDefined (e2)))
1351 message ("Macro %s already defined", fname),
1354 uentry_showWhereDefined (e2);
1355 uentry_clearDefined (e2);
1358 if (uentry_isFunction (e2))
1360 uentry_setType (e2, ctype_unknown);
1363 context_enterUnknownMacro (e2);
1367 context_enterConstantMacro (e2);
1372 if (uentry_isForward (e2) && uentry_isFunction (e2))
1379 ("Parameterized macro has no prototype or specification: %s ",
1384 uentry_setType (e2, ctype_unknown);
1385 uentry_setFunctionDefined (e2, loc);
1386 uentry_setUsed (e2, fileloc_undefined);
1387 context_enterUnknownMacro (e2);
1391 if (uentry_isIter (e2))
1394 specparams = uentry_getParams (e2);
1395 noparams = uentryList_size (specparams);
1396 uentry_setDefined (e2, loc);
1397 context_enterIterDef (e2);
1399 else if (uentry_isEndIter (e2))
1402 uentry_setDefined (e2, loc);
1403 context_enterIterEnd (e2); /* don't care about it now */
1404 /* but should parse like an iter! */
1406 else if (uentry_isConstant (e2))
1412 message ("Constant %s implemented as parameterized macro",
1416 uentry_showWhereSpecified (e2);
1417 uentry_setType (e2, ctype_unknown);
1418 uentry_makeConstantFunction (e2);
1419 uentry_setDefined (e2, g_currentloc);
1420 uentry_setFunctionDefined (e2, g_currentloc);
1421 context_enterUnknownMacro (e2);
1425 if (!uentry_isSpecified (e2))
1427 fileloc oloc = uentry_whereDeclared (e2);
1429 if (fileloc_isLib (oloc))
1433 else if (fileloc_isUndefined (oloc)
1434 || fileloc_isPreproc (oloc))
1439 (FLG_MACROCONSTDECL,
1441 ("Macro constant %q not declared",
1442 uentry_getName (e2)),
1446 else if (!fileloc_withinLines (oloc, loc, 2))
1447 { /* bogus! will give errors if there is too much whitespace */
1451 ("Macro constant name %s does not match name in "
1452 "previous constant declaration. This constant "
1453 "is declared at %q", fname,
1454 fileloc_unparse (oloc)),
1463 context_enterConstantMacro (e2);
1464 cstring_free (fname);
1470 else if (ctype_isFunction (ct))
1473 specparams = ctype_argsFunction (ct);
1474 noparams = uentryList_size (specparams);
1476 uentry_setFunctionDefined (e2, loc);
1477 context_enterMacro (e2);
1479 else if (uentry_isVar (e2))
1485 message ("Variable %s implemented as parameterized macro",
1489 uentry_showWhereSpecified (e2);
1490 uentry_setType (e2, ctype_unknown);
1491 uentry_makeVarFunction (e2);
1492 uentry_setDefined (e2, g_currentloc);
1493 uentry_setFunctionDefined (e2, g_currentloc);
1494 context_enterUnknownMacro (e2);
1498 uentry ucons = uentry_makeConstant (fname,
1501 if (uentry_isExpandedMacro (e2))
1509 message ("Variable %s implemented by a macro",
1513 uentry_showWhereSpecified (e2);
1517 uentry_setDefined (e2, loc);
1518 uentry_setUsed (ucons, loc);
1520 context_enterConstantMacro (ucons);
1521 uentry_markOwned (ucons);
1522 cstring_free (fname);
1528 if (uentry_isDatatype (e2))
1532 message ("Type implemented as macro: %x",
1533 uentry_getName (e2)),
1534 message ("A type is implemented using a macro definition. A "
1535 "typedef should be used instead."),
1538 cscanner_swallowMacro ();
1539 /* Must exit scope (not sure why a new scope was entered?) */
1540 usymtab_quietExitScope (g_currentloc);
1541 uentry_setDefined (e2, g_currentloc);
1547 (message ("Unexpanded macro not function or constant: %q",
1548 uentry_unparse (e2)));
1549 uentry_setType (e2, ctype_unknown);
1553 uentry_makeVarFunction (e2);
1554 uentry_setDefined (e2, g_currentloc);
1555 uentry_setFunctionDefined (e2, g_currentloc);
1556 context_enterUnknownMacro (e2);
1567 /* evans 2001-09-09 - if it has params, assume a function */
1571 (FLG_MACROMATCHNAME,
1572 message ("Unexpanded macro %s does not match name of a declared "
1573 "function. The name used in the control "
1574 "comment on the previous line should match.",
1578 ce = uentry_makeFunction (fname, ctype_unknown,
1582 warnClause_undefined,
1584 uentry_setUsed (ce, loc); /* perhaps bogus? */
1585 e2 = usymtab_supEntryReturn (ce);
1586 context_enterUnknownMacro (e2);
1591 (FLG_MACROMATCHNAME,
1592 message ("Unexpanded macro %s does not match name of a constant "
1593 "or iter declaration. The name used in the control "
1594 "comment on the previous line should match. "
1595 "(Assuming macro defines a constant.)",
1599 ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
1600 uentry_setUsed (ce, loc); /* perhaps bogus? */
1601 e2 = usymtab_supEntryReturn (ce);
1603 context_enterConstantMacro (e2);
1604 cstring_free (fname);
1610 /* in macros, ( must follow immediatetly after name */
1616 c = skip_whitespace ();
1618 while (c != ')' && c != '\0')
1621 bool suppress = context_inSuppressRegion ();
1622 cstring paramname = cstring_undefined;
1625 ** save the parameter location
1629 context_saveLocation ();
1632 while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
1634 paramname = cstring_appendChar (paramname, c);
1635 c = macro_nextChar ();
1638 if (c == ' ' || c == '\t') c = skip_whitespace ();
1642 c = macro_nextChar ();
1643 if (c == ' ' || c == '\t') c = skip_whitespace ();
1648 llfatalerror (cstring_makeLiteral
1649 ("Bad macro syntax: uentryList"));
1652 if ((isspecfcn || isiter) && (paramno < noparams)
1653 && !uentry_isElipsisMarker (uentryList_getN
1654 (specparams, paramno)))
1656 fileloc sloc = context_getSaveLocation ();
1657 uentry decl = uentryList_getN (specparams, paramno);
1660 param = uentry_nameCopy (paramname, decl);
1662 uentry_setParam (param);
1663 sr = sRef_makeParam (paramno, uentry_getType (param), stateInfo_makeLoc (sloc));
1665 if (sRef_getNullState (sr) == NS_ABSNULL)
1667 ctype pt = ctype_realType (uentry_getType (param));
1669 if (ctype_isUser (pt))
1671 uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
1673 if (uentry_isValid (te))
1675 sRef_setStateFromUentry (sr, te);
1680 sRef_setNullState (sr, NS_UNKNOWN, sloc);
1684 uentry_setSref (param, sr);
1685 uentry_setDeclaredForceOnly (param, sloc);
1687 skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
1691 fileloc sloc = context_getSaveLocation ();
1693 param = uentry_makeVariableSrefParam
1694 (paramname, ctype_unknown, fileloc_copy (sloc),
1695 sRef_makeParam (paramno, ctype_unknown, stateInfo_makeLoc (sloc)));
1696 DPRINTF (("Unknown param: %s", uentry_unparseFull (param)));
1697 cstring_free (paramname);
1699 sRef_setPosNull (uentry_getSref (param), sloc);
1700 uentry_setDeclaredForce (param, sloc);
1703 fileloc_free (sloc);
1708 llassert (!uentry_isElipsisMarker (param));
1712 sRef_makeUnsafe (uentry_getSref (param));
1715 pn = uentryList_add (pn, uentry_copy (param));
1716 usymtab_supEntry (param);
1720 /* don't add param */
1721 uentry_free (param);
1726 (void) macro_nextChar ();
1727 c = skip_whitespace ();
1735 if (isspecfcn || isiter)
1737 if (paramno != noparams && noparams >= 0)
1743 message ("Macro %s specified with %d args, defined with %d",
1744 fname, noparams, paramno),
1747 uentry_showWhereSpecified (e2);
1748 uentry_resetParams (e2, pn);
1753 uentry_resetParams (e2, pn);
1760 ** the form should be:
1762 ** # define newname oldname
1763 ** where oldname refers to a function matching the specification
1769 sRef_setGlobalScope ();
1770 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
1771 sRef_clearGlobalScope ();
1775 context_setMacroMissingParams ();
1780 /* context_setuentryList (pn); */
1781 usymtab_enterScope ();
1784 cstring_free (fname);
1789 static bool handleSpecial (char *yyt)
1791 char *l; /* !! = mstring_create (MAX_NAME_LENGTH); */
1798 len_yyt = strlen (yyt +1) ;
1800 l = mstring_copy (yyt + 1);
1802 while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
1804 l = mstring_append(l, c);
1807 /* Need to safe original l for deallocating. */
1812 olc = cstring_fromChars (ol);
1814 if (cstring_equalPrefixLit (olc, "pragma"))
1816 char *pname = mstring_create (size_fromInt (MAX_PRAGMA_LEN));
1817 char *opname = pname;
1818 char *ptr = ol + 6; /* pragma is six characters, plus space */
1822 /* skip whitespace */
1823 while (((c = *ptr) != '\0') && isspace (c))
1829 while (((c = *ptr) != '\0') && !isspace (c))
1833 if (len > MAX_PRAGMA_LEN)
1844 if (len == PRAGMA_LEN_EXPAND
1845 && mstring_equal (opname, PRAGMA_EXPAND))
1847 cstring exname = cstring_undefined;
1851 while (((c = *ptr) != '\0') && !isspace (c))
1853 exname = cstring_appendChar (exname, c);
1858 ue = usymtab_lookupExposeGlob (exname);
1860 if (uentry_isExpandedMacro (ue))
1862 if (fileloc_isPreproc (uentry_whereDefined (ue)))
1864 fileloc_setColumn (g_currentloc, 1);
1865 uentry_setDefined (ue, g_currentloc);
1869 cstring_free (exname);
1872 else if (cstring_equalPrefixLit (olc, "ident"))
1874 /* Some pre-processors will leave these in the code. Ignore rest of line */
1877 ** Yuk...Win32 filenames can have spaces in them...we need to read
1878 ** to the matching end quote.
1880 else if ((sscanf (ol, "line %d \"", &lineno) == 1)
1881 || (sscanf (ol, " %d \"", &lineno) == 1))
1887 /*@access cstring@*/
1888 while (*tmp != '\"' && *tmp != '\0')
1893 llassert (*tmp == '\"');
1899 while (*tmp != '\"' && *tmp != '\0')
1904 llassert (*tmp == '\"');
1908 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
1911 ** DOS-like path delimiters get delivered in pairs, something like
1912 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
1913 ** remove the pre dirs yet as we usually specify tmp paths relative
1914 ** to the current directory, so tmp files would not get found in
1915 ** the hash table. If this method fails we try it again later.
1922 ** Skip past the drive marker.
1925 if (strchr (stmp, ':') != NULL)
1927 stmp = strchr (stmp, ':') + 1;
1930 while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
1932 if (*(stmp+1) == CONNECTCHAR)
1934 memmove (stmp, stmp+1, strlen (stmp));
1940 fid = fileTable_lookupBase (context_fileTable (), fname);
1941 if (!(fileId_isValid (fid)))
1943 fname = removePreDirs (fname);
1944 fid = fileTable_lookupBase (context_fileTable (), fname);
1947 # else /* !defined(OS2) && !defined(MSDOS) */
1948 fname = removePreDirs (fname);
1949 fid = fileTable_lookupBase (context_fileTable (), fname);
1950 # endif /* !defined(OS2) && !defined(MSDOS) */
1952 if (!(fileId_isValid (fid)))
1954 if (context_inXHFile ())
1956 fid = fileTable_addXHFile (context_fileTable (), fname);
1958 else if (isHeaderFile (fname))
1960 fid = fileTable_addHeaderFile (context_fileTable (), fname);
1964 fid = fileTable_addFile (context_fileTable (), fname);
1968 setFileLine (fid, lineno);
1969 /*@noaccess cstring@*/
1971 else if ((sscanf (ol, "line %d", &lineno) == 1)
1972 || (sscanf (ol, " %d", &lineno) == 1))
1974 setLine (lineno); /* next line is <cr> */
1978 if (mstring_equal (ol, "")) {
1979 DPRINTF (("Empty pp command!"));
1981 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
1982 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
1988 (FLG_UNRECOGDIRECTIVE,
1989 message ("Unrecognized pre-processor directive: #%s",
1990 cstring_fromChars (ol)),
1995 return FALSE; /* evans 2001-12-30: was: TRUE; */
2002 static int handleLlSpecial (void)
2007 char *s = mstring_createEmpty ();
2013 loc = fileloc_copy (g_currentloc);
2014 DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
2016 while (((ic = ninput ()) != 0) && isalpha (ic))
2019 s = mstring_append (s, c);
2023 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
2026 if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
2030 llassert (ic == (int) AFTER_COMMENT_MARKER[1]);
2036 return QNOMODS; /* special token no modifications token */
2040 DPRINTF (("Coment marker: %s", os));
2041 tok = commentMarkerToken (cstring_fromChars (os));
2045 tokLength = charsread;
2047 s_inSpecPart = TRUE;
2048 s_whichSpecPart = tok;
2053 DPRINTF (("Not a comment marker..."));
2054 /* Add rest of the comment */
2056 if (ic != 0 && ic != EOF)
2060 s = mstring_append (s, c);
2063 while (((ic = ninput ()) != 0) && (ic != EOF)
2064 && (ic != (int) AFTER_COMMENT_MARKER[0]))
2068 /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
2071 hasnl = TRUE; /* This prevents tokLength from being set later. */
2076 message ("Likely parse error: syntactic comment token spans multiple lines: %s",
2077 cstring_fromChars (s)),
2081 s = mstring_append (s, c);
2086 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
2088 if (ic == (int) AFTER_COMMENT_MARKER[0])
2091 llassert ((char) nc == AFTER_COMMENT_MARKER[1]);
2097 while (*s == ' ' || *s == '\t' || *s == '\n')
2102 if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
2106 while (c == '-' || c == '+' || c == '=')
2108 ynm set = ynm_fromCodeChar (c);
2113 thisflag = cstring_fromChars (s);
2115 while ((c = *s) != '\0' && (c != '-') && (c != '=')
2116 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
2123 if (!context_getFlag (FLG_NOCOMMENTS))
2125 cstring flagname = thisflag;
2126 flagcode fflag = flags_identifyFlag (flagname);
2128 if (flagcode_isSkip (fflag))
2132 else if (flagcode_isModeName (fflag))
2134 if (ynm_isMaybe (set))
2139 ("Semantic comment attempts to restore flag %s. "
2140 "A mode flag cannot be restored.",
2145 context_setMode (flagname);
2148 else if (flagcode_isInvalid (fflag))
2151 (FLG_UNRECOGFLAGCOMMENTS,
2152 message ("Unrecognized option in semantic comment: %s",
2156 else if (flagcode_isGlobalFlag (fflag))
2161 ("Semantic comment attempts to set global flag %s. "
2162 "A global flag cannot be set locally.",
2168 context_fileSetFlag (fflag, set, loc);
2170 if (flagcode_hasArgument (fflag))
2172 if (ynm_isMaybe (set))
2177 ("Semantic comment attempts to restore flag %s. "
2178 "A flag for setting a value cannot be restored.",
2183 { /* cut-and-pastied from llmain...blecch */
2184 cstring extra = cstring_undefined;
2190 rest = mstring_copy (s);
2194 while ((rchar = *rest) != '\0'
2195 && (isspace (rchar)))
2201 while ((rchar = *rest) != '\0'
2202 && !isspace (rchar))
2204 extra = cstring_appendChar (extra, rchar);
2208 s--; /* evans 2002-07-12: this was previously only in the else branch.
2209 Leads to an invalid read on the true branch.
2214 if (cstring_isUndefined (extra))
2219 ("Flag %s (in semantic comment) must be followed by an argument",
2220 flagcode_unparse (fflag)));
2225 if (flagcode_hasNumber (fflag))
2227 setValueFlag (fflag, extra);
2229 else if (flagcode_hasChar (fflag))
2231 setValueFlag (fflag, extra);
2233 else if (flagcode_hasString (fflag))
2235 setStringFlag (fflag, extra);
2239 cstring_free (extra);
2253 while ((c == ' ') || (c == '\t') || (c == '\n'))
2259 if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
2261 DPRINTF (("Here adding comment: %s", os));
2262 context_addComment (cstring_fromCharsNew (os), loc);
2274 annotationInfo ainfo;
2276 while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
2288 t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
2289 macrocode = tokenMacroCode (cstring_fromChars (t));
2291 if (macrocode != BADTOK)
2293 tokLength = hasnl ? 0 : size_toInt (mstring_length (t));
2299 if (macrocode == SKIPTOK)
2307 ainfo = context_lookupAnnotation (cstring_fromChars (os));
2309 if (annotationInfo_isDefined (ainfo)) {
2310 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
2311 /*@i324@*/ yylval.annotation = ainfo;
2319 if (context_inHeader ())
2326 if ((context_inMacro () || context_inGlobalContext ())
2327 && macrocode != SKIPTOK
2328 && !isArtificial (cstring_fromChars (os)))
2330 if (context_processingMacros ())
2332 /* evans 2002-02-24: don't add comments when procssing macros */
2336 context_addComment (cstring_fromCharsNew (os), loc);
2350 if (mstring_equal (t, "ignore"))
2352 if (!context_getFlag (FLG_NOCOMMENTS))
2354 context_enterSuppressRegion (loc);
2357 else if ((*t == 'i' || *t == 't')
2358 && (*(t + 1) == '\0'))
2360 if (!context_getFlag (FLG_NOCOMMENTS)
2361 && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
2363 context_enterSuppressLine (-1, loc); /* infinite suppression */
2366 else if (((*t == 'i') || (*t == 't'))
2367 && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
2369 bool tmpcomment = (*t == 't');
2371 char *tt = t; /* don't mangle t, since it is free'd */
2374 if (lc >= '0' && lc <= '9')
2376 val = (int)(lc - '0');
2379 while (lc >= '0' && lc <= '9')
2382 val += (int) (lc - '0');
2387 if (!context_getFlag (FLG_NOCOMMENTS)
2388 && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
2390 DPRINTF (("Here: enter suppress: %s", fileloc_unparse (loc)));
2391 context_enterSuppressLine (val, loc);
2394 else if (mstring_equal (t, "end"))
2396 if (!context_getFlag (FLG_NOCOMMENTS))
2398 context_exitSuppressRegion (loc);
2401 else if (mstring_equal (t, "notfunction"))
2403 ; /* handled by pcpp */
2405 else if (mstring_equal (t, "access"))
2411 while (((c = *s) != '\0') && (c == ' ' || c == '\t' || c == '\n'))
2421 tname = cstring_fromChars (s);
2423 while ((c = *s) != '\0' && c != ' '
2424 && c != '\t' && c != '\n' && c != ',')
2431 DPRINTF (("Access %s", tname));
2433 if (!context_getFlag (FLG_NOCOMMENTS)
2434 && !context_getFlag (FLG_NOACCESS))
2436 if (usymtab_existsType (tname))
2438 typeId uid = usymtab_getTypeId (tname);
2439 uentry ue = usymtab_getTypeEntry (uid);
2441 if (uentry_isAbstractDatatype (ue))
2443 context_addFileAccessType (uid);
2444 DPRINTF (("Adding access to: %s / %d", tname, uid));
2451 ("Non-abstract type %s used in access comment",
2458 if (!(context_inSuppressRegion ()
2459 || context_inSuppressZone (loc)))
2464 ("Unrecognized type %s used in access comment",
2476 if (c != ',' && c != ' ')
2482 else if (mstring_equal (t, "noaccess"))
2489 while (((lc = *s) != '\0') && (lc == ' ' || lc == '\t' || lc == '\n'))
2499 tname = cstring_fromChars (s);
2501 while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
2502 && lc != '\n' && lc != ',')
2509 if (!context_getFlag (FLG_NOCOMMENTS)
2510 && !context_getFlag (FLG_NOACCESS))
2512 if (usymtab_existsType (tname))
2514 typeId tuid = usymtab_getTypeId (tname);
2516 if (context_couldHaveAccess (tuid))
2518 DPRINTF (("Removing access: %s", tname));
2519 context_removeFileAccessType (tuid);
2523 if (!(context_inSuppressRegion ()
2524 || context_inSuppressZone (loc)))
2526 uentry ue = usymtab_getTypeEntry (tuid);
2528 if (uentry_isAbstractDatatype (ue))
2533 ("Non-accessible abstract type %s used in noaccess comment",
2542 ("Non-abstract type %s used in noaccess comment",
2551 if (!(context_inSuppressRegion ()
2552 || context_inSuppressZone (loc)))
2557 ("Unrecognized type %s used in noaccess comment",
2569 if (lc != ',' && lc != ' ')
2577 voptgenerror (FLG_UNRECOGCOMMENTS,
2578 message ("Semantic comment unrecognized: %s",
2579 cstring_fromChars (os)),
2591 static /*@only@*/ cstring makeIdentifier (char *s)
2593 char *c = mstring_create (strlen (s) + 1);
2594 cstring id = cstring_fromChars (c);
2596 while (isalnum (*s) || (*s == '_') || (*s == '$'))
2605 /*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn)
2607 if (!(usymtab_exists (cn)))
2609 fileloc loc = fileloc_createExternal ();
2612 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
2615 uentry ce = uentry_makeUnrecognized (cn, loc);
2617 if (!context_inIterEnd ())
2621 message ("Unrecognized (possibly system) identifier: %q",
2622 uentry_getName (ce)),
2629 return (usymtab_lookup (cn));
2633 ** like, coerceId, but doesn't supercede for iters
2636 /*@observer@*/ uentry coerceIterId (cstring cn)
2638 if (!(usymtab_exists (cn)))
2640 return uentry_undefined;
2643 return (usymtab_lookup (cn));
2647 ** Need to keep this in case there is a declaration that isn't processed until
2648 ** the scope exits. Would be good to rearrange the symbol table so this doesn't
2649 ** happen, and save all the cstring copying.
2652 /*@observer@*/ cstring cscanner_observeLastIdentifier ()
2654 cstring res = s_lastidprocessed;
2658 static void cscanner_setLastIdentifier (/*@keep@*/ cstring id) /*@modifies s_lastidprocessed@*/
2660 if (cstring_isDefined (s_lastidprocessed))
2662 cstring_free (s_lastidprocessed);
2665 s_lastidprocessed = id;
2668 static int processIdentifier (cstring id)
2672 if (context_getFlag (FLG_GRAMMAR))
2674 lldiagmsg (message ("Process identifier: %s", id));
2677 context_clearJustPopped ();
2678 cscanner_setLastIdentifier (id);
2680 DPRINTF (("Context: %s", context_unparse ()));
2682 if (context_inFunctionHeader ())
2684 int tok = commentMarkerToken (id);
2685 DPRINTF (("in function decl: %s", id));
2693 tok = tokenMacroCode (id);
2701 annotationInfo ainfo;
2703 if (expectingMetaStateName)
2705 metaStateInfo msinfo = context_lookupMetaStateInfo (id);
2707 if (metaStateInfo_isDefined (msinfo))
2709 yylval.msinfo = msinfo;
2710 return METASTATE_NAME;
2714 DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id)));
2718 ainfo = context_lookupAnnotation (id);
2720 if (annotationInfo_isDefined (ainfo))
2722 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
2723 /*@i324@*/ yylval.annotation = ainfo;
2728 DPRINTF (("Not annotation: %s", id));
2734 DPRINTF (("Here!"));
2736 /* Consider handling: Defined by C99 as static const char __func__[] */
2738 if (context_getFlag (FLG_GNUEXTENSIONS))
2742 if (cstring_equalLit (id, "__stdcall")
2743 || cstring_equalLit (id, "__cdecl")
2744 || cstring_equalLit (id, "__extension__"))
2748 else if (cstring_equalLit (id, "__volatile__"))
2752 else if (cstring_equalLit (id, "__signed"))
2756 else if (cstring_equalLit (id, "__unsigned"))
2760 else if (cstring_equalLit (id, "__const__"))
2764 else if (cstring_equalLit (id, "__alignof__"))
2766 tok = CALIGNOF; /* alignof is parsed like sizeof */
2768 else if (cstring_equalLit (id, "__typeof__"))
2772 else if (cstring_equalLit (id, "typeof"))
2776 else if (cstring_equalLit (id, "__FUNCTION__")
2777 || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
2779 /* These tokens hold the name of the current function as strings */
2780 /* evans 2001-12-30: changed from exprNode_stringLiteral; bug reported by Jim Zelenka. */
2781 yylval.expr = exprNode_makeConstantString (id, fileloc_copy (g_currentloc));
2783 lastWasString = TRUE;
2787 else if (cstring_equalLit (id, "__attribute__")
2788 || cstring_equalLit (id, "__asm__")
2789 || cstring_equalLit (id, "_asm")
2790 || cstring_equalLit (id, "__asm")
2791 || cstring_equalLit (id, "__declspec"))
2794 bool useparens = FALSE;
2795 bool usebraces = FALSE;
2796 bool inquote = FALSE;
2797 bool inescape = FALSE;
2800 while ((ic = input ()) != EOF)
2802 char cc = (char) ic;
2808 else if (cc == '\\')
2812 else if (cc == '\"')
2848 else if (cc == ')' && useparens)
2851 if (depth == 0) break;
2853 else if (cc == '}' && usebraces)
2856 if (depth == 0) break;
2859 && !usebraces && !useparens
2860 && cstring_equalLit (id, "__asm"))
2863 ** We need this because some MS VC++ include files
2864 ** have __asm mov ... }
2865 ** Its a kludge, but otherwise would need to parse
2882 context_incLineno ();
2884 if (cstring_equalLit (id, "__asm")
2885 && !useparens && !usebraces)
2892 llassert ((useparens && ic == (int) ')')
2893 || (usebraces && ic == (int) '}')
2894 || (!useparens && !usebraces));
2898 else if (cstring_equalLit (id, "inline")
2899 || cstring_equalLit (id, "__inline")
2900 || cstring_equalLit (id, "_inline")
2901 || cstring_equalLit (id, "__inline__"))
2916 le = usymtab_lookupSafe (id);
2918 /*@-dependenttrans@*/
2920 if (uentry_isIter (le))
2922 /*@i32@*/ yylval.entry = le;
2925 else if (uentry_isEndIter (le))
2927 /*@i32@*/ yylval.entry = le;
2928 return (ITER_ENDNAME);
2930 else if (uentry_isUndefined (le))
2932 yylval.cname = cstring_copy (id);
2934 /* avoid parse errors for certain system built ins */
2936 if (g_expectingTypeName && (cstring_firstChar (id) == '_')
2937 && (cstring_secondChar (id) == '_'))
2939 return (TYPE_NAME_OR_ID);
2942 return (NEW_IDENTIFIER);
2944 else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
2946 if (uentry_isDatatype (le))
2948 yylval.cname = cstring_copy (id);
2949 return (NEW_IDENTIFIER);
2953 /*@i32@*/ yylval.entry = le;
2954 return (IDENTIFIER);
2957 else if (uentry_isDatatype (le))
2959 if (!g_expectingTypeName)
2961 yylval.cname = cstring_copy (id);
2963 return (NEW_IDENTIFIER);
2967 yylval.ctyp = uentry_getAbstractType (le);
2969 uentry_setUsed (le, g_currentloc);
2975 /*@i32@*/ yylval.entry = le;
2976 return (IDENTIFIER);
2979 /*@=dependenttrans@*/
2982 static bool processHashIdentifier (/*@only@*/ cstring id)
2984 if (context_inMacro () || context_inIterDef () ||
2985 context_inIterEnd ())
2989 context_clearJustPopped ();
2991 le = usymtab_lookupSafe (id);
2992 cscanner_setLastIdentifier (id);
2994 if (uentry_isParam (le) || uentry_isRefParam (le))
3006 ** Will be handled by handleLlSpecial
3015 static /*@only@*/ exprNode processString (void)
3019 char *nl = strchr (yytext, '\n');
3020 cstring ns = cstring_fromCharsNew (yytext);
3024 loc = fileloc_copy (g_currentloc);
3025 addColumn (size_toInt (cstring_length (ns)));
3031 loc = fileloc_copy (g_currentloc);
3033 context_incLineno ();
3035 while ((nl = strchr ((nl + 1), '\n')) != NULL)
3037 context_incLineno ();
3043 res = exprNode_stringLiteral (ns, loc);
3048 ** process a wide character string L"...."
3051 static /*@only@*/ exprNode processWideString ()
3055 char *nl = strchr (yytext, '\n');
3058 llassert (*yytext == 'L');
3061 ns = cstring_fromCharsNew (yytext);
3065 loc = fileloc_copy (g_currentloc);
3066 addColumn (size_toInt (cstring_length (ns)));
3072 loc = fileloc_copy (g_currentloc);
3074 context_incLineno ();
3076 while ((nl = strchr ((nl + 1), '\n')) != NULL)
3078 context_incLineno ();
3083 res = exprNode_wideStringLiteral (ns, loc);
3093 llassert (*yytext != '\0');
3094 fchar = *(yytext + 1);
3095 if (fchar != '\\') return fchar;
3097 next = *(yytext + 2);
3101 case 'n': return '\n';
3102 case 't': return '\t';
3103 case '\"': return '\"';
3104 case '\'': return '\'';
3105 case '\\': return '\\';
3106 default: return '\0';
3111 double processFloat ()
3113 double ret = atof (yytext);
3124 llassert (yytext[0] == '0'
3125 && (yytext[1] == 'X' || yytext[1] == 'x'));
3127 while (yytext[index] != '\0') {
3129 char c = yytext[index];
3131 if (c >= '0' && c <= '9') {
3132 tval = (int) c - (int) '0';
3133 } else if (c >= 'A' && c <= 'F') {
3134 tval = (int) c - (int) 'A' + 10;
3135 } else if (c >= 'a' && c <= 'f') {
3136 tval = (int) c - (int) 'a' + 10;
3137 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
3139 while (yytext[index] != '\0') {
3140 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
3145 message ("Invalid character (%c) following specifier in hex constant: %s",
3146 c, cstring_fromChars (yytext)),
3156 message ("Invalid character (%c) in hex constant: %s",
3157 c, cstring_fromChars (yytext)),
3162 val = (val * 16) + tval;
3166 DPRINTF (("Hex constant: %s = %ld", yytext, val));
3171 long processOctal ()
3176 llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
3178 while (yytext[index] != '\0') {
3180 char c = yytext[index];
3182 if (c >= '0' && c <= '7') {
3183 tval = (int) c - (int) '0';
3184 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
3186 while (yytext[index] != '\0') {
3187 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
3192 message ("Invalid character (%c) following specifier in octal constant: %s",
3193 c, cstring_fromChars (yytext)),
3203 message ("Invalid character (%c) in octal constant: %s",
3204 c, cstring_fromChars (yytext)),
3209 val = (val * 8) + tval;
3213 DPRINTF (("Octal constant: %s = %ld", yytext, val));
3220 return (atol (yytext));
3224 processSpec (int tok)
3226 size_t length = strlen (yytext);
3232 patched to fix assert failures in constraint code.
3233 Added the else if test so that splint does not treat MaxSet and MaxRead
3236 if (s_whichSpecPart == QMODIFIES
3237 || s_whichSpecPart == QDEFINES
3238 || s_whichSpecPart == QUSES
3239 || s_whichSpecPart == QALLOCATES
3240 || s_whichSpecPart == QSETS
3241 || s_whichSpecPart == QRELEASES)
3244 DPRINTF((message("Treating specifaction keyword %s as an identifiers. (This corresponds to"
3245 " token %d and we're in the specification denoted by %d see cgrammar_tokens.h"
3246 " for an explanation of these numbers",
3247 yytext, tok, s_whichSpecPart)
3250 ; /* Allow specificiation keywords to be used as identifiers in these contexts. */
3252 else if ( (s_whichSpecPart == QPRECLAUSE
3253 || s_whichSpecPart == QPOSTCLAUSE
3254 || s_whichSpecPart == QINVARIANT )
3255 && (!isConstraintToken(tok) )
3258 DPRINTF((message("Treating specifaction keyword %s as an identifiers. (This corresponds to"
3259 " token %d and we're in the specification denoted by %d see cgrammar_tokens.h"
3260 " for an explanation of these numbers",
3261 yytext, tok, s_whichSpecPart)
3264 /* Allow specificiation keywords to be used as identifiers in these contexts. */
3268 setTokLengthT (length);
3273 context_saveLocation ();
3274 setTokLengthT (length);
3275 return (processIdentifier (makeIdentifier (yytext)));
3278 void cscanner_expectingMetaStateName ()
3280 llassert (!expectingMetaStateName);
3281 llassert (context_inFunctionHeader ());
3282 expectingMetaStateName = TRUE;
3285 void cscanner_clearExpectingMetaStateName ()
3287 llassert (expectingMetaStateName);
3288 expectingMetaStateName = FALSE;
3291 /*drl added 12/11/2002
3292 Tell whether a token has special meaning
3293 within a function constraint
3296 /*uncomment the additional if statement tests
3297 when minSet and minRead are supported
3299 int isConstraintToken(int tok)
3304 /* || tok == QMINREAD
3305 || tok == QMINSET */