2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 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 lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-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 LCLint 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 "lclintMacros.nf"
68 # if defined(OS2) && defined(__IBMC__)
69 /* needed for isatty()... */
77 # include "cgrammar.h"
78 # include "cgrammar_tokens.h"
80 # include "fileIdList.h"
83 static bool lastWasString = FALSE;
84 static char savechar = '\0';
87 # define yyinput() (incColumn (), getc (yyin))
89 static /*@owned@*/ cstring lastidprocessed = cstring_undefined;
90 static int lminput (void);
91 static int tokLength = 0;
92 static bool inSpecPart = FALSE;
93 static bool continueLine = FALSE;
95 static int ninput (void);
96 static char processChar (void);
97 static double processFloat (void);
98 static /*@only@*/ exprNode processString (void);
99 static long processDec (void);
100 static long processHex (void);
101 static long processOctal (void);
102 static int processIdentifier (/*@only@*/ cstring)
103 /*@globals undef lastidprocessed@*/ ;
104 static bool processHashIdentifier (/*@only@*/ cstring)
105 /*@globals undef lastidprocessed@*/ ;
107 static int processSpec (int);
108 static bool handleSpecial (char *);
109 static int handleLlSpecial (void);
110 static void handleMacro (void);
111 static bool processMacro (void);
112 static /*@only@*/ cstring makeIdentifier (char *);
114 /* yes, this is exported! */
115 bool g_expectingTypeName = TRUE; /* beginning of file can be type name! */
117 static bool expectingMetaStateName = FALSE;
119 static int returnInt (ctype, long);
120 static int returnFloat (ctype, double);
121 static int returnChar (char);
122 static void setTokLength (int) /*@modifies g_currentloc@*/ ;
123 static void setTokLengthT (size_t) /*@modifies g_currentloc@*/ ;
125 static void advanceLine (void)
132 # define RETURN_INT(c,i) \
133 do { lastWasString = FALSE; \
134 return (returnInt (c, i)); } while (FALSE)
136 # define RETURN_FLOAT(c,f) \
137 do { lastWasString = FALSE; \
138 return (returnFloat (c, f)); \
141 # define RETURN_CHAR(c) \
142 do { lastWasString = FALSE; \
143 return (returnChar (c)); \
146 # define RETURN_TOK(t) \
147 do { yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, tokLength)); \
149 lastWasString = FALSE; \
150 return (t); } while (FALSE)
152 # define RETURN_TYPE(t, ct) \
153 do { yylval.ctyp = ct; tokLength = 0; return (t); } while (FALSE)
155 /* don't fileloc_decColumn (g_currentloc, tokLength));
156 the string could have \n's in it!
159 # define RETURN_STRING(c) \
160 do { yylval.expr = exprNode_stringLiteral (c, fileloc_decColumn (g_currentloc, tokLength)); \
162 lastWasString = TRUE; \
163 return (CCONSTANT); } while (FALSE)
165 # define RETURN_EXPR(e) \
166 do { yylval.expr = e; \
168 lastWasString = TRUE; \
169 return (CCONSTANT); } while (FALSE)
173 static void setTokLength (int len)
177 DPRINTF (("Set tok length: %d", len));
180 static void setTokLengthT (size_t len)
182 setTokLength (size_toInt (len));
185 # include "flex.head"
187 /*@-unrecog@*/ /*@i5343@*/
193 "/*" { llfatalbug (cstring_makeLiteral ("Comment in pre-processor output")); }
195 "#"{Letter}({Letter}|{Digit})* {
196 context_saveLocation ();
197 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
199 if (processHashIdentifier (makeIdentifier (yytext + 1)))
203 /* was nothing! */ /*@i32@*/
204 RETURN_STRING (cstring_makeLiteral ("\"\""));
208 RETURN_STRING (cstring_makeLiteral ("\"\""));
213 if (handleSpecial (yytext))
220 "#" { if (handleSpecial (yytext))
222 setTokLength (1); RETURN_TOK (0);
225 "..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); }
226 "break" { setTokLength (5); RETURN_TOK (BREAK); }
227 "case" { setTokLength (4); RETURN_TOK (CASE); }
228 "continue" { setTokLength (8); RETURN_TOK (CONTINUE); }
229 "default" { setTokLength (7); RETURN_TOK (DEFAULT); }
230 "do" { setTokLength (2); RETURN_TOK (DO); }
231 "else" { setTokLength (4); RETURN_TOK (CELSE); }
232 "for" { setTokLength (3); RETURN_TOK (CFOR); }
233 "goto" { setTokLength (4); RETURN_TOK (GOTO); }
234 "if" { setTokLength (2); RETURN_TOK (CIF); }
235 "return" { setTokLength (6); RETURN_TOK (RETURN); }
236 "sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); }
237 "offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); }
238 "switch" { setTokLength (6); RETURN_TOK (SWITCH); }
239 "while" { setTokLength (5); RETURN_TOK (WHILE); }
240 "va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); }
241 "va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); }
243 /* gcc extension...this might not be appropriate */
244 setTokLength (6); RETURN_TOK (QINLINE); }
246 "struct" { setTokLength (6); RETURN_TOK (CSTRUCT); }
247 "typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); }
249 "union" { setTokLength (5); RETURN_TOK (CUNION); }
250 "enum" { setTokLength (4); RETURN_TOK (CENUM); }
252 "void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); }
253 "int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); }
254 "double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); }
255 "char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); }
256 "float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); }
258 "long" { setTokLength (4); RETURN_TOK (QLONG); }
259 "short" { setTokLength (5); RETURN_TOK (QSHORT); }
260 "unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); }
261 "signed" { setTokLength (6); RETURN_TOK (QSIGNED); }
263 "volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); }
264 "const" { setTokLength (5); RETURN_TOK (QCONST); }
266 /* some systems expect this! [gack!] */
267 "__const" { setTokLength (7); RETURN_TOK (QCONST); }
269 "extern" { setTokLength (6); RETURN_TOK (QEXTERN); }
270 "auto" { setTokLength (4); RETURN_TOK (QAUTO); }
271 "register" { setTokLength (8); RETURN_TOK (QREGISTER); }
272 "static" { setTokLength (6); RETURN_TOK (QSTATIC); }
274 \"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
275 L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
276 "out" { return (processSpec (QOUT)); }
277 "in" { return (processSpec (QIN)); }
278 "partial" { return (processSpec (QPARTIAL)); }
279 "special" { return (processSpec (QSPECIAL)); }
280 "anytype" { return (processSpec (QANYTYPE)); }
281 "integraltype" { return (processSpec (QINTEGRALTYPE)); }
282 "unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); }
283 "signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); }
284 "keep" { return (processSpec (QKEEP)); }
285 "null" { return (processSpec (QNULL)); }
286 "notnull" { return (processSpec (QNOTNULL)); }
287 "isnull" { return (processSpec (QISNULL)); }
288 "truenull" { return (processSpec (QTRUENULL)); }
289 "falsenull" { return (processSpec (QFALSENULL)); }
290 "relnull" { return (processSpec (QRELNULL)); }
291 "reldef" { return (processSpec (QRELDEF)); }
292 "exposed" { return (processSpec (QEXPOSED)); }
293 "newref" { return (processSpec (QNEWREF)); }
294 "tempref" { return (processSpec (QTEMPREF)); }
295 "killref" { return (processSpec (QKILLREF)); }
296 "refcounted" { return (processSpec (QREFCOUNTED)); }
297 "checked" { return (processSpec (QCHECKED)); }
298 "checkmod" { return (processSpec (QCHECKMOD)); }
299 "checkedstrict" { return (processSpec (QCHECKEDSTRICT)); }
300 "unchecked" { return (processSpec (QUNCHECKED)); }
301 "only" { return (processSpec (QONLY)); }
302 "owned" { return (processSpec (QOWNED)); }
303 "observer" { return (processSpec (QOBSERVER)); }
304 "dependent" { return (processSpec (QDEPENDENT)); }
305 "unused" { return (processSpec (QUNUSED)); }
306 "external" { return (processSpec (QEXTERNAL)); }
307 "sef" { return (processSpec (QSEF)); }
308 "shared" { return (processSpec (QSHARED)); }
309 "yield" { return (processSpec (QYIELD)); }
310 "undef" { return (processSpec (QUNDEF)); }
311 "killed" { return (processSpec (QKILLED)); }
312 "nullterminated" { return (processSpec (QNULLTERMINATED));}
313 "MaxSet" { return (processSpec (QMAXSET));}
314 "MaxRead" { return (processSpec (QMAXREAD));}
315 "maxSet" { return (processSpec (QMAXSET));}
316 "maxRead" { return (processSpec (QMAXREAD));}
318 {Letter}({Letter}|{Digit})* { int tok;
319 context_saveLocation ();
320 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
321 tok = processIdentifier (makeIdentifier (yytext));
327 0[xX]{H}+ { setTokLengthT (mstring_length (yytext));
328 RETURN_INT (ctype_int, processHex ()); /* evs 2000-05-17 was ctype_uint */
330 0[xX]{H}+{L} { setTokLengthT (mstring_length (yytext));
331 RETURN_INT (ctype_lint, processHex ()); }
332 0[xX]{H}+{L}{L} { setTokLengthT (mstring_length (yytext));
333 RETURN_INT (ctype_llint, processHex ()); }
334 0[xX]{H}+{U} { setTokLengthT (mstring_length (yytext));
335 RETURN_INT (ctype_uint, processHex ()); }
336 0[xX]{H}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
337 RETURN_INT (ctype_ulint, processHex ()); }
338 0[xX]{H}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
339 RETURN_INT (ctype_ullint, processHex ()); }
340 0[xX]{H}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
341 RETURN_INT (ctype_ullint, processHex ()); }
342 0{Digit}+ { setTokLengthT (mstring_length (yytext));
343 RETURN_INT (ctype_int, processOctal ()); }
344 0{Digit}+{U} { setTokLengthT (mstring_length (yytext));
345 RETURN_INT (ctype_uint, processOctal ()); }
346 0{Digit}+{L} { setTokLengthT (mstring_length (yytext));
347 RETURN_INT (ctype_lint, processOctal ()); }
348 0{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
349 RETURN_INT (ctype_llint, processOctal ()); }
350 0{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
351 RETURN_INT (ctype_ulint, processOctal ()); }
352 0{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
353 RETURN_INT (ctype_ullint, processOctal ()); }
354 0{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
355 RETURN_INT (ctype_ullint, processOctal ()); }
356 {Digit}+ { setTokLengthT (mstring_length (yytext));
357 RETURN_INT (ctype_int, processDec ()); }
358 {Digit}+{U} { setTokLengthT (mstring_length (yytext));
359 RETURN_INT (ctype_uint, processDec ()); }
360 {Digit}+{L} { setTokLengthT (mstring_length (yytext));
361 RETURN_INT (ctype_lint, processDec ()); }
362 {Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
363 RETURN_INT (ctype_llint, processDec ()); }
364 {Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
365 RETURN_INT (ctype_ulint, processDec ()); }
366 {Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
367 RETURN_INT (ctype_ullint, processDec ()); }
368 {Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
369 RETURN_INT (ctype_ullint, processDec ()); }
370 '(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
371 RETURN_CHAR (processChar ()); }
372 L'(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
373 RETURN_CHAR (processChar ()); }
374 {Digit}+{E}[fF] { setTokLengthT (mstring_length (yytext));
375 RETURN_FLOAT (ctype_float, processFloat ()); }
376 {Digit}+{E}[lL] { setTokLengthT (mstring_length (yytext));
377 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
378 {Digit}+{E} { setTokLengthT (mstring_length (yytext));
379 RETURN_FLOAT (ctype_double, processFloat ()); }
381 {Digit}*"."{Digit}+({E})?[fF] { setTokLengthT (mstring_length (yytext));
382 RETURN_FLOAT (ctype_float, processFloat ()); }
383 {Digit}*"."{Digit}+({E})?[lL] { setTokLengthT (mstring_length (yytext));
384 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
385 {Digit}*"."{Digit}+({E})? { setTokLengthT (mstring_length (yytext));
386 RETURN_FLOAT (ctype_double, processFloat ()); }
388 {Digit}+"."{Digit}*({E})?[fF] { setTokLengthT (mstring_length (yytext));
389 RETURN_FLOAT (ctype_float, processFloat ()); }
390 {Digit}+"."{Digit}*({E})?[lL] { setTokLengthT (mstring_length (yytext));
391 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
392 {Digit}+"."{Digit}*({E})? { setTokLengthT (mstring_length (yytext));
393 RETURN_FLOAT (ctype_double, processFloat ()); }
395 ">>=" { setTokLength (3); RETURN_TOK (RIGHT_ASSIGN); }
396 "<<=" { setTokLength (3); RETURN_TOK (LEFT_ASSIGN); }
397 "+=" { setTokLength (2); RETURN_TOK (ADD_ASSIGN); }
398 "-=" { setTokLength (2); RETURN_TOK (SUB_ASSIGN); }
399 "*=" { setTokLength (2); RETURN_TOK (MUL_ASSIGN); }
400 "/=" { setTokLength (2); RETURN_TOK (DIV_ASSIGN); }
401 "%=" { setTokLength (2); RETURN_TOK (MOD_ASSIGN); }
402 "&=" { setTokLength (2); RETURN_TOK (AND_ASSIGN); }
403 "^=" { setTokLength (2); RETURN_TOK (XOR_ASSIGN); }
404 "|=" { setTokLength (2); RETURN_TOK (OR_ASSIGN); }
405 ">>" { setTokLength (2); RETURN_TOK (RIGHT_OP); }
406 "<<" { setTokLength (2); RETURN_TOK (LEFT_OP); }
407 "++" { setTokLength (2); RETURN_TOK (INC_OP); }
408 "--" { setTokLength (2); RETURN_TOK (DEC_OP); }
409 "->" { setTokLength (2); RETURN_TOK (ARROW_OP); }
410 "&&" { setTokLength (2); RETURN_TOK (AND_OP); }
411 "||" { setTokLength (2); RETURN_TOK (OR_OP); }
412 "<=" { setTokLength (2); RETURN_TOK (LE_OP); }
413 ">=" { setTokLength (2); RETURN_TOK (GE_OP); }
414 "==" { setTokLength (2); RETURN_TOK (EQ_OP); }
415 "!=" { setTokLength (2); RETURN_TOK (NE_OP); }
416 ";" { setTokLength (1); RETURN_TOK (TSEMI); }
417 "{" { setTokLength (1); RETURN_TOK (TLBRACE); }
418 "}" { setTokLength (1); RETURN_TOK (TRBRACE); }
419 "," { setTokLength (1); RETURN_TOK (TCOMMA); }
420 ":" { setTokLength (1); RETURN_TOK (TCOLON); }
421 "=" { setTokLength (1); RETURN_TOK (TASSIGN); }
422 "(" { setTokLength (1); RETURN_TOK (TLPAREN); }
423 ")" { setTokLength (1); RETURN_TOK (TRPAREN); }
424 "[" { setTokLength (1); RETURN_TOK (TLSQBR); }
425 "]" { setTokLength (1); RETURN_TOK (TRSQBR); }
426 "." { setTokLength (1); RETURN_TOK (TDOT); }
427 "&" { setTokLength (1); RETURN_TOK (TAMPERSAND); }
428 "!" { setTokLength (1); RETURN_TOK (TEXCL); }
431 "~" { setTokLength (1); RETURN_TOK (TTILDE); }
432 "-" { setTokLength (1); RETURN_TOK (TMINUS); }
433 "+" { setTokLength (1); RETURN_TOK (TPLUS); }
434 "*" { setTokLength (1); RETURN_TOK (TMULT); }
435 "/" { setTokLength (1); RETURN_TOK (TDIV); }
436 "%" { setTokLength (1); RETURN_TOK (TPERCENT); }
437 "<" { setTokLength (1); RETURN_TOK (TLT); }
438 ">" { setTokLength (1); RETURN_TOK (TGT); }
439 "^" { setTokLength (1); RETURN_TOK (TCIRC); }
440 "|" { setTokLength (1); RETURN_TOK (TBAR); }
441 "?" { setTokLength (1); RETURN_TOK (TQUEST); }
444 "/\\" { setTokLength (1); RETURN_TOK (TCAND); }
447 [ \t\v\f] { incColumn (); }
448 \n { context_incLineno ();
449 if (tokLength != 0) {
451 /* No error to report
454 message ("Likely parse error: token spans multiple lines."),
461 continueLine = FALSE;
465 if (context_inMacro ())
467 /* Don't use RETURN_TOK */
468 yylval.tok = lltok_create (TENDMACRO, g_currentloc);
469 lastWasString = FALSE;
474 "@@MR@@" { setTokLength (6);
476 if (processMacro ()) {
477 if (context_inIterDef ())
479 RETURN_TOK (LLMACROITER);
481 if (context_inIterEnd ())
483 RETURN_TOK (LLMACROEND);
485 if (context_inMacro ())
487 RETURN_TOK (LLMACRO);
491 "@QLMR" { if (context_inHeader () || context_inFunction ())
497 int nspchar = ninput ();
501 ** This is a hack to get the column number correct.
504 llassert (nspchar >= '0' && nspchar <= '9');
506 nspaces = nspchar - '0';
508 setTokLength (5 + nspaces);
512 DPRINTF (("Here we are: %s", context_unparse ()));
514 if (context_inIterDef ())
516 RETURN_TOK (LLMACROITER);
518 if (context_inIterEnd ())
520 RETURN_TOK (LLMACROEND);
522 if (context_inMacro ())
524 RETURN_TOK (LLMACRO);
529 "@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); }
530 "@.FA" { setTokLength (4); lldiagmsg (message ("Access types: %q", typeIdSet_unparse (context_fileAccessTypes ()))); }
531 "@.F" { setTokLength (3);
532 lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc)));
534 "@.L" { setTokLength (3); usymtab_printLocal (); }
535 "@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); }
536 "@.C" { setTokLength (3); lldiagmsg (context_unparse ()); }
537 "@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); }
538 "@.G" { setTokLength (3); usymtab_printGuards (); }
539 "@.S" { setTokLength (3); usymtab_printOut (); }
540 "@.X" { setTokLength (3); usymtab_printAll (); }
541 "@.Z" { setTokLength (3); usymtab_printComplete (); }
542 "@.T" { setTokLength (3); usymtab_printTypes (); }
543 "@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); }
544 "@.M" { setTokLength (3);
545 lldiagmsg (message ("Can modify: %q",
546 sRefSet_unparse (context_modList ())));
548 "%{" { /* BEFORE_COMMENT_MARKER */
550 incColumn (); incColumn ();
551 tok = handleLlSpecial ();
555 if (tok == CANNOTATION) {
558 /* Beware - this bashes yylval! */
563 "%}" { /* AFTER_COMMENT_MARKER */
566 RETURN_TOK (QENDMACRO); }
567 "\\" { incColumn (); continueLine = TRUE; }
569 if ((int) *yytext == 13 ) {
574 message ("Invalid character (ascii: %d), skipping character",
583 /*@null@*/ /*@observer@*/ char *name;
588 ** These tokens are followed by syntax that is parsed by the
592 struct skeyword s_parsetable[] = {
593 { "modifies", QMODIFIES } ,
594 { "globals", QGLOBALS } ,
597 { "constant", QCONSTANT } ,
598 { "function", QFUNCTION } ,
600 { "defines", QDEFINES } ,
602 { "allocates", QALLOCATES } ,
604 { "releases", QRELEASES } ,
605 { "pre", QPRECLAUSE } ,
606 { "post", QPOSTCLAUSE } ,
607 { "setBufferSize", QSETBUFFERSIZE},
608 { "setStringLength", QSETSTRINGLENGTH},
609 { "testinRange", QTESTINRANGE},
610 { "requires", QPRECLAUSE } ,
611 { "ensures", QPOSTCLAUSE } ,
616 ** These tokens are either stand-alone tokens, or followed by
617 ** token-specific text.
620 struct skeyword s_keytable[] = {
621 { "anytype", QANYTYPE } ,
622 { "integraltype", QINTEGRALTYPE } ,
623 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,
624 { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,
628 { "owned", QOWNED } ,
629 { "dependent", QDEPENDENT } ,
630 { "partial", QPARTIAL } ,
631 { "special", QSPECIAL } ,
632 { "truenull", QTRUENULL } ,
633 { "falsenull", QFALSENULL } ,
636 { "notnull", QNOTNULL } ,
637 { "abstract", QABSTRACT } ,
638 { "concrete", QCONCRETE } ,
639 { "mutable", QMUTABLE } ,
640 { "immutable", QIMMUTABLE } ,
641 { "unused", QUNUSED } ,
642 { "external", QEXTERNAL } ,
644 { "unique", QUNIQUE } ,
645 { "returned", QRETURNED } ,
646 { "exposed", QEXPOSED } ,
647 { "refcounted", QREFCOUNTED } ,
649 { "newref", QNEWREF } ,
650 { "tempref", QTEMPREF } ,
651 { "killref", QKILLREF } ,
653 { "relnull", QRELNULL } ,
654 { "nullterminated", QNULLTERMINATED },
655 { "setBufferSize", QSETBUFFERSIZE },
656 { "testInRange", QTESTINRANGE},
657 { "MaxSet", QMAXSET},
658 { "MaxRead", QMAXREAD},
659 { "reldef", QRELDEF } ,
660 { "observer", QOBSERVER } ,
661 { "exits", QEXITS } ,
662 { "mayexit", QMAYEXIT } ,
663 { "trueexit", QTRUEEXIT } ,
664 { "falseexit", QFALSEEXIT } ,
665 { "neverexit", QNEVEREXIT } ,
667 { "shared", QSHARED } ,
669 { "unchecked", QUNCHECKED } ,
670 { "checked", QCHECKED } ,
671 { "checkmod", QCHECKMOD } ,
672 { "checkedstrict", QCHECKEDSTRICT } ,
673 { "innercontinue", QINNERCONTINUE } ,
674 { "innerbreak", QINNERBREAK } ,
675 { "loopbreak", QLOOPBREAK } ,
676 { "switchbreak", QSWITCHBREAK } ,
677 { "safebreak", QSAFEBREAK } ,
678 { "fallthrough", QFALLTHROUGH } ,
679 { "l_fallthrou", QLINTFALLTHROUGH } ,
680 { "l_fallth", QLINTFALLTHRU } ,
681 { "notreached", QNOTREACHED } ,
682 { "l_notreach", QLINTNOTREACHED } ,
683 { "printflike", QPRINTFLIKE } ,
684 { "l_printfli", QLINTPRINTFLIKE } ,
685 { "scanflike", QSCANFLIKE } ,
686 { "messagelike", QMESSAGELIKE } ,
687 { "l_argsus", QARGSUSED } ,
692 ** would be better if these weren't hard coded...
695 static bool isArtificial (cstring s)
697 return (cstring_equalLit (s, "modifies")
698 || cstring_equalLit (s, "globals")
699 || cstring_equalLit (s, "warn")
700 || cstring_equalLit (s, "alt"));
703 void swallowMacro (void)
706 bool skipnext = FALSE;
708 while ((i = lminput ()) != EOF)
725 reader_checkUngetc (i, yyin);
733 reader_checkUngetc (i, yyin);
737 static int commentMarkerToken (cstring s)
741 while (s_parsetable[i].name != NULL)
743 DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name));
745 if (cstring_equalLit (s, s_parsetable[i].name))
747 return s_parsetable[i].token;
756 static int tokenMacroCode (cstring s)
760 while (s_keytable[i].name != NULL)
762 if (cstring_equalLit (s, s_keytable[i].name))
764 if (s_keytable[i].token == QLINTFALLTHROUGH)
767 (FLG_WARNLINTCOMMENTS,
769 ("Traditional lint comment /*FALLTHROUGH*/ used. "
770 "This is interpreted by "
771 "LCLint in the same way as most Unix lints, but it is "
772 "preferable to replace it with the /*@fallthrough@*/ "
777 else if (s_keytable[i].token == QLINTFALLTHRU)
780 (FLG_WARNLINTCOMMENTS,
782 ("Traditional lint comment /*FALLTHRU*/ used. "
783 "This is interpreted by "
784 "LCLint in the same way as most Unix lints, but it is "
785 "preferable to replace it with the /*@fallthrough@*/ "
790 else if (s_keytable[i].token == QLINTNOTREACHED)
793 (FLG_WARNLINTCOMMENTS,
795 ("Traditional lint comment /*NOTREACHED*/ used. "
796 "This is interpreted by "
797 "LCLint in the same way as most Unix lints, but it is "
798 "preferable to replace it with the /*@notreached@*/ "
799 "semantic comment."),
804 else if (s_keytable[i].token == QPRINTFLIKE)
806 setSpecialFunction (qual_createPrintfLike ());
809 else if (s_keytable[i].token == QLINTPRINTFLIKE)
812 (FLG_WARNLINTCOMMENTS,
814 ("Traditional lint comment /*PRINTFLIKE*/ used. "
815 "This is interpreted by "
816 "LCLint in the same way as most Unix lints, but it is "
817 "preferable to replace it with either /*@printflike@*/, "
818 "/*@scanflike@*/ or /*@messagelike@*/."),
821 setSpecialFunction (qual_createPrintfLike ());
824 else if (s_keytable[i].token == QSCANFLIKE)
826 setSpecialFunction (qual_createScanfLike ());
829 else if (s_keytable[i].token == QMESSAGELIKE)
831 setSpecialFunction (qual_createMessageLike ());
834 else if (s_keytable[i].token == QARGSUSED)
837 (FLG_WARNLINTCOMMENTS,
839 ("Traditional lint comment /*ARGSUSED*/ used. "
840 "This is interpreted by "
841 "LCLint in the same way as most Unix lints, but it is "
842 "preferable to use /*@unused@*/ annotations on "
843 "the unused parameters."),
850 return s_keytable[i].token;
859 static int lminput ()
861 if (savechar == '\0')
868 int save = (int) savechar;
874 static void lmsavechar (char c)
876 if (savechar == '\0') savechar = c;
879 llbuglit ("lmsavechar: override");
883 static int returnFloat (ctype ct, double f)
885 yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext),
886 fileloc_decColumn (g_currentloc, tokLength));
891 static int returnInt (ctype ct, long i)
895 if (ctype_equal (ct, ctype_int))
899 c = context_typeofZero ();
903 c = context_typeofOne ();
907 yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext),
908 fileloc_decColumn (g_currentloc, tokLength), i);
913 static int returnChar (char c)
915 yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext),
916 fileloc_decColumn (g_currentloc, tokLength));
925 if (c != EOF && ((char)c == '\n'))
927 context_incLineno ();
933 static char macro_nextChar ()
935 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
940 c = char_fromInt (ic);
942 if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
946 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
948 ; /* skip to newline */
951 context_incLineno ();
955 return macro_nextChar ();
962 else /* if (c == '@') */
964 llassert (FALSE); /*@i23@*/
965 if (handleLlSpecial () != BADTOK)
967 llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
970 return macro_nextChar ();
973 else if (!in_escape && c == '\"')
975 in_quote = !in_quote;
977 else if (!in_escape && c == '\'')
981 else if ((in_quote || in_char) && c == '\\')
983 in_escape = !in_escape;
985 else if ((in_quote || in_char) && in_escape)
989 else if (!in_quote && c == '/')
993 if ((c2 = char_fromInt (lminput ())) == '*')
997 while ((c2 = char_fromInt (lminput ())) != '\0'
998 && c2 != '\n' && c2 != '*')
1005 while ((c2 = char_fromInt (lminput ())) != '\0'
1018 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1022 return macro_nextChar ();
1026 /*** putchar does not work! why? puts to stdio...??! ***/
1034 ** keeps semantic comments
1037 static char macro_nextCharC ()
1039 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
1042 c = char_fromInt (lminput ());
1044 if (!in_quote && !in_char && c == '\\')
1046 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
1048 ; /* skip to newline */
1051 context_incLineno ();
1055 return macro_nextCharC ();
1062 else if (!in_escape && c == '\"')
1064 in_quote = !in_quote;
1066 else if (!in_escape && c == '\'')
1070 else if ((in_quote || in_char) && c == '\\')
1072 in_escape = !in_escape;
1074 else if ((in_quote || in_char) && in_escape)
1078 else if (!in_quote && c == '/')
1082 if ((c2 = char_fromInt (lminput ())) == '*')
1086 while ((c2 = char_fromInt (lminput ())) != '\0'
1087 && c2 != '\n' && c2 != '*')
1094 while ((c2 = char_fromInt (lminput ())) != '\0'
1107 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1111 return macro_nextCharC ();
1122 ** skips whitespace (handles line continuations)
1123 ** returns first non-whitespace character
1126 static char skip_whitespace ()
1130 while ((c = macro_nextChar ()) == ' ' || c == '\t')
1138 static void handleMacro ()
1140 cstring mac = cstring_undefined;
1144 while (currentColumn () > 2)
1146 mac = cstring_appendChar (mac, ' ');
1150 c = macro_nextCharC ();
1152 if (c >= '0' && c <= '9')
1156 for (i = 0; i < ((c - '0') + 1); i++)
1158 mac = cstring_appendChar (mac, ' ');
1166 while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
1168 mac = cstring_appendChar (mac, c);
1172 macrocode = tokenMacroCode (mac);
1174 if (macrocode == BADTOK && !isArtificial (mac))
1176 context_addMacroCache (mac);
1185 context_incLineno ();
1189 static bool processMacro (void)
1194 cstring fname = cstring_undefined;
1196 bool isspecfcn = FALSE;
1197 bool isiter = FALSE;
1198 bool skipparam = FALSE;
1199 bool isenditer = FALSE;
1200 bool unknownm = FALSE;
1201 bool hasParams = FALSE;
1202 bool emptyMacro = FALSE;
1203 char c = skip_whitespace ();
1204 fileloc loc = fileloc_noColumn (g_currentloc);
1206 /* are both of these necessary? what do they mean? */
1207 uentryList specparams = uentryList_undefined;
1208 uentryList pn = uentryList_undefined;
1210 context_resetMacroMissingParams ();
1212 if (c == '\0' || c == '\n')
1214 llcontbug (cstring_makeLiteral ("Bad macro"));
1219 fname = cstring_appendChar (fname, c);
1221 while ((c = macro_nextChar ()) != '(' && c != '\0'
1222 && c != ' ' && c != '\t' && c != '\n')
1224 fname = cstring_appendChar (fname, c);
1227 if (c == ' ' || c == '\t' || c == '\n')
1233 while (c == ' ' || c == '\t')
1235 c = macro_nextChar ();
1249 hasParams = (c == '(');
1251 if (usymtab_exists (fname))
1253 e2 = usymtab_lookupExpose (fname);
1254 ct = uentry_getType (e2);
1256 if (uentry_isCodeDefined (e2)
1257 && fileloc_isUser (uentry_whereDefined (e2)))
1261 message ("Macro %s already defined", fname),
1264 uentry_showWhereDefined (e2);
1265 uentry_clearDefined (e2);
1268 if (uentry_isFunction (e2))
1270 uentry_setType (e2, ctype_unknown);
1273 context_enterUnknownMacro (e2);
1277 context_enterConstantMacro (e2);
1282 if (uentry_isForward (e2) && uentry_isFunction (e2))
1289 ("Parameterized macro has no prototype or specification: %s ",
1294 uentry_setType (e2, ctype_unknown);
1295 uentry_setFunctionDefined (e2, loc);
1296 uentry_setUsed (e2, fileloc_undefined);
1297 context_enterUnknownMacro (e2);
1301 if (uentry_isIter (e2))
1304 specparams = uentry_getParams (e2);
1305 noparams = uentryList_size (specparams);
1306 uentry_setDefined (e2, loc);
1307 context_enterIterDef (e2);
1309 else if (uentry_isEndIter (e2))
1312 uentry_setDefined (e2, loc);
1313 context_enterIterEnd (e2); /* don't care about it now */
1314 /* but should parse like an iter! */
1316 else if (uentry_isConstant (e2))
1322 message ("Constant %s implemented as parameterized macro",
1326 uentry_showWhereSpecified (e2);
1327 uentry_setType (e2, ctype_unknown);
1328 uentry_makeConstantFunction (e2);
1329 uentry_setDefined (e2, g_currentloc);
1330 uentry_setFunctionDefined (e2, g_currentloc);
1331 context_enterUnknownMacro (e2);
1335 if (!uentry_isSpecified (e2))
1337 fileloc oloc = uentry_whereDeclared (e2);
1339 if (fileloc_isLib (oloc))
1343 else if (fileloc_isUndefined (oloc)
1344 || fileloc_isPreproc (oloc))
1349 (FLG_MACROCONSTDECL,
1351 ("Macro constant %q not declared",
1352 uentry_getName (e2)),
1356 else if (!fileloc_withinLines (oloc, loc, 2))
1357 { /* bogus! will give errors if there is too much whitespace */
1361 ("Macro constant name %s does not match name in "
1362 "previous constant declaration. This constant "
1363 "is declared at %q", fname,
1364 fileloc_unparse (oloc)),
1369 context_enterConstantMacro (e2);
1370 cstring_free (fname);
1376 else if (ctype_isFunction (ct))
1379 specparams = ctype_argsFunction (ct);
1380 noparams = uentryList_size (specparams);
1382 uentry_setFunctionDefined (e2, loc);
1383 context_enterMacro (e2);
1385 else if (uentry_isVar (e2))
1391 message ("Variable %s implemented as parameterized macro",
1395 uentry_showWhereSpecified (e2);
1396 uentry_setType (e2, ctype_unknown);
1397 uentry_makeVarFunction (e2);
1398 uentry_setDefined (e2, g_currentloc);
1399 uentry_setFunctionDefined (e2, g_currentloc);
1400 context_enterUnknownMacro (e2);
1404 uentry ucons = uentry_makeConstant (fname,
1407 if (uentry_isExpandedMacro (e2))
1415 message ("Variable %s implemented by a macro",
1419 uentry_showWhereSpecified (e2);
1423 uentry_setDefined (e2, loc);
1424 uentry_setUsed (ucons, loc);
1426 context_enterConstantMacro (ucons);
1427 uentry_markOwned (ucons);
1428 cstring_free (fname);
1434 if (uentry_isDatatype (e2))
1438 message ("Type implemented as macro: %x",
1439 uentry_getName (e2)),
1440 message ("A type is implemented using a macro definition. A "
1441 "typedef should be used instead."),
1445 /* Must exit scope (not sure why a new scope was entered?) */
1446 usymtab_quietExitScope (g_currentloc);
1447 uentry_setDefined (e2, g_currentloc);
1453 (message ("Unexpanded macro not function or constant: %q",
1454 uentry_unparse (e2)));
1455 uentry_setType (e2, ctype_unknown);
1459 uentry_makeVarFunction (e2);
1460 uentry_setDefined (e2, g_currentloc);
1461 uentry_setFunctionDefined (e2, g_currentloc);
1462 context_enterUnknownMacro (e2);
1473 /* evans 2001-09-09 - if it has params, assume a function */
1477 (FLG_MACROMATCHNAME,
1478 message ("Unexpanded macro %s does not match name of a declared "
1479 "function. The name used in the control "
1480 "comment on the previous line should match.",
1484 ce = uentry_makeFunction (fname, ctype_unknown,
1488 warnClause_undefined,
1490 uentry_setUsed (ce, loc); /* perhaps bogus? */
1491 e2 = usymtab_supEntryReturn (ce);
1492 context_enterUnknownMacro (e2);
1497 (FLG_MACROMATCHNAME,
1498 message ("Unexpanded macro %s does not match name of a constant "
1499 "or iter declaration. The name used in the control "
1500 "comment on the previous line should match. "
1501 "(Assuming macro defines a constant.)",
1505 ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
1506 uentry_setUsed (ce, loc); /* perhaps bogus? */
1507 e2 = usymtab_supEntryReturn (ce);
1509 context_enterConstantMacro (e2);
1510 cstring_free (fname);
1516 /* in macros, ( must follow immediatetly after name */
1522 c = skip_whitespace ();
1524 while (c != ')' && c != '\0')
1527 bool suppress = context_inSuppressRegion ();
1528 cstring paramname = cstring_undefined;
1531 ** save the parameter location
1535 context_saveLocation ();
1538 while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
1540 paramname = cstring_appendChar (paramname, c);
1541 c = macro_nextChar ();
1544 if (c == ' ' || c == '\t') c = skip_whitespace ();
1548 c = macro_nextChar ();
1549 if (c == ' ' || c == '\t') c = skip_whitespace ();
1554 llfatalerror (cstring_makeLiteral
1555 ("Bad macro syntax: uentryList"));
1558 if ((isspecfcn || isiter) && (paramno < noparams)
1559 && !uentry_isElipsisMarker (uentryList_getN
1560 (specparams, paramno)))
1562 fileloc sloc = context_getSaveLocation ();
1563 uentry decl = uentryList_getN (specparams, paramno);
1566 param = uentry_nameCopy (paramname, decl);
1568 uentry_setParam (param);
1569 sr = sRef_makeParam (paramno, uentry_getType (param), stateInfo_makeLoc (sloc));
1571 if (sRef_getNullState (sr) == NS_ABSNULL)
1573 ctype pt = ctype_realType (uentry_getType (param));
1575 if (ctype_isUser (pt))
1577 uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
1579 if (uentry_isValid (te))
1581 sRef_setStateFromUentry (sr, te);
1586 sRef_setNullState (sr, NS_UNKNOWN, sloc);
1590 uentry_setSref (param, sr);
1591 uentry_setDeclaredForceOnly (param, sloc);
1593 skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
1597 fileloc sloc = context_getSaveLocation ();
1599 param = uentry_makeVariableSrefParam
1600 (paramname, ctype_unknown, fileloc_copy (sloc),
1601 sRef_makeParam (paramno, ctype_unknown, stateInfo_makeLoc (sloc)));
1602 DPRINTF (("Unknown param: %s", uentry_unparseFull (param)));
1603 cstring_free (paramname);
1605 sRef_setPosNull (uentry_getSref (param), sloc);
1606 uentry_setDeclaredForce (param, sloc);
1609 fileloc_free (sloc);
1614 llassert (!uentry_isElipsisMarker (param));
1618 sRef_makeUnsafe (uentry_getSref (param));
1621 pn = uentryList_add (pn, uentry_copy (param));
1622 usymtab_supEntry (param);
1626 /* don't add param */
1627 uentry_free (param);
1632 (void) macro_nextChar ();
1633 c = skip_whitespace ();
1641 if (isspecfcn || isiter)
1643 if (paramno != noparams && noparams >= 0)
1649 message ("Macro %s specified with %d args, defined with %d",
1650 fname, noparams, paramno),
1653 uentry_showWhereSpecified (e2);
1654 uentry_resetParams (e2, pn);
1659 uentry_resetParams (e2, pn);
1666 ** the form should be:
1668 ** # define newname oldname
1669 ** where oldname refers to a function matching the specification
1675 sRef_setGlobalScope ();
1676 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
1677 sRef_clearGlobalScope ();
1681 context_setMacroMissingParams ();
1686 /* context_setuentryList (pn); */
1687 usymtab_enterScope ();
1690 cstring_free (fname);
1695 static bool handleSpecial (char *yyt)
1697 char *l = mstring_create (MAX_NAME_LENGTH);
1703 strcpy (l, yyt + 1);
1705 /* Need to safe original l for deallocating. */
1708 l += strlen (yyt) - 1;
1710 while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
1716 olc = cstring_fromChars (ol);
1718 if (cstring_equalPrefixLit (olc, "pragma"))
1720 char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN));
1721 char *opname = pname;
1722 char *ptr = ol + 6; /* pragma is six characters, plus space */
1726 /* skip whitespace */
1727 while (((c = *ptr) != '\0') && isspace (c))
1733 while (((c = *ptr) != '\0') && !isspace (c))
1737 if (len > MAX_PRAGMA_LEN)
1748 if (len == PRAGMA_LEN_EXPAND
1749 && mstring_equal (opname, PRAGMA_EXPAND))
1751 cstring exname = cstring_undefined;
1755 while (((c = *ptr) != '\0') && !isspace (c))
1757 exname = cstring_appendChar (exname, c);
1762 ue = usymtab_lookupExposeGlob (exname);
1764 if (uentry_isExpandedMacro (ue))
1766 if (fileloc_isPreproc (uentry_whereDefined (ue)))
1768 fileloc_setColumn (g_currentloc, 1);
1769 uentry_setDefined (ue, g_currentloc);
1773 cstring_free (exname);
1776 else if (cstring_equalPrefixLit (olc, "ident"))
1778 /* Some pre-processors will leave these in the code. Ignore rest of line */
1781 ** Yuk...Win32 filenames can have spaces in them...we need to read
1782 ** to the matching end quote.
1784 else if ((sscanf (ol, "line %d \"", &lineno) == 1)
1785 || (sscanf (ol, " %d \"", &lineno) == 1))
1791 /*@access cstring@*/
1792 while (*tmp != '\"' && *tmp != '\0')
1797 llassert (*tmp == '\"');
1803 while (*tmp != '\"' && *tmp != '\0')
1808 llassert (*tmp == '\"');
1812 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
1815 ** DOS-like path delimiters get delivered in pairs, something like
1816 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
1817 ** remove the pre dirs yet as we usually specify tmp paths relative
1818 ** to the current directory, so tmp files would not get found in
1819 ** the hash table. If this method fails we try it again later.
1826 ** Skip past the drive marker.
1829 if (strchr (stmp, ':') != NULL)
1831 stmp = strchr (stmp, ':') + 1;
1834 while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
1836 if (*(stmp+1) == CONNECTCHAR)
1838 memmove (stmp, stmp+1, strlen (stmp));
1844 fid = fileTable_lookupBase (context_fileTable (), fname);
1845 if (!(fileId_isValid (fid)))
1847 fname = removePreDirs (fname);
1848 fid = fileTable_lookupBase (context_fileTable (), fname);
1851 # else /* !defined(OS2) && !defined(MSDOS) */
1852 fname = removePreDirs (fname);
1853 fid = fileTable_lookupBase (context_fileTable (), fname);
1854 # endif /* !defined(OS2) && !defined(MSDOS) */
1856 if (!(fileId_isValid (fid)))
1858 if (context_inXHFile ())
1860 fid = fileTable_addXHFile (context_fileTable (), fname);
1862 else if (isHeaderFile (fname))
1864 fid = fileTable_addHeaderFile (context_fileTable (), fname);
1868 fid = fileTable_addFile (context_fileTable (), fname);
1872 setFileLine (fid, lineno);
1873 /*@noaccess cstring@*/
1875 else if ((sscanf (ol, "line %d", &lineno) == 1)
1876 || (sscanf (ol, " %d", &lineno) == 1))
1878 setLine (lineno); /* next line is <cr> */
1882 if (mstring_equal (ol, "")) {
1883 DPRINTF (("Empty pp command!"));
1885 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
1886 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
1892 (FLG_UNRECOGDIRECTIVE,
1893 message ("Unrecognized pre-processor directive: #%s",
1894 cstring_fromChars (ol)),
1899 return FALSE; /* evans 2001-12-30: was: TRUE; */
1906 static int handleLlSpecial ()
1911 char *s = mstring_createEmpty ();
1917 loc = fileloc_copy (g_currentloc);
1918 DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
1920 while (((ic = ninput ()) != 0) && isalpha (ic))
1923 s = mstring_append (s, c);
1927 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
1930 if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
1934 llassert (ic == AFTER_COMMENT_MARKER[1]);
1940 return QNOMODS; /* special token no modifications token */
1944 DPRINTF (("Coment marker: %s", os));
1945 tok = commentMarkerToken (cstring_fromChars (os));
1949 tokLength = charsread;
1956 DPRINTF (("Not a comment marker..."));
1957 /* Add rest of the comment */
1959 if (ic != 0 && ic != EOF)
1963 s = mstring_append (s, c);
1966 while (((ic = ninput ()) != 0) && (ic != EOF)
1967 && (ic != AFTER_COMMENT_MARKER[0]))
1971 /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
1974 hasnl = TRUE; /* This prevents tokLength from being set later. */
1979 message ("Likely parse error: syntactic comment token spans multiple lines: %s",
1980 cstring_fromChars (s)),
1984 s = mstring_append (s, c);
1989 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
1991 if (ic == AFTER_COMMENT_MARKER[0])
1994 llassert ((char) nc == AFTER_COMMENT_MARKER[1]);
2000 while (*s == ' ' || *s == '\t' || *s == '\n')
2005 if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
2009 while (c == '-' || c == '+' || c == '=')
2011 ynm set = ynm_fromCodeChar (c);
2016 thisflag = cstring_fromChars (s);
2018 while ((c = *s) != '\0' && (c != '-') && (c != '=')
2019 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
2026 if (!context_getFlag (FLG_NOCOMMENTS))
2028 cstring flagname = thisflag;
2029 flagcode fflag = identifyFlag (flagname);
2031 if (flagcode_isSkip (fflag))
2035 else if (flagcode_isInvalid (fflag))
2037 if (isMode (flagname))
2039 if (ynm_isMaybe (set))
2044 ("Semantic comment attempts to restore flag %s. "
2045 "A mode flag cannot be restored.",
2050 context_setMode (flagname);
2056 (FLG_UNRECOGFLAGCOMMENTS,
2057 message ("Unrecognized option in semantic comment: %s",
2062 else if (flagcode_isGlobalFlag (fflag))
2067 ("Semantic comment attempts to set global flag %s. "
2068 "A global flag cannot be set locally.",
2074 context_fileSetFlag (fflag, set);
2076 if (flagcode_hasArgument (fflag))
2078 if (ynm_isMaybe (set))
2083 ("Semantic comment attempts to restore flag %s. "
2084 "A flag for setting a value cannot be restored.",
2089 { /* cut-and-pastied from llmain...blecch */
2090 cstring extra = cstring_undefined;
2096 rest = mstring_copy (s);
2100 while ((rchar = *rest) != '\0'
2101 && (isspace (rchar)))
2107 while ((rchar = *rest) != '\0'
2108 && !isspace (rchar))
2110 extra = cstring_appendChar (extra, rchar);
2117 if (cstring_isUndefined (extra))
2122 ("Flag %s (in semantic comment) must be followed by an argument",
2123 flagcode_unparse (fflag)));
2129 if (flagcode_hasValue (fflag))
2131 setValueFlag (fflag, extra);
2133 else if (flagcode_hasString (fflag))
2135 setStringFlag (fflag, extra);
2152 while ((c == ' ') || (c == '\t') || (c == '\n'))
2158 if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
2160 DPRINTF (("Here adding comment: %s", os));
2161 context_addComment (cstring_fromCharsNew (os));
2173 annotationInfo ainfo;
2175 while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
2187 t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
2188 macrocode = tokenMacroCode (cstring_fromChars (t));
2190 if (macrocode != BADTOK)
2192 tokLength = hasnl ? 0 : mstring_length (t);
2198 if (macrocode == SKIPTOK)
2206 ainfo = context_lookupAnnotation (cstring_fromChars (os));
2208 if (annotationInfo_isDefined (ainfo)) {
2209 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
2210 /*@i324@*/ yylval.annotation = ainfo;
2218 if (context_inHeader ())
2225 if ((context_inMacro () || context_inGlobalContext ())
2226 && macrocode != SKIPTOK
2227 && !isArtificial (cstring_fromChars (os)))
2229 DPRINTF (("Add comment: %s", os));
2230 context_addComment (cstring_fromCharsNew (os));
2243 if (mstring_equal (t, "ignore"))
2245 if (!context_getFlag (FLG_NOCOMMENTS))
2247 context_enterSuppressRegion ();
2250 else if ((*t == 'i' || *t == 't')
2251 && (*(t + 1) == '\0'))
2253 if (!context_getFlag (FLG_NOCOMMENTS)
2254 && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
2256 context_enterSuppressLine (-1); /* infinite suppression */
2259 else if (((*t == 'i') || (*t == 't'))
2260 && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
2262 bool tmpcomment = (*t == 't');
2264 char *tt = t; /* don't mangle t, since it is free'd */
2267 if (lc >= '0' && lc <= '9')
2269 val = (int)(lc - '0');
2272 while (lc >= '0' && lc <= '9')
2281 if (!context_getFlag (FLG_NOCOMMENTS)
2282 && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
2284 context_enterSuppressLine (val);
2287 else if (mstring_equal (t, "end"))
2289 if (!context_getFlag (FLG_NOCOMMENTS))
2291 context_exitSuppressRegion ();
2294 else if (mstring_equal (t, "notfunction"))
2296 ; /* handled by pcpp */
2298 else if (mstring_equal (t, "access"))
2304 while ((c = *s) && (c == ' ' || c == '\t' || c == '\n'))
2314 tname = cstring_fromChars (s);
2316 while ((c = *s) != '\0' && c != ' '
2317 && c != '\t' && c != '\n' && c != ',')
2324 DPRINTF (("Access %s", tname));
2326 if (!context_getFlag (FLG_NOCOMMENTS)
2327 && !context_getFlag (FLG_NOACCESS))
2329 if (usymtab_existsType (tname))
2331 typeId uid = usymtab_getTypeId (tname);
2332 uentry ue = usymtab_getTypeEntry (uid);
2334 if (uentry_isAbstractDatatype (ue))
2336 context_addFileAccessType (uid);
2337 DPRINTF (("Adding access to: %s / %d", tname, uid));
2344 ("Non-abstract type %s used in access comment",
2351 if (!(context_inSuppressRegion ()
2352 || context_inSuppressZone (g_currentloc)))
2357 ("Unrecognized type %s used in access comment",
2369 if (c != ',' && c != ' ')
2375 else if (mstring_equal (t, "noaccess"))
2382 while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n'))
2392 tname = cstring_fromChars (s);
2394 while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
2395 && lc != '\n' && lc != ',')
2402 if (!context_getFlag (FLG_NOCOMMENTS)
2403 && !context_getFlag (FLG_NOACCESS))
2405 if (usymtab_existsType (tname))
2407 typeId tuid = usymtab_getTypeId (tname);
2409 if (context_couldHaveAccess (tuid))
2411 DPRINTF (("Removing access: %s", tname));
2412 context_removeFileAccessType (tuid);
2416 if (!(context_inSuppressRegion ()
2417 || context_inSuppressZone (g_currentloc)))
2419 uentry ue = usymtab_getTypeEntry (tuid);
2421 if (uentry_isAbstractDatatype (ue))
2426 ("Non-accessible abstract type %s used in noaccess comment",
2435 ("Non-abstract type %s used in noaccess comment",
2444 if (!(context_inSuppressRegion ()
2445 || context_inSuppressZone (g_currentloc)))
2450 ("Unrecognized type %s used in noaccess comment",
2462 if (lc != ',' && lc != ' ')
2470 voptgenerror (FLG_UNRECOGCOMMENTS,
2471 message ("Semantic comment unrecognized: %s",
2472 cstring_fromChars (os)), loc);
2483 static /*@only@*/ cstring makeIdentifier (char *s)
2485 char *c = mstring_create (size_toInt (strlen (s)) + 1);
2486 cstring id = cstring_fromChars (c);
2488 while (isalnum (*s) || (*s == '_') || (*s == '$'))
2497 /*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn)
2499 if (!(usymtab_exists (cn)))
2501 fileloc loc = fileloc_createExternal ();
2504 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
2507 uentry ce = uentry_makeUnrecognized (cn, loc);
2509 if (!context_inIterEnd ())
2513 message ("Unrecognized (possibly system) identifier: %q",
2514 uentry_getName (ce)),
2521 return (usymtab_lookup (cn));
2525 ** like, coerceId, but doesn't supercede for iters
2528 /*@observer@*/ uentry coerceIterId (cstring cn)
2530 if (!(usymtab_exists (cn)))
2532 return uentry_undefined;
2535 return (usymtab_lookup (cn));
2538 /*@observer@*/ cstring LastIdentifier ()
2540 return (lastidprocessed);
2543 static int processIdentifier (cstring id)
2547 if (context_getFlag (FLG_GRAMMAR))
2549 lldiagmsg (message ("Process identifier: %s", id));
2552 context_clearJustPopped ();
2553 lastidprocessed = id;
2555 if (context_inFunctionHeader ())
2557 int tok = commentMarkerToken (id);
2558 DPRINTF (("in function decl..."));
2566 tok = tokenMacroCode (id);
2574 annotationInfo ainfo;
2576 if (expectingMetaStateName)
2578 metaStateInfo msinfo = context_lookupMetaStateInfo (id);
2580 if (metaStateInfo_isDefined (msinfo))
2582 yylval.msinfo = msinfo;
2583 return METASTATE_NAME;
2587 DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id)));
2591 ainfo = context_lookupAnnotation (id);
2593 if (annotationInfo_isDefined (ainfo))
2595 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
2596 /*@i324@*/ yylval.annotation = ainfo;
2601 DPRINTF (("Not annotation: %s", id));
2607 /* Consider handling: Defined by C99 as static const char __func__[] */
2609 if (context_getFlag (FLG_GNUEXTENSIONS))
2613 if (cstring_equalLit (id, "__stdcall")
2614 || cstring_equalLit (id, "__cdecl")
2615 || cstring_equalLit (id, "__extension__"))
2619 else if (cstring_equalLit (id, "__volatile__"))
2623 else if (cstring_equalLit (id, "__signed"))
2627 else if (cstring_equalLit (id, "__unsigned"))
2631 else if (cstring_equalLit (id, "__const__"))
2635 else if (cstring_equalLit (id, "__alignof__"))
2637 tok = CALIGNOF; /* alignof is parsed like sizeof */
2639 else if (cstring_equalLit (id, "__FUNCTION__")
2640 || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
2642 /* These tokens hold the name of the current function as strings */
2643 yylval.expr = exprNode_stringLiteral (id, fileloc_copy (g_currentloc));
2645 lastWasString = TRUE;
2649 else if (cstring_equalLit (id, "__attribute__")
2650 || cstring_equalLit (id, "__asm__")
2651 || cstring_equalLit (id, "_asm")
2652 || cstring_equalLit (id, "__asm")
2653 || cstring_equalLit (id, "__declspec"))
2656 bool useparens = FALSE;
2657 bool usebraces = FALSE;
2658 bool inquote = FALSE;
2659 bool inescape = FALSE;
2662 while ((ic = input ()) != EOF)
2669 else if (ic == '\\')
2673 else if (ic == '\"')
2709 else if (ic == ')' && useparens)
2712 if (depth == 0) break;
2714 else if (ic == '}' && usebraces)
2717 if (depth == 0) break;
2720 && !usebraces && !useparens
2721 && cstring_equalLit (id, "__asm"))
2724 ** We need this because some MS VC++ include files
2725 ** have __asm mov ... }
2726 ** Its a kludge, but otherwise would need to parse
2735 context_incLineno ();
2737 if (cstring_equalLit (id, "__asm")
2738 && !useparens && !usebraces)
2745 llassert ((useparens && ic == ')')
2746 || (usebraces && ic == '}')
2747 || (!useparens && !usebraces));
2751 else if (cstring_equalLit (id, "inline")
2752 || cstring_equalLit (id, "__inline")
2753 || cstring_equalLit (id, "_inline")
2754 || cstring_equalLit (id, "__inline__"))
2765 le = usymtab_lookupSafe (id);
2767 /*@-dependenttrans@*/
2769 if (uentry_isIter (le))
2771 /*@i32@*/ yylval.entry = le;
2774 else if (uentry_isEndIter (le))
2776 /*@i32@*/ yylval.entry = le;
2777 return (ITER_ENDNAME);
2779 else if (uentry_isUndefined (le))
2783 /* avoid parse errors for certain system built ins */
2785 if (g_expectingTypeName && (cstring_firstChar (id) == '_')
2786 && (cstring_secondChar (id) == '_'))
2788 return (TYPE_NAME_OR_ID);
2791 return (NEW_IDENTIFIER);
2793 else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
2795 if (uentry_isDatatype (le))
2798 return (NEW_IDENTIFIER);
2802 /*@i32@*/ yylval.entry = le;
2803 return (IDENTIFIER);
2806 else if (uentry_isDatatype (le))
2808 if (!g_expectingTypeName)
2812 return (NEW_IDENTIFIER);
2816 yylval.ctyp = uentry_getAbstractType (le);
2818 uentry_setUsed (le, g_currentloc);
2824 /*@i32@*/ yylval.entry = le;
2825 return (IDENTIFIER);
2828 /*@=dependenttrans@*/
2831 static bool processHashIdentifier (/*@only@*/ cstring id)
2833 if (context_inMacro () || context_inIterDef () ||
2834 context_inIterEnd ())
2838 context_clearJustPopped ();
2840 lastidprocessed = id;
2841 le = usymtab_lookupSafe (id);
2843 if (uentry_isParam (le) || uentry_isRefParam (le))
2855 ** Will be handled by handleLlSpecial
2864 static /*@only@*/ exprNode processString ()
2868 char *nl = strchr (yytext, '\n');
2869 cstring ns = cstring_fromCharsNew (yytext);
2873 loc = fileloc_copy (g_currentloc);
2874 addColumn (cstring_length (ns));
2880 loc = fileloc_copy (g_currentloc);
2882 context_incLineno ();
2884 while ((nl = strchr ((nl + 1), '\n')) != NULL)
2886 context_incLineno ();
2892 res = exprNode_stringLiteral (ns, loc);
2902 llassert (*yytext != '\0');
2903 fchar = *(yytext + 1);
2904 if (fchar != '\\') return fchar;
2906 next = *(yytext + 2);
2910 case 'n': return '\n';
2911 case 't': return '\t';
2912 case '\"': return '\"';
2913 case '\'': return '\'';
2914 case '\\': return '\\';
2915 default: return '\0';
2920 double processFloat ()
2922 double ret = atof (yytext);
2933 llassert (yytext[0] == '0'
2934 && (yytext[1] == 'X' || yytext[1] == 'x'));
2936 while (yytext[index] != '\0') {
2938 char c = yytext[index];
2940 if (c >= '0' && c <= '9') {
2941 tval = (int) c - (int) '0';
2942 } else if (c >= 'A' && c <= 'F') {
2943 tval = (int) c - (int) 'A' + 10;
2944 } else if (c >= 'a' && c <= 'f') {
2945 tval = (int) c - (int) 'a' + 10;
2946 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2948 while (yytext[index] != '\0') {
2949 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2954 message ("Invalid character (%c) following specifier in hex constant: %s",
2955 c, cstring_fromChars (yytext)),
2965 message ("Invalid character (%c) in hex constant: %s",
2966 c, cstring_fromChars (yytext)),
2971 val = (val * 16) + tval;
2975 DPRINTF (("Hex constant: %s = %ld", yytext, val));
2980 long processOctal ()
2985 llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
2987 while (yytext[index] != '\0') {
2989 char c = yytext[index];
2991 if (c >= '0' && c <= '7') {
2992 tval = (int) c - (int) '0';
2993 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2995 while (yytext[index] != '\0') {
2996 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
3001 message ("Invalid character (%c) following specifier in octal constant: %s",
3002 c, cstring_fromChars (yytext)),
3012 message ("Invalid character (%c) in octal constant: %s",
3013 c, cstring_fromChars (yytext)),
3018 val = (val * 8) + tval;
3022 DPRINTF (("Octal constant: %s = %ld", yytext, val));
3029 return (atol (yytext));
3033 processSpec (int tok)
3035 size_t length = strlen (yytext);
3039 setTokLengthT (length);
3045 context_saveLocation ();
3046 setTokLengthT (length);
3047 return (processIdentifier (makeIdentifier (yytext)));
3051 void cscanner_expectingMetaStateName ()
3053 llassert (!expectingMetaStateName);
3054 llassert (context_inFunctionHeader ());
3055 expectingMetaStateName = TRUE;
3058 void cscanner_clearExpectingMetaStateName ()
3060 llassert (expectingMetaStateName);
3061 expectingMetaStateName = FALSE;