2 ** Copyright (c) Massachusetts Institute of Technology 1994-1998.
3 ** All Rights Reserved.
4 ** Unpublished rights reserved under the copyright laws of
7 ** THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 ** OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
10 ** This code is distributed freely and may be used freely under the
11 ** following conditions:
13 ** 1. This notice may not be removed or altered.
15 ** 2. Works derived from this code are not distributed for
16 ** commercial gain without explicit permission from MIT
17 ** (for permission contact lclint-request@sds.lcs.mit.edu).
20 * Modified by Herbert 08/19/97:
21 * - added #include for IBM's OS/2 compiler.
22 * - fixed weird bug with lookup of tmp files (OS/2 and MSDOS only).
26 * Modified by Mike Smith
27 * Corrected missing 'line' in scanf() calls in handleSpecial().
28 * Without this, I get an error when LCLint hits a '#line' directive
29 * in the pre-pre-processed source files. For safety, I have made these
30 * conditional on OS2 and MSDOS because I don't understand why noone else
31 * has seen this problem.
33 * Modified by Mike Smith, 4th June 1997
34 * Finally resolved the #line problem. The scanf() calls have been fixed to
35 * allow the following #line forms:-
37 * #line 123 "filename"
42 * The last two are generated by the GNU pre-processor, apparently
53 ULSuffix ({U}{L}|{L}{U})
57 ** based on original C lexer by Nate Osgood
58 ** from hacrat@catfish.lcs.mit.edu Mon Jun 14 13:06:32 1993
62 # include "lclintMacros.nf"
66 # include "cgrammar.h"
67 # include "cgrammar_tokens.h"
69 # include "fileIdList.h"
72 # if defined(OS2) && defined(__IBMC__)
73 /* needed for isatty()... */
77 static bool lastWasString = FALSE;
78 static char savechar = '\0';
81 # define yyinput() (incColumn (), getc (yyin))
83 static /*@owned@*/ cstring lastidprocessed = cstring_undefined;
84 static int lminput (void);
85 static int tokLength = 0;
86 static bool inSpecPart = FALSE;
87 static bool continueLine = FALSE;
89 static int ninput (void);
90 static char processChar (void);
91 static double processFloat (void);
92 static /*@only@*/ exprNode processString (void);
93 static long processDec (void);
94 static long processHex (void);
95 static long processOctal (void);
96 static int processIdentifier (/*@only@*/ cstring)
97 /*@globals undef lastidprocessed@*/ ;
98 static bool processHashIdentifier (/*@only@*/ cstring)
99 /*@globals undef lastidprocessed@*/ ;
101 static int processSpec (int);
102 static bool handleSpecial (char *);
103 static int handleLlSpecial (void);
104 static void handleMacro (void);
105 static bool processMacro (void);
106 static /*@only@*/ cstring makeIdentifier (char *);
108 /* yes, this is exported! */
109 bool g_expectingTypeName = TRUE; /* beginning of file can be type name! */
111 static bool expectingMetaStateName = FALSE;
113 static int returnInt (ctype, long);
114 static int returnFloat (ctype, double);
115 static int returnChar (char);
116 static void setTokLength (int) /*@modifies g_currentloc@*/ ;
117 static void setTokLengthT (size_t) /*@modifies g_currentloc@*/ ;
119 static void advanceLine (void)
126 # define RETURN_INT(c,i) \
127 do { lastWasString = FALSE; \
128 return (returnInt (c, i)); } while (FALSE)
130 # define RETURN_FLOAT(c,f) \
131 do { lastWasString = FALSE; \
132 return (returnFloat (c, f)); \
135 # define RETURN_CHAR(c) \
136 do { lastWasString = FALSE; \
137 return (returnChar (c)); \
140 # define RETURN_TOK(t) \
141 do { yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, tokLength)); \
143 lastWasString = FALSE; \
144 return (t); } while (FALSE)
146 # define RETURN_TYPE(t, ct) \
147 do { yylval.ctyp = ct; tokLength = 0; return (t); } while (FALSE)
149 /* don't fileloc_decColumn (g_currentloc, tokLength));
150 the string could have \n's in it!
153 # define RETURN_STRING(c) \
154 do { yylval.expr = exprNode_stringLiteral (c, fileloc_decColumn (g_currentloc, tokLength)); \
156 lastWasString = TRUE; \
157 return (CCONSTANT); } while (FALSE)
159 # define RETURN_EXPR(e) \
160 do { yylval.expr = e; \
162 lastWasString = TRUE; \
163 return (CCONSTANT); } while (FALSE)
167 static void setTokLength (int len)
173 static void setTokLengthT (size_t len)
175 setTokLength (size_toInt (len));
178 # include "flex.head"
180 /*@-unrecog@*/ /*@i5343@*/
186 "/*" { llfatalbug (cstring_makeLiteral ("Comment in pre-processor output")); }
188 "#"{Letter}({Letter}|{Digit})* {
189 context_saveLocation ();
190 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
192 if (processHashIdentifier (makeIdentifier (yytext + 1)))
196 /* was nothing! */ /*@i32@*/
197 RETURN_STRING (cstring_makeLiteral ("\"\""));
201 RETURN_STRING (cstring_makeLiteral ("\"\""));
206 if (handleSpecial (yytext))
213 "#" { if (handleSpecial (yytext))
215 setTokLength (1); RETURN_TOK (0);
218 "..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); }
219 "break" { setTokLength (5); RETURN_TOK (BREAK); }
220 "case" { setTokLength (4); RETURN_TOK (CASE); }
221 "continue" { setTokLength (8); RETURN_TOK (CONTINUE); }
222 "default" { setTokLength (7); RETURN_TOK (DEFAULT); }
223 "do" { setTokLength (2); RETURN_TOK (DO); }
224 "else" { setTokLength (4); RETURN_TOK (CELSE); }
225 "for" { setTokLength (3); RETURN_TOK (CFOR); }
226 "goto" { setTokLength (4); RETURN_TOK (GOTO); }
227 "if" { setTokLength (2); RETURN_TOK (CIF); }
228 "return" { setTokLength (6); RETURN_TOK (RETURN); }
229 "sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); }
230 "offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); }
231 "switch" { setTokLength (6); RETURN_TOK (SWITCH); }
232 "while" { setTokLength (5); RETURN_TOK (WHILE); }
233 "va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); }
234 "va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); }
236 /* gcc extension...this might not be appropriate */
237 setTokLength (6); RETURN_TOK (QINLINE); }
239 "struct" { setTokLength (6); RETURN_TOK (CSTRUCT); }
240 "typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); }
242 "union" { setTokLength (5); RETURN_TOK (CUNION); }
243 "enum" { setTokLength (4); RETURN_TOK (CENUM); }
245 "void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); }
246 "int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); }
247 "double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); }
248 "char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); }
249 "float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); }
251 "long" { setTokLength (4); RETURN_TOK (QLONG); }
252 "short" { setTokLength (5); RETURN_TOK (QSHORT); }
253 "unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); }
254 "signed" { setTokLength (6); RETURN_TOK (QSIGNED); }
256 "volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); }
257 "const" { setTokLength (5); RETURN_TOK (QCONST); }
259 /* some systems expect this! [gack!] */
260 "__const" { setTokLength (7); RETURN_TOK (QCONST); }
262 "extern" { setTokLength (6); RETURN_TOK (QEXTERN); }
263 "auto" { setTokLength (4); RETURN_TOK (QAUTO); }
264 "register" { setTokLength (8); RETURN_TOK (QREGISTER); }
265 "static" { setTokLength (6); RETURN_TOK (QSTATIC); }
267 \"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
268 L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
269 "out" { return (processSpec (QOUT)); }
270 "in" { return (processSpec (QIN)); }
271 "partial" { return (processSpec (QPARTIAL)); }
272 "special" { return (processSpec (QSPECIAL)); }
273 "anytype" { return (processSpec (QANYTYPE)); }
274 "integraltype" { return (processSpec (QINTEGRALTYPE)); }
275 "unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); }
276 "signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); }
277 "keep" { return (processSpec (QKEEP)); }
278 "null" { return (processSpec (QNULL)); }
279 "notnull" { return (processSpec (QNOTNULL)); }
280 "isnull" { return (processSpec (QISNULL)); }
281 "truenull" { return (processSpec (QTRUENULL)); }
282 "falsenull" { return (processSpec (QFALSENULL)); }
283 "relnull" { return (processSpec (QRELNULL)); }
284 "reldef" { return (processSpec (QRELDEF)); }
285 "exposed" { return (processSpec (QEXPOSED)); }
286 "newref" { return (processSpec (QNEWREF)); }
287 "tempref" { return (processSpec (QTEMPREF)); }
288 "killref" { return (processSpec (QKILLREF)); }
289 "refcounted" { return (processSpec (QREFCOUNTED)); }
290 "checked" { return (processSpec (QCHECKED)); }
291 "checkmod" { return (processSpec (QCHECKMOD)); }
292 "checkedstrict" { return (processSpec (QCHECKEDSTRICT)); }
293 "unchecked" { return (processSpec (QUNCHECKED)); }
294 "only" { return (processSpec (QONLY)); }
295 "owned" { return (processSpec (QOWNED)); }
296 "observer" { return (processSpec (QOBSERVER)); }
297 "dependent" { return (processSpec (QDEPENDENT)); }
298 "unused" { return (processSpec (QUNUSED)); }
299 "external" { return (processSpec (QEXTERNAL)); }
300 "sef" { return (processSpec (QSEF)); }
301 "shared" { return (processSpec (QSHARED)); }
302 "yield" { return (processSpec (QYIELD)); }
303 "undef" { return (processSpec (QUNDEF)); }
304 "killed" { return (processSpec (QKILLED)); }
305 "nullterminated" { return (processSpec (QNULLTERMINATED));}
306 "MaxSet" { return (processSpec (QMAXSET));}
307 "MaxRead" { return (processSpec (QMAXREAD));}
308 "maxSet" { return (processSpec (QMAXSET));}
309 "maxRead" { return (processSpec (QMAXREAD));}
311 {Letter}({Letter}|{Digit})* { int tok;
312 context_saveLocation ();
313 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
314 tok = processIdentifier (makeIdentifier (yytext));
320 0[xX]{H}+ { setTokLengthT (mstring_length (yytext));
321 RETURN_INT (ctype_int, processHex ()); /* evs 2000-05-17 was ctype_uint */
323 0[xX]{H}+{L} { setTokLengthT (mstring_length (yytext));
324 RETURN_INT (ctype_lint, processHex ()); }
325 0[xX]{H}+{L}{L} { setTokLengthT (mstring_length (yytext));
326 RETURN_INT (ctype_llint, processHex ()); }
327 0[xX]{H}+{U} { setTokLengthT (mstring_length (yytext));
328 RETURN_INT (ctype_uint, processHex ()); }
329 0[xX]{H}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
330 RETURN_INT (ctype_ulint, processHex ()); }
331 0[xX]{H}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
332 RETURN_INT (ctype_ullint, processHex ()); }
333 0[xX]{H}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
334 RETURN_INT (ctype_ullint, processHex ()); }
335 0{Digit}+ { setTokLengthT (mstring_length (yytext));
336 RETURN_INT (ctype_int, processOctal ()); }
337 0{Digit}+{U} { setTokLengthT (mstring_length (yytext));
338 RETURN_INT (ctype_uint, processOctal ()); }
339 0{Digit}+{L} { setTokLengthT (mstring_length (yytext));
340 RETURN_INT (ctype_lint, processOctal ()); }
341 0{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
342 RETURN_INT (ctype_llint, processOctal ()); }
343 0{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
344 RETURN_INT (ctype_ulint, processOctal ()); }
345 0{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
346 RETURN_INT (ctype_ullint, processOctal ()); }
347 0{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
348 RETURN_INT (ctype_ullint, processOctal ()); }
349 {Digit}+ { setTokLengthT (mstring_length (yytext));
350 RETURN_INT (ctype_int, processDec ()); }
351 {Digit}+{U} { setTokLengthT (mstring_length (yytext));
352 RETURN_INT (ctype_uint, processDec ()); }
353 {Digit}+{L} { setTokLengthT (mstring_length (yytext));
354 RETURN_INT (ctype_lint, processDec ()); }
355 {Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
356 RETURN_INT (ctype_llint, processDec ()); }
357 {Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
358 RETURN_INT (ctype_ulint, processDec ()); }
359 {Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
360 RETURN_INT (ctype_ullint, processDec ()); }
361 {Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
362 RETURN_INT (ctype_ullint, processDec ()); }
363 '(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
364 RETURN_CHAR (processChar ()); }
365 {Digit}+{E}[fF] { setTokLengthT (mstring_length (yytext));
366 RETURN_FLOAT (ctype_float, processFloat ()); }
367 {Digit}+{E}[lL] { setTokLengthT (mstring_length (yytext));
368 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
369 {Digit}+{E} { setTokLengthT (mstring_length (yytext));
370 RETURN_FLOAT (ctype_double, processFloat ()); }
372 {Digit}*"."{Digit}+({E})?[fF] { setTokLengthT (mstring_length (yytext));
373 RETURN_FLOAT (ctype_float, processFloat ()); }
374 {Digit}*"."{Digit}+({E})?[lL] { setTokLengthT (mstring_length (yytext));
375 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
376 {Digit}*"."{Digit}+({E})? { setTokLengthT (mstring_length (yytext));
377 RETURN_FLOAT (ctype_double, processFloat ()); }
379 {Digit}+"."{Digit}*({E})?[fF] { setTokLengthT (mstring_length (yytext));
380 RETURN_FLOAT (ctype_float, processFloat ()); }
381 {Digit}+"."{Digit}*({E})?[lL] { setTokLengthT (mstring_length (yytext));
382 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
383 {Digit}+"."{Digit}*({E})? { setTokLengthT (mstring_length (yytext));
384 RETURN_FLOAT (ctype_double, processFloat ()); }
386 ">>=" { setTokLength (3); RETURN_TOK (RIGHT_ASSIGN); }
387 "<<=" { setTokLength (3); RETURN_TOK (LEFT_ASSIGN); }
388 "+=" { setTokLength (2); RETURN_TOK (ADD_ASSIGN); }
389 "-=" { setTokLength (2); RETURN_TOK (SUB_ASSIGN); }
390 "*=" { setTokLength (2); RETURN_TOK (MUL_ASSIGN); }
391 "/=" { setTokLength (2); RETURN_TOK (DIV_ASSIGN); }
392 "%=" { setTokLength (2); RETURN_TOK (MOD_ASSIGN); }
393 "&=" { setTokLength (2); RETURN_TOK (AND_ASSIGN); }
394 "^=" { setTokLength (2); RETURN_TOK (XOR_ASSIGN); }
395 "|=" { setTokLength (2); RETURN_TOK (OR_ASSIGN); }
396 ">>" { setTokLength (2); RETURN_TOK (RIGHT_OP); }
397 "<<" { setTokLength (2); RETURN_TOK (LEFT_OP); }
398 "++" { setTokLength (2); RETURN_TOK (INC_OP); }
399 "--" { setTokLength (2); RETURN_TOK (DEC_OP); }
400 "->" { setTokLength (2); RETURN_TOK (ARROW_OP); }
401 "&&" { setTokLength (2); RETURN_TOK (AND_OP); }
402 "||" { setTokLength (2); RETURN_TOK (OR_OP); }
403 "<=" { setTokLength (2); RETURN_TOK (LE_OP); }
404 ">=" { setTokLength (2); RETURN_TOK (GE_OP); }
405 "==" { setTokLength (2); RETURN_TOK (EQ_OP); }
406 "!=" { setTokLength (2); RETURN_TOK (NE_OP); }
407 ";" { setTokLength (1); RETURN_TOK (TSEMI); }
408 "{" { setTokLength (1); RETURN_TOK (TLBRACE); }
409 "}" { setTokLength (1); RETURN_TOK (TRBRACE); }
410 "," { setTokLength (1); RETURN_TOK (TCOMMA); }
411 ":" { setTokLength (1); RETURN_TOK (TCOLON); }
412 "=" { setTokLength (1); RETURN_TOK (TASSIGN); }
413 "(" { setTokLength (1); RETURN_TOK (TLPAREN); }
414 ")" { setTokLength (1); RETURN_TOK (TRPAREN); }
415 "[" { setTokLength (1); RETURN_TOK (TLSQBR); }
416 "]" { setTokLength (1); RETURN_TOK (TRSQBR); }
417 "." { setTokLength (1); RETURN_TOK (TDOT); }
418 "&" { setTokLength (1); RETURN_TOK (TAMPERSAND); }
419 "!" { setTokLength (1); RETURN_TOK (TEXCL); }
422 "~" { setTokLength (1); RETURN_TOK (TTILDE); }
423 "-" { setTokLength (1); RETURN_TOK (TMINUS); }
424 "+" { setTokLength (1); RETURN_TOK (TPLUS); }
425 "*" { setTokLength (1); RETURN_TOK (TMULT); }
426 "/" { setTokLength (1); RETURN_TOK (TDIV); }
427 "%" { setTokLength (1); RETURN_TOK (TPERCENT); }
428 "<" { setTokLength (1); RETURN_TOK (TLT); }
429 ">" { setTokLength (1); RETURN_TOK (TGT); }
430 "^" { setTokLength (1); RETURN_TOK (TCIRC); }
431 "|" { setTokLength (1); RETURN_TOK (TBAR); }
432 "?" { setTokLength (1); RETURN_TOK (TQUEST); }
435 "/\\" { setTokLength (1); RETURN_TOK (TCAND); }
438 [ \t\v\f] { incColumn (); }
439 \n { context_incLineno ();
442 continueLine = FALSE;
446 if (context_inMacro ())
448 /* Don't use RETURN_TOK */
449 yylval.tok = lltok_create (TENDMACRO, g_currentloc);
450 lastWasString = FALSE;
455 "@@MR@@" { setTokLength (6);
457 if (processMacro ()) {
458 if (context_inIterDef ())
460 RETURN_TOK (LLMACROITER);
462 if (context_inIterEnd ())
464 RETURN_TOK (LLMACROEND);
466 if (context_inMacro ())
468 RETURN_TOK (LLMACRO);
472 "@QLMR" { if (context_inHeader () || context_inFunction ())
478 int nspchar = ninput ();
482 ** This is a hack to get the column number correct.
485 llassert (nspchar >= '0' && nspchar <= '9');
487 nspaces = nspchar - '0';
489 setTokLength (5 + nspaces);
493 if (context_inIterDef ())
495 RETURN_TOK (LLMACROITER);
497 if (context_inIterEnd ())
499 RETURN_TOK (LLMACROEND);
501 if (context_inMacro ())
503 RETURN_TOK (LLMACRO);
508 "@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); }
509 "@.FA" { setTokLength (4); lldiagmsg (message ("Access types: %q", typeIdSet_unparse (context_fileAccessTypes ()))); }
510 "@.F" { setTokLength (3);
511 lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc)));
513 "@.L" { setTokLength (3); usymtab_printLocal (); }
514 "@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); }
515 "@.C" { setTokLength (3); lldiagmsg (context_unparse ()); }
516 "@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); }
517 "@.G" { setTokLength (3); usymtab_printGuards (); }
518 "@.S" { setTokLength (3); usymtab_printOut (); }
519 "@.X" { setTokLength (3); usymtab_printAll (); }
520 "@.Z" { setTokLength (3); usymtab_printComplete (); }
521 "@.T" { setTokLength (3); usymtab_printTypes (); }
522 "@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); }
523 "@.M" { setTokLength (3);
524 lldiagmsg (message ("Can modify: %q",
525 sRefSet_unparse (context_modList ())));
527 "%{" { /* BEFORE_COMMENT_MARKER */
529 incColumn (); incColumn ();
530 tok = handleLlSpecial ();
534 if (tok == CANNOTATION) {
537 /* Beware - this bashes yylval! */
542 "%}" { /* AFTER_COMMENT_MARKER */
545 RETURN_TOK (QENDMACRO); }
546 "\\" { incColumn (); continueLine = TRUE; }
548 if ((int) *yytext == 13 ) {
553 message ("Invalid character (ascii: %d), skipping character",
562 /*@null@*/ /*@observer@*/ char *name;
567 ** These tokens are followed by syntax that is parsed by the
571 struct skeyword s_parsetable[] = {
572 { "modifies", QMODIFIES } ,
573 { "globals", QGLOBALS } ,
576 { "constant", QCONSTANT } ,
577 { "function", QFUNCTION } ,
579 { "defines", QDEFINES } ,
581 { "allocates", QALLOCATES } ,
583 { "releases", QRELEASES } ,
584 { "pre", QPRECLAUSE } ,
585 { "post", QPOSTCLAUSE } ,
586 { "setBufferSize", QSETBUFFERSIZE},
587 { "setStringLength", QSETSTRINGLENGTH},
588 { "testinRange", QTESTINRANGE},
589 { "requires", QPRECLAUSE } ,
590 { "ensures", QPOSTCLAUSE } ,
595 ** These tokens are either stand-alone tokens, or followed by
596 ** token-specific text.
599 struct skeyword s_keytable[] = {
600 { "anytype", QANYTYPE } ,
601 { "integraltype", QINTEGRALTYPE } ,
602 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,
603 { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,
607 { "owned", QOWNED } ,
608 { "dependent", QDEPENDENT } ,
609 { "partial", QPARTIAL } ,
610 { "special", QSPECIAL } ,
611 { "truenull", QTRUENULL } ,
612 { "falsenull", QFALSENULL } ,
615 { "notnull", QNOTNULL } ,
616 { "abstract", QABSTRACT } ,
617 { "concrete", QCONCRETE } ,
618 { "mutable", QMUTABLE } ,
619 { "immutable", QIMMUTABLE } ,
620 { "unused", QUNUSED } ,
621 { "external", QEXTERNAL } ,
623 { "unique", QUNIQUE } ,
624 { "returned", QRETURNED } ,
625 { "exposed", QEXPOSED } ,
626 { "refcounted", QREFCOUNTED } ,
628 { "newref", QNEWREF } ,
629 { "tempref", QTEMPREF } ,
630 { "killref", QKILLREF } ,
632 { "relnull", QRELNULL } ,
633 { "nullterminated", QNULLTERMINATED },
634 { "setBufferSize", QSETBUFFERSIZE },
635 { "testInRange", QTESTINRANGE},
636 { "MaxSet", QMAXSET},
637 { "MaxRead", QMAXREAD},
638 { "reldef", QRELDEF } ,
639 { "observer", QOBSERVER } ,
640 { "exits", QEXITS } ,
641 { "mayexit", QMAYEXIT } ,
642 { "trueexit", QTRUEEXIT } ,
643 { "falseexit", QFALSEEXIT } ,
644 { "neverexit", QNEVEREXIT } ,
646 { "shared", QSHARED } ,
648 { "unchecked", QUNCHECKED } ,
649 { "checked", QCHECKED } ,
650 { "checkmod", QCHECKMOD } ,
651 { "checkedstrict", QCHECKEDSTRICT } ,
652 { "innercontinue", QINNERCONTINUE } ,
653 { "innerbreak", QINNERBREAK } ,
654 { "loopbreak", QLOOPBREAK } ,
655 { "switchbreak", QSWITCHBREAK } ,
656 { "safebreak", QSAFEBREAK } ,
657 { "fallthrough", QFALLTHROUGH } ,
658 { "l_fallthrou", QLINTFALLTHROUGH } ,
659 { "l_fallth", QLINTFALLTHRU } ,
660 { "notreached", QNOTREACHED } ,
661 { "l_notreach", QLINTNOTREACHED } ,
662 { "printflike", QPRINTFLIKE } ,
663 { "l_printfli", QLINTPRINTFLIKE } ,
664 { "scanflike", QSCANFLIKE } ,
665 { "messagelike", QMESSAGELIKE } ,
666 { "l_argsus", QARGSUSED } ,
671 ** would be better if these weren't hard coded...
674 static bool isArtificial (cstring s)
676 return (cstring_equalLit (s, "modifies")
677 || cstring_equalLit (s, "globals")
678 || cstring_equalLit (s, "warn")
679 || cstring_equalLit (s, "alt"));
682 void swallowMacro (void)
685 bool skipnext = FALSE;
687 while ((i = lminput ()) != EOF)
704 reader_checkUngetc (i, yyin);
712 reader_checkUngetc (i, yyin);
716 static int commentMarkerToken (cstring s)
720 while (s_parsetable[i].name != NULL)
722 DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name));
724 if (cstring_equalLit (s, s_parsetable[i].name))
726 return s_parsetable[i].token;
735 static int tokenMacroCode (cstring s)
739 while (s_keytable[i].name != NULL)
741 if (cstring_equalLit (s, s_keytable[i].name))
743 if (s_keytable[i].token == QLINTFALLTHROUGH)
746 (FLG_WARNLINTCOMMENTS,
748 ("Traditional lint comment /*FALLTHROUGH*/ used. "
749 "This is interpreted by "
750 "LCLint in the same way as most Unix lints, but it is "
751 "preferable to replace it with the /*@fallthrough@*/ "
756 else if (s_keytable[i].token == QLINTFALLTHRU)
759 (FLG_WARNLINTCOMMENTS,
761 ("Traditional lint comment /*FALLTHRU*/ used. "
762 "This is interpreted by "
763 "LCLint in the same way as most Unix lints, but it is "
764 "preferable to replace it with the /*@fallthrough@*/ "
769 else if (s_keytable[i].token == QLINTNOTREACHED)
772 (FLG_WARNLINTCOMMENTS,
774 ("Traditional lint comment /*NOTREACHED*/ used. "
775 "This is interpreted by "
776 "LCLint in the same way as most Unix lints, but it is "
777 "preferable to replace it with the /*@notreached@*/ "
778 "semantic comment."),
783 else if (s_keytable[i].token == QPRINTFLIKE)
785 setSpecialFunction (qual_createPrintfLike ());
788 else if (s_keytable[i].token == QLINTPRINTFLIKE)
791 (FLG_WARNLINTCOMMENTS,
793 ("Traditional lint comment /*PRINTFLIKE*/ used. "
794 "This is interpreted by "
795 "LCLint in the same way as most Unix lints, but it is "
796 "preferable to replace it with either /*@printflike@*/, "
797 "/*@scanflike@*/ or /*@messagelike@*/."),
800 setSpecialFunction (qual_createPrintfLike ());
803 else if (s_keytable[i].token == QSCANFLIKE)
805 setSpecialFunction (qual_createScanfLike ());
808 else if (s_keytable[i].token == QMESSAGELIKE)
810 setSpecialFunction (qual_createMessageLike ());
813 else if (s_keytable[i].token == QARGSUSED)
816 (FLG_WARNLINTCOMMENTS,
818 ("Traditional lint comment /*ARGSUSED*/ used. "
819 "This is interpreted by "
820 "LCLint in the same way as most Unix lints, but it is "
821 "preferable to use /*@unused@*/ annotations on "
822 "the unused parameters."),
829 return s_keytable[i].token;
838 static int lminput ()
840 if (savechar == '\0')
847 int save = (int) savechar;
853 static void lmsavechar (char c)
855 if (savechar == '\0') savechar = c;
858 llbuglit ("lmsavechar: override");
862 static int returnFloat (ctype ct, double f)
864 yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext),
865 fileloc_decColumn (g_currentloc, tokLength));
870 static int returnInt (ctype ct, long i)
874 if (ctype_equal (ct, ctype_int))
878 c = context_typeofZero ();
882 c = context_typeofOne ();
886 yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext),
887 fileloc_decColumn (g_currentloc, tokLength), i);
892 static int returnChar (char c)
894 yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext),
895 fileloc_decColumn (g_currentloc, tokLength));
904 if (c != EOF && ((char)c == '\n'))
906 context_incLineno ();
912 static char macro_nextChar ()
914 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
919 c = char_fromInt (ic);
921 if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
925 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
927 ; /* skip to newline */
930 context_incLineno ();
934 return macro_nextChar ();
941 else /* if (c == '@') */
943 llassert (FALSE); /*@i23@*/
944 if (handleLlSpecial () != BADTOK)
946 llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
949 return macro_nextChar ();
952 else if (!in_escape && c == '\"')
954 in_quote = !in_quote;
956 else if (!in_escape && c == '\'')
960 else if ((in_quote || in_char) && c == '\\')
962 in_escape = !in_escape;
964 else if ((in_quote || in_char) && in_escape)
968 else if (!in_quote && c == '/')
972 if ((c2 = char_fromInt (lminput ())) == '*')
976 while ((c2 = char_fromInt (lminput ())) != '\0'
977 && c2 != '\n' && c2 != '*')
984 while ((c2 = char_fromInt (lminput ())) != '\0'
997 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1001 return macro_nextChar ();
1005 /*** putchar does not work! why? puts to stdio...??! ***/
1013 ** keeps semantic comments
1016 static char macro_nextCharC ()
1018 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
1021 c = char_fromInt (lminput ());
1023 if (!in_quote && !in_char && c == '\\')
1025 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
1027 ; /* skip to newline */
1030 context_incLineno ();
1034 return macro_nextCharC ();
1041 else if (!in_escape && c == '\"')
1043 in_quote = !in_quote;
1045 else if (!in_escape && c == '\'')
1049 else if ((in_quote || in_char) && c == '\\')
1051 in_escape = !in_escape;
1053 else if ((in_quote || in_char) && in_escape)
1057 else if (!in_quote && c == '/')
1061 if ((c2 = char_fromInt (lminput ())) == '*')
1065 while ((c2 = char_fromInt (lminput ())) != '\0'
1066 && c2 != '\n' && c2 != '*')
1073 while ((c2 = char_fromInt (lminput ())) != '\0'
1086 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1090 return macro_nextCharC ();
1101 ** skips whitespace (handles line continuations)
1102 ** returns first non-whitespace character
1105 static char skip_whitespace ()
1109 while ((c = macro_nextChar ()) == ' ' || c == '\t')
1117 static void handleMacro ()
1119 cstring mac = cstring_undefined;
1123 while (currentColumn () > 2)
1125 mac = cstring_appendChar (mac, ' ');
1129 c = macro_nextCharC ();
1131 if (c >= '0' && c <= '9')
1135 for (i = 0; i < ((c - '0') + 1); i++)
1137 mac = cstring_appendChar (mac, ' ');
1145 while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
1147 mac = cstring_appendChar (mac, c);
1151 macrocode = tokenMacroCode (mac);
1153 if (macrocode == BADTOK && !isArtificial (mac))
1155 context_addMacroCache (mac);
1164 context_incLineno ();
1168 static bool processMacro (void)
1173 cstring fname = cstring_undefined;
1175 bool isspecfcn = FALSE;
1176 bool isiter = FALSE;
1177 bool skipparam = FALSE;
1178 bool isenditer = FALSE;
1179 bool unknownm = FALSE;
1180 bool hasParams = FALSE;
1181 bool emptyMacro = FALSE;
1182 char c = skip_whitespace ();
1183 fileloc loc = fileloc_noColumn (g_currentloc);
1185 /* are both of these necessary? what do they mean? */
1186 uentryList specparams = uentryList_undefined;
1187 uentryList pn = uentryList_undefined;
1189 context_resetMacroMissingParams ();
1191 if (c == '\0' || c == '\n')
1193 llcontbug (cstring_makeLiteral ("Bad macro"));
1198 fname = cstring_appendChar (fname, c);
1200 while ((c = macro_nextChar ()) != '(' && c != '\0'
1201 && c != ' ' && c != '\t' && c != '\n')
1203 fname = cstring_appendChar (fname, c);
1206 if (c == ' ' || c == '\t' || c == '\n')
1212 while (c == ' ' || c == '\t')
1214 c = macro_nextChar ();
1228 hasParams = (c == '(');
1231 if (usymtab_exists (fname))
1233 e2 = usymtab_lookupExpose (fname);
1234 ct = uentry_getType (e2);
1236 if (uentry_isCodeDefined (e2)
1237 && fileloc_isUser (uentry_whereDefined (e2)))
1241 message ("Macro %s already defined", fname),
1244 uentry_showWhereDefined (e2);
1245 uentry_clearDefined (e2);
1248 if (uentry_isFunction (e2))
1250 uentry_setType (e2, ctype_unknown);
1253 context_enterUnknownMacro (e2);
1257 context_enterConstantMacro (e2);
1262 if (uentry_isForward (e2) && uentry_isFunction (e2))
1269 ("Parameterized macro has no prototype or specification: %s ",
1274 uentry_setType (e2, ctype_unknown);
1275 uentry_setFunctionDefined (e2, loc);
1276 uentry_setUsed (e2, fileloc_undefined);
1277 context_enterUnknownMacro (e2);
1281 if (uentry_isIter (e2))
1284 specparams = uentry_getParams (e2);
1285 noparams = uentryList_size (specparams);
1286 uentry_setDefined (e2, loc);
1287 context_enterIterDef (e2);
1289 else if (uentry_isEndIter (e2))
1292 uentry_setDefined (e2, loc);
1293 context_enterIterEnd (e2); /* don't care about it now */
1294 /* but should parse like an iter! */
1296 else if (uentry_isConstant (e2))
1302 message ("Constant %s implemented as parameterized macro",
1306 uentry_showWhereSpecified (e2);
1307 uentry_setType (e2, ctype_unknown);
1308 uentry_makeConstantFunction (e2);
1309 uentry_setDefined (e2, g_currentloc);
1310 uentry_setFunctionDefined (e2, g_currentloc);
1311 context_enterUnknownMacro (e2);
1315 if (!uentry_isSpecified (e2))
1317 fileloc oloc = uentry_whereDeclared (e2);
1319 if (fileloc_isLib (oloc))
1323 else if (fileloc_isUndefined (oloc)
1324 || fileloc_isPreproc (oloc))
1329 (FLG_MACROCONSTDECL,
1331 ("Macro constant %q not declared",
1332 uentry_getName (e2)),
1336 else if (!fileloc_withinLines (oloc, loc, 2))
1337 { /* bogus! will give errors if there is too much whitespace */
1341 ("Macro constant name %s does not match name in "
1342 "previous constant declaration. This constant "
1343 "is declared at %q", fname,
1344 fileloc_unparse (oloc)),
1349 context_enterConstantMacro (e2);
1350 cstring_free (fname);
1356 else if (ctype_isFunction (ct))
1359 specparams = ctype_argsFunction (ct);
1360 noparams = uentryList_size (specparams);
1362 uentry_setFunctionDefined (e2, loc);
1363 context_enterMacro (e2);
1365 else if (uentry_isVar (e2))
1371 message ("Variable %s implemented as parameterized macro",
1375 uentry_showWhereSpecified (e2);
1376 uentry_setType (e2, ctype_unknown);
1377 uentry_makeVarFunction (e2);
1378 uentry_setDefined (e2, g_currentloc);
1379 uentry_setFunctionDefined (e2, g_currentloc);
1380 context_enterUnknownMacro (e2);
1384 uentry ucons = uentry_makeConstant (fname,
1387 if (uentry_isExpandedMacro (e2))
1395 message ("Variable %s implemented by a macro",
1399 uentry_showWhereSpecified (e2);
1403 uentry_setDefined (e2, loc);
1404 uentry_setUsed (ucons, loc);
1406 context_enterConstantMacro (ucons);
1407 uentry_markOwned (ucons);
1408 cstring_free (fname);
1414 if (uentry_isDatatype (e2))
1418 message ("Type implemented as macro: %x",
1419 uentry_getName (e2)),
1420 message ("A type is implemented using a macro definition. A "
1421 "typedef should be used instead."),
1425 /* Must exit scope (not sure why a new scope was entered?) */
1426 usymtab_quietExitScope (g_currentloc);
1427 uentry_setDefined (e2, g_currentloc);
1433 (message ("Unexpanded macro not function or constant: %q",
1434 uentry_unparse (e2)));
1435 uentry_setType (e2, ctype_unknown);
1439 uentry_makeVarFunction (e2);
1440 uentry_setDefined (e2, g_currentloc);
1441 uentry_setFunctionDefined (e2, g_currentloc);
1442 context_enterUnknownMacro (e2);
1454 (FLG_MACROMATCHNAME,
1455 message ("Unexpanded macro %s does not match name of a constant "
1456 "or iter declaration. The name used in the control "
1457 "comment on the previous line should match. "
1458 "(Assuming macro defines a constant.)",
1463 ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
1464 uentry_setUsed (ce, loc); /* perhaps bogus? */
1465 e2 = usymtab_supEntryReturn (ce);
1467 context_enterConstantMacro (e2);
1468 cstring_free (fname);
1473 /* in macros, ( must follow immediatetly after name */
1479 c = skip_whitespace ();
1481 while (c != ')' && c != '\0')
1484 bool suppress = context_inSuppressRegion ();
1485 cstring paramname = cstring_undefined;
1488 ** save the parameter location
1492 context_saveLocation ();
1495 while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
1497 paramname = cstring_appendChar (paramname, c);
1498 c = macro_nextChar ();
1501 if (c == ' ' || c == '\t') c = skip_whitespace ();
1505 c = macro_nextChar ();
1506 if (c == ' ' || c == '\t') c = skip_whitespace ();
1511 llfatalerror (cstring_makeLiteral
1512 ("Bad macro syntax: uentryList"));
1515 if ((isspecfcn || isiter) && (paramno < noparams)
1516 && !uentry_isElipsisMarker (uentryList_getN
1517 (specparams, paramno)))
1519 fileloc sloc = context_getSaveLocation ();
1520 uentry decl = uentryList_getN (specparams, paramno);
1523 param = uentry_nameCopy (paramname, decl);
1526 uentry_setParam (param);
1527 sr = sRef_makeParam (paramno, uentry_getType (param), stateInfo_makeLoc (sloc));
1529 if (sRef_getNullState (sr) == NS_ABSNULL)
1531 ctype pt = ctype_realType (uentry_getType (param));
1533 if (ctype_isUser (pt))
1535 uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
1537 if (uentry_isValid (te))
1539 sRef_setStateFromUentry (sr, te);
1544 sRef_setNullState (sr, NS_UNKNOWN, sloc);
1548 uentry_setSref (param, sr);
1549 uentry_setDeclaredForceOnly (param, sloc);
1551 skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
1555 fileloc sloc = context_getSaveLocation ();
1557 param = uentry_makeVariableSrefParam
1558 (paramname, ctype_unknown, fileloc_copy (sloc),
1559 sRef_makeParam (paramno, ctype_unknown, stateInfo_makeLoc (sloc)));
1560 cstring_free (paramname);
1562 sRef_setPosNull (uentry_getSref (param), sloc);
1563 uentry_setDeclaredForce (param, sloc);
1566 fileloc_free (sloc);
1571 llassert (!uentry_isElipsisMarker (param));
1575 sRef_makeUnsafe (uentry_getSref (param));
1578 pn = uentryList_add (pn, uentry_copy (param));
1579 usymtab_supEntry (param);
1583 /* don't add param */
1584 uentry_free (param);
1589 (void) macro_nextChar ();
1590 c = skip_whitespace ();
1598 if (isspecfcn || isiter)
1600 if (paramno != noparams && noparams >= 0)
1606 message ("Macro %s specified with %d args, defined with %d",
1607 fname, noparams, paramno),
1610 uentry_showWhereSpecified (e2);
1611 uentry_resetParams (e2, pn);
1616 uentry_resetParams (e2, pn);
1623 ** the form should be:
1625 ** # define newname oldname
1626 ** where oldname refers to a function matching the specification
1632 sRef_setGlobalScope ();
1633 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
1634 sRef_clearGlobalScope ();
1638 context_setMacroMissingParams ();
1643 /* context_setuentryList (pn); */
1644 usymtab_enterScope ();
1647 cstring_free (fname);
1652 static bool handleSpecial (char *yyt)
1654 char *l = mstring_create (MAX_NAME_LENGTH);
1655 static bool reportcpp = FALSE;
1661 strcpy (l, yyt + 1);
1663 /* Need to safe original l for deallocating. */
1666 l += strlen (yyt) - 1;
1668 while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
1674 olc = cstring_fromChars (ol);
1676 if (cstring_equalPrefix (olc, "pragma"))
1678 char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN));
1679 char *opname = pname;
1680 char *ptr = ol + 6; /* pragma is six characters, plus space */
1684 /* skip whitespace */
1685 while (((c = *ptr) != '\0') && isspace (c))
1691 while (((c = *ptr) != '\0') && !isspace (c))
1695 if (len > MAX_PRAGMA_LEN)
1706 if (len == PRAGMA_LEN_EXPAND
1707 && mstring_equal (opname, PRAGMA_EXPAND))
1709 cstring exname = cstring_undefined;
1713 while (((c = *ptr) != '\0') && !isspace (c))
1715 exname = cstring_appendChar (exname, c);
1720 ue = usymtab_lookupExposeGlob (exname);
1722 if (uentry_isExpandedMacro (ue))
1724 if (fileloc_isPreproc (uentry_whereDefined (ue)))
1726 fileloc_setColumn (g_currentloc, 1);
1727 uentry_setDefined (ue, g_currentloc);
1731 cstring_free (exname);
1734 else if (cstring_equalPrefix (olc, "ident"))
1736 /* Some pre-processors will leave these in the code. Ignore rest of line */
1739 ** Yuk...Win32 filenames can have spaces in them...we need to read
1740 ** to the matching end quote.
1742 else if ((sscanf (ol, "line %d \"", &lineno) == 1)
1743 || (sscanf (ol, " %d \"", &lineno) == 1))
1749 /*@access cstring@*/
1750 while (*tmp != '\"' && *tmp != '\0')
1755 llassert (*tmp == '\"');
1761 while (*tmp != '\"' && *tmp != '\0')
1766 llassert (*tmp == '\"');
1770 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
1773 ** DOS-like path delimiters get delivered in pairs, something like
1774 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
1775 ** remove the pre dirs yet as we usually specify tmp paths relative
1776 ** to the current directory, so tmp files would not get found in
1777 ** the hash table. If this method fails we try it again later.
1784 ** Skip past the drive marker.
1787 if (strchr (stmp, ':') != NULL)
1789 stmp = strchr (stmp, ':') + 1;
1792 while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
1794 if (*(stmp+1) == CONNECTCHAR)
1796 memmove (stmp, stmp+1, strlen (stmp));
1802 fid = fileTable_lookupBase (context_fileTable (), fname);
1803 if (!(fileId_isValid (fid)))
1805 fname = removePreDirs (fname);
1806 fid = fileTable_lookupBase (context_fileTable (), fname);
1809 # else /* !defined(OS2) && !defined(MSDOS) */
1810 fname = removePreDirs (fname);
1811 fid = fileTable_lookupBase (context_fileTable (), fname);
1812 # endif /* !defined(OS2) && !defined(MSDOS) */
1814 if (!(fileId_isValid (fid)))
1816 if (context_inXHFile ())
1818 fid = fileTable_addXHFile (context_fileTable (), fname);
1820 else if (isHeaderFile (fname))
1822 fid = fileTable_addHeaderFile (context_fileTable (), fname);
1826 fid = fileTable_addFile (context_fileTable (), fname);
1830 setFileLine (fid, lineno);
1831 /*@noaccess cstring@*/
1833 else if ((sscanf (ol, "line %d", &lineno) == 1)
1834 || (sscanf (ol, " %d", &lineno) == 1))
1836 setLine (lineno); /* next line is <cr> */
1840 if (mstring_equal (ol, "")) {
1841 DPRINTF (("Empty pp command!"));
1843 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
1844 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
1853 llbug (message ("File contains preprocessor command: #%s",
1854 cstring_fromChars (ol)));
1867 static int handleLlSpecial ()
1871 char *s = mstring_createEmpty ();
1877 loc = fileloc_copy (g_currentloc);
1878 DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
1880 while (((ic = ninput ()) != 0) && isalpha (ic))
1883 s = mstring_append (s, c);
1887 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
1890 if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
1894 llassert (ic == AFTER_COMMENT_MARKER[1]);
1900 return QNOMODS; /* special token no modifications token */
1904 DPRINTF (("Coment marker: %s", os));
1905 tok = commentMarkerToken (cstring_fromChars (os));
1909 tokLength = charsread;
1916 DPRINTF (("Not a comment marker..."));
1917 /* Add rest of the comment */
1919 if (ic != 0 && ic != EOF)
1923 s = mstring_append (s, c);
1926 while (((ic = ninput ()) != 0) && (ic != EOF)
1927 && (ic != AFTER_COMMENT_MARKER[0]))
1930 s = mstring_append (s, c);
1935 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
1937 if (ic == AFTER_COMMENT_MARKER[0])
1940 llassert ((char) nc == AFTER_COMMENT_MARKER[1]);
1946 while (*s == ' ' || *s == '\t' || *s == '\n')
1951 if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
1955 while (c == '-' || c == '+' || c == '=')
1957 ynm set = ynm_fromCodeChar (c);
1962 thisflag = cstring_fromChars (s);
1964 while ((c = *s) != '\0' && (c != '-') && (c != '=')
1965 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
1972 if (!context_getFlag (FLG_NOCOMMENTS))
1974 cstring flagname = thisflag;
1975 flagcode fflag = identifyFlag (flagname);
1977 if (flagcode_isSkip (fflag))
1981 else if (flagcode_isInvalid (fflag))
1983 if (isMode (flagname))
1985 if (ynm_isMaybe (set))
1990 ("Semantic comment attempts to restore flag %s. "
1991 "A mode flag cannot be restored.",
1996 context_setMode (flagname);
2002 (FLG_UNRECOGFLAGCOMMENTS,
2003 message ("Unrecognized option in semantic comment: %s",
2008 else if (flagcode_isGlobalFlag (fflag))
2013 ("Semantic comment attempts to set global flag %s. "
2014 "A global flag cannot be set locally.",
2020 context_fileSetFlag (fflag, set);
2022 if (flagcode_hasArgument (fflag))
2024 if (ynm_isMaybe (set))
2029 ("Semantic comment attempts to restore flag %s. "
2030 "A flag for setting a value cannot be restored.",
2035 { /* cut-and-pastied from llmain...blecch */
2036 cstring extra = cstring_undefined;
2042 rest = mstring_copy (s);
2046 while ((rchar = *rest) != '\0'
2047 && (isspace (rchar)))
2053 while ((rchar = *rest) != '\0'
2054 && !isspace (rchar))
2056 extra = cstring_appendChar (extra, rchar);
2063 if (cstring_isUndefined (extra))
2068 ("Flag %s (in semantic comment) must be followed by an argument",
2069 flagcode_unparse (fflag)));
2075 if (flagcode_hasValue (fflag))
2077 setValueFlag (fflag, extra);
2079 else if (flagcode_hasString (fflag))
2081 setStringFlag (fflag, extra);
2098 while ((c == ' ') || (c == '\t') || (c == '\n'))
2104 if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
2106 DPRINTF (("Here adding comment: %s", os));
2107 context_addComment (cstring_fromCharsNew (os));
2119 annotationInfo ainfo;
2121 while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
2133 t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
2134 macrocode = tokenMacroCode (cstring_fromChars (t));
2136 if (macrocode != BADTOK)
2138 tokLength = mstring_length (t);
2144 if (macrocode == SKIPTOK)
2152 ainfo = context_lookupAnnotation (cstring_fromChars (os));
2154 if (annotationInfo_isDefined (ainfo)) {
2155 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
2156 /*@i324@*/ yylval.annotation = ainfo;
2164 if (context_inHeader ())
2171 if ((context_inMacro () || context_inGlobalContext ())
2172 && macrocode != SKIPTOK
2173 && !isArtificial (cstring_fromChars (os)))
2175 DPRINTF (("Add comment: %s", os));
2176 context_addComment (cstring_fromCharsNew (os));
2189 if (mstring_equal (t, "ignore"))
2191 if (!context_getFlag (FLG_NOCOMMENTS))
2193 context_enterSuppressRegion ();
2196 else if ((*t == 'i' || *t == 't')
2197 && (*(t + 1) == '\0'))
2199 if (!context_getFlag (FLG_NOCOMMENTS)
2200 && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
2202 context_enterSuppressLine (-1); /* infinite suppression */
2205 else if (((*t == 'i') || (*t == 't'))
2206 && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
2208 bool tmpcomment = (*t == 't');
2210 char *tt = t; /* don't mangle t, since it is free'd */
2213 if (lc >= '0' && lc <= '9')
2215 val = (int)(lc - '0');
2218 while (lc >= '0' && lc <= '9')
2227 if (!context_getFlag (FLG_NOCOMMENTS)
2228 && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
2230 context_enterSuppressLine (val);
2233 else if (mstring_equal (t, "end"))
2235 if (!context_getFlag (FLG_NOCOMMENTS))
2237 context_exitSuppressRegion ();
2240 else if (mstring_equal (t, "notfunction"))
2242 ; /* handled by pcpp */
2244 else if (mstring_equal (t, "access"))
2250 while ((c = *s) && (c == ' ' || c == '\t' || c == '\n'))
2260 tname = cstring_fromChars (s);
2262 while ((c = *s) != '\0' && c != ' '
2263 && c != '\t' && c != '\n' && c != ',')
2270 DPRINTF (("Access %s", tname));
2272 if (!context_getFlag (FLG_NOCOMMENTS)
2273 && !context_getFlag (FLG_NOACCESS))
2275 if (usymtab_existsType (tname))
2277 typeId uid = usymtab_getTypeId (tname);
2278 uentry ue = usymtab_getTypeEntry (uid);
2280 if (uentry_isAbstractDatatype (ue))
2282 context_addFileAccessType (uid);
2283 DPRINTF (("Adding access to: %s / %d", tname, uid));
2290 ("Non-abstract type %s used in access comment",
2297 if (!(context_inSuppressRegion ()
2298 || context_inSuppressZone (g_currentloc)))
2303 ("Unrecognized type %s used in access comment",
2315 if (c != ',' && c != ' ')
2321 else if (mstring_equal (t, "noaccess"))
2328 while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n'))
2338 tname = cstring_fromChars (s);
2340 while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
2341 && lc != '\n' && lc != ',')
2348 if (!context_getFlag (FLG_NOCOMMENTS)
2349 && !context_getFlag (FLG_NOACCESS))
2351 if (usymtab_existsType (tname))
2353 typeId tuid = usymtab_getTypeId (tname);
2355 if (context_couldHaveAccess (tuid))
2357 DPRINTF (("Removing access: %s", tname));
2358 context_removeFileAccessType (tuid);
2362 if (!(context_inSuppressRegion ()
2363 || context_inSuppressZone (g_currentloc)))
2365 uentry ue = usymtab_getTypeEntry (tuid);
2367 if (uentry_isAbstractDatatype (ue))
2372 ("Non-accessible abstract type %s used in noaccess comment",
2381 ("Non-abstract type %s used in noaccess comment",
2390 if (!(context_inSuppressRegion ()
2391 || context_inSuppressZone (g_currentloc)))
2396 ("Unrecognized type %s used in noaccess comment",
2408 if (lc != ',' && lc != ' ')
2416 voptgenerror (FLG_UNRECOGCOMMENTS,
2417 message ("Semantic comment unrecognized: %s",
2418 cstring_fromChars (os)), loc);
2429 static /*@only@*/ cstring makeIdentifier (char *s)
2431 char *c = mstring_create (size_toInt (strlen (s)) + 1);
2432 cstring id = cstring_fromChars (c);
2434 while (isalnum (*s) || (*s == '_') || (*s == '$'))
2443 /*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn)
2445 if (!(usymtab_exists (cn)))
2447 fileloc loc = fileloc_createExternal ();
2450 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
2453 uentry ce = uentry_makeUnrecognized (cn, loc);
2455 if (!context_inIterEnd ())
2459 message ("Unrecognized (possibly system) identifier: %q",
2460 uentry_getName (ce)),
2467 return (usymtab_lookup (cn));
2471 ** like, coerceId, but doesn't supercede for iters
2474 /*@observer@*/ uentry coerceIterId (cstring cn)
2476 if (!(usymtab_exists (cn)))
2478 return uentry_undefined;
2481 return (usymtab_lookup (cn));
2484 /*@observer@*/ cstring LastIdentifier ()
2486 return (lastidprocessed);
2489 static int processIdentifier (cstring id)
2493 if (context_getFlag (FLG_GRAMMAR))
2495 lldiagmsg (message ("Process identifier: %s", id));
2498 context_clearJustPopped ();
2499 lastidprocessed = id;
2501 if (context_inFunctionHeader ())
2503 int tok = commentMarkerToken (id);
2504 DPRINTF (("in function decl..."));
2512 tok = tokenMacroCode (id);
2520 annotationInfo ainfo;
2522 if (expectingMetaStateName)
2524 metaStateInfo msinfo = context_lookupMetaStateInfo (id);
2526 if (metaStateInfo_isDefined (msinfo))
2528 yylval.msinfo = msinfo;
2529 return METASTATE_NAME;
2533 DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id)));
2537 ainfo = context_lookupAnnotation (id);
2539 if (annotationInfo_isDefined (ainfo))
2541 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
2542 /*@i324@*/ yylval.annotation = ainfo;
2547 DPRINTF (("Not annotation: %s", id));
2553 /* Consider handling: Defined by C99 as static const char __func__[] */
2555 if (context_getFlag (FLG_GNUEXTENSIONS))
2559 if (cstring_equalLit (id, "__stdcall")
2560 || cstring_equalLit (id, "__cdecl")
2561 || cstring_equalLit (id, "__extension__"))
2565 else if (cstring_equalLit (id, "__volatile__"))
2569 else if (cstring_equalLit (id, "__signed"))
2573 else if (cstring_equalLit (id, "__unsigned"))
2577 else if (cstring_equalLit (id, "__const__"))
2581 else if (cstring_equalLit (id, "__alignof__"))
2583 tok = CALIGNOF; /* alignof is parsed like sizeof */
2585 else if (cstring_equalLit (id, "__FUNCTION__")
2586 || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
2588 /* These tokens hold the name of the current function as strings */
2589 yylval.expr = exprNode_stringLiteral (id, fileloc_copy (g_currentloc));
2591 lastWasString = TRUE;
2595 else if (cstring_equalLit (id, "__attribute__")
2596 || cstring_equalLit (id, "__asm__")
2597 || cstring_equalLit (id, "_asm")
2598 || cstring_equalLit (id, "__asm")
2599 || cstring_equalLit (id, "__declspec"))
2602 bool useparens = FALSE;
2603 bool usebraces = FALSE;
2604 bool inquote = FALSE;
2605 bool inescape = FALSE;
2608 while ((ic = input ()) != EOF)
2615 else if (ic == '\\')
2619 else if (ic == '\"')
2655 else if (ic == ')' && useparens)
2658 if (depth == 0) break;
2660 else if (ic == '}' && usebraces)
2663 if (depth == 0) break;
2666 && !usebraces && !useparens
2667 && cstring_equalLit (id, "__asm"))
2670 ** We need this because some MS VC++ include files
2671 ** have __asm mov ... }
2672 ** Its a kludge, but otherwise would need to parse
2681 context_incLineno ();
2683 if (cstring_equalLit (id, "__asm")
2684 && !useparens && !usebraces)
2691 llassert ((useparens && ic == ')')
2692 || (usebraces && ic == '}')
2693 || (!useparens && !usebraces));
2697 else if (cstring_equalLit (id, "inline")
2698 || cstring_equalLit (id, "__inline")
2699 || cstring_equalLit (id, "_inline")
2700 || cstring_equalLit (id, "__inline__"))
2711 le = usymtab_lookupSafe (id);
2713 /*@-dependenttrans@*/
2715 if (uentry_isIter (le))
2717 /*@i32@*/ yylval.entry = le;
2720 else if (uentry_isEndIter (le))
2722 /*@i32@*/ yylval.entry = le;
2723 return (ITER_ENDNAME);
2725 else if (uentry_isUndefined (le))
2729 /* avoid parse errors for certain system built ins */
2731 if (g_expectingTypeName && (cstring_firstChar (id) == '_')
2732 && (cstring_secondChar (id) == '_'))
2734 return (TYPE_NAME_OR_ID);
2737 return (NEW_IDENTIFIER);
2739 else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
2741 if (uentry_isDatatype (le))
2744 return (NEW_IDENTIFIER);
2748 /*@i32@*/ yylval.entry = le;
2749 return (IDENTIFIER);
2752 else if (uentry_isDatatype (le))
2754 if (!g_expectingTypeName)
2758 return (NEW_IDENTIFIER);
2762 yylval.ctyp = uentry_getAbstractType (le);
2764 uentry_setUsed (le, g_currentloc);
2770 /*@i32@*/ yylval.entry = le;
2771 return (IDENTIFIER);
2774 /*@=dependenttrans@*/
2777 static bool processHashIdentifier (/*@only@*/ cstring id)
2779 if (context_inMacro () || context_inIterDef () ||
2780 context_inIterEnd ())
2784 context_clearJustPopped ();
2786 lastidprocessed = id;
2787 le = usymtab_lookupSafe (id);
2789 if (uentry_isParam (le) || uentry_isRefParam (le))
2806 static /*@only@*/ exprNode processString ()
2810 char *nl = strchr (yytext, '\n');
2811 cstring ns = cstring_fromCharsNew (yytext);
2815 loc = fileloc_copy (g_currentloc);
2816 addColumn (cstring_length (ns));
2822 loc = fileloc_copy (g_currentloc);
2824 context_incLineno ();
2826 while ((nl = strchr ((nl + 1), '\n')) != NULL)
2828 context_incLineno ();
2834 res = exprNode_stringLiteral (ns, loc);
2844 llassert (*yytext != '\0');
2845 fchar = *(yytext + 1);
2846 if (fchar != '\\') return fchar;
2848 next = *(yytext + 2);
2852 case 'n': return '\n';
2853 case 't': return '\t';
2854 case '\"': return '\"';
2855 case '\'': return '\'';
2856 case '\\': return '\\';
2857 default: return '\0';
2862 double processFloat ()
2864 double ret = atof (yytext);
2875 llassert (yytext[0] == '0'
2876 && (yytext[1] == 'X' || yytext[1] == 'x'));
2878 while (yytext[index] != '\0') {
2880 char c = yytext[index];
2882 if (c >= '0' && c <= '9') {
2883 tval = (int) c - (int) '0';
2884 } else if (c >= 'A' && c <= 'F') {
2885 tval = (int) c - (int) 'A' + 10;
2886 } else if (c >= 'a' && c <= 'f') {
2887 tval = (int) c - (int) 'a' + 10;
2888 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2890 while (yytext[index] != '\0') {
2891 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2896 message ("Invalid character (%c) following specifier in hex constant: %s",
2897 c, cstring_fromChars (yytext)),
2907 message ("Invalid character (%c) in hex constant: %s",
2908 c, cstring_fromChars (yytext)),
2913 val = (val * 16) + tval;
2917 DPRINTF (("Hex constant: %s = %ld", yytext, val));
2922 long processOctal ()
2927 llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
2929 while (yytext[index] != '\0') {
2931 char c = yytext[index];
2933 if (c >= '0' && c <= '7') {
2934 tval = (int) c - (int) '0';
2938 message ("Invalid character (%c) in octal constant: %s",
2939 c, cstring_fromChars (yytext)),
2944 val = (val * 8) + tval;
2948 DPRINTF (("Octal constant: %s = %ld", yytext, val));
2955 return (atol (yytext));
2959 processSpec (int tok)
2961 size_t length = strlen (yytext);
2966 setTokLengthT (length);
2972 context_saveLocation ();
2973 setTokLengthT (length);
2974 return (processIdentifier (makeIdentifier (yytext)));
2978 void cscanner_expectingMetaStateName ()
2980 llassert (!expectingMetaStateName);
2981 llassert (context_inFunctionHeader ());
2982 expectingMetaStateName = TRUE;
2985 void cscanner_clearExpectingMetaStateName ()
2987 llassert (expectingMetaStateName);
2988 expectingMetaStateName = FALSE;