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"
65 # include "cgrammar.h"
66 # include "cgrammar_tokens.h"
68 # include "fileIdList.h"
71 # if defined(OS2) && defined(__IBMC__)
72 /* needed for isatty()... */
76 static bool lastWasString = FALSE;
77 static char savechar = '\0';
80 # define yyinput() (incColumn (), getc (yyin))
84 extern /*@external@*/ int read ();
88 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 int returnInt (ctype, long);
118 static int returnFloat (ctype, double);
119 static int returnChar (char);
120 static void setTokLength (int) /*@modifies g_currentloc@*/ ;
121 static void setTokLengthT (size_t) /*@modifies g_currentloc@*/ ;
123 static void advanceLine (void)
130 # define RETURN_INT(c,i) \
131 do { lastWasString = FALSE; \
132 return (returnInt (c, i)); } while (FALSE)
134 # define RETURN_FLOAT(c,f) \
135 do { lastWasString = FALSE; \
136 return (returnFloat (c, f)); \
139 # define RETURN_CHAR(c) \
140 do { lastWasString = FALSE; \
141 return (returnChar (c)); \
144 # define RETURN_TOK(t) \
145 do { yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, tokLength)); \
147 lastWasString = FALSE; \
148 return (t); } while (FALSE)
150 # define RETURN_TYPE(t, ct) \
151 do { yylval.ctyp = ct; tokLength = 0; return (t); } while (FALSE)
153 /* don't fileloc_decColumn (g_currentloc, tokLength));
154 the string could have \n's in it!
157 # define RETURN_STRING(c) \
158 do { yylval.expr = exprNode_stringLiteral (c, fileloc_decColumn (g_currentloc, tokLength)); \
160 lastWasString = TRUE; \
161 return (CCONSTANT); } while (FALSE)
163 # define RETURN_EXPR(e) \
164 do { yylval.expr = e; \
166 lastWasString = TRUE; \
167 return (CCONSTANT); } while (FALSE)
171 static void setTokLength (int len)
177 static void setTokLengthT (size_t len)
179 setTokLength (size_toInt (len));
182 # include "flex.head"
184 /*@-unrecog@*/ /*@i5343@*/
190 "/*" { llfatalbug (cstring_makeLiteral ("Comment in pre-processor output")); }
192 "#"{Letter}({Letter}|{Digit})* {
193 context_saveLocation ();
194 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
196 if (processHashIdentifier (makeIdentifier (yytext + 1)))
200 /* was nothing! */ /*@i32@*/
201 RETURN_STRING (cstring_makeLiteral ("\"\""));
205 RETURN_STRING (cstring_makeLiteral ("\"\""));
210 if (handleSpecial (yytext))
217 "#" { if (handleSpecial (yytext))
219 setTokLength (1); RETURN_TOK (0);
222 "..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); }
223 "break" { setTokLength (5); RETURN_TOK (BREAK); }
224 "case" { setTokLength (4); RETURN_TOK (CASE); }
225 "continue" { setTokLength (8); RETURN_TOK (CONTINUE); }
226 "default" { setTokLength (7); RETURN_TOK (DEFAULT); }
227 "do" { setTokLength (2); RETURN_TOK (DO); }
228 "else" { setTokLength (4); RETURN_TOK (CELSE); }
229 "for" { setTokLength (3); RETURN_TOK (CFOR); }
230 "goto" { setTokLength (4); RETURN_TOK (GOTO); }
231 "if" { setTokLength (2); RETURN_TOK (CIF); }
232 "return" { setTokLength (6); RETURN_TOK (RETURN); }
233 "sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); }
234 "offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); }
235 "switch" { setTokLength (6); RETURN_TOK (SWITCH); }
236 "while" { setTokLength (5); RETURN_TOK (WHILE); }
237 "va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); }
238 "va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); }
240 /* gcc extension...this might not be appropriate */
241 setTokLength (6); RETURN_TOK (QINLINE); }
243 "struct" { setTokLength (6); RETURN_TOK (CSTRUCT); }
244 "typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); }
246 "union" { setTokLength (5); RETURN_TOK (CUNION); }
247 "enum" { setTokLength (4); RETURN_TOK (CENUM); }
249 "void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); }
250 "int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); }
251 "double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); }
252 "char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); }
253 "float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); }
255 "long" { setTokLength (4); RETURN_TOK (QLONG); }
256 "short" { setTokLength (5); RETURN_TOK (QSHORT); }
257 "unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); }
258 "signed" { setTokLength (6); RETURN_TOK (QSIGNED); }
260 "volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); }
261 "const" { setTokLength (5); RETURN_TOK (QCONST); }
263 /* some systems expect this! [gack!] */
264 "__const" { setTokLength (7); RETURN_TOK (QCONST); }
266 "extern" { setTokLength (6); RETURN_TOK (QEXTERN); }
267 "auto" { setTokLength (4); RETURN_TOK (QAUTO); }
268 "register" { setTokLength (8); RETURN_TOK (QREGISTER); }
269 "static" { setTokLength (6); RETURN_TOK (QSTATIC); }
271 \"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
272 "out" { return (processSpec (QOUT)); }
273 "in" { return (processSpec (QIN)); }
274 "partial" { return (processSpec (QPARTIAL)); }
275 "special" { return (processSpec (QSPECIAL)); }
276 "anytype" { return (processSpec (QANYTYPE)); }
277 "integraltype" { return (processSpec (QINTEGRALTYPE)); }
278 "unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); }
279 "signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); }
280 "keep" { return (processSpec (QKEEP)); }
281 "null" { return (processSpec (QNULL)); }
282 "notnull" { return (processSpec (QNOTNULL)); }
283 "isnull" { return (processSpec (QISNULL)); }
284 "truenull" { return (processSpec (QTRUENULL)); }
285 "falsenull" { return (processSpec (QFALSENULL)); }
286 "relnull" { return (processSpec (QRELNULL)); }
287 "reldef" { return (processSpec (QRELDEF)); }
288 "exposed" { return (processSpec (QEXPOSED)); }
289 "newref" { return (processSpec (QNEWREF)); }
290 "tempref" { return (processSpec (QTEMPREF)); }
291 "killref" { return (processSpec (QKILLREF)); }
292 "refcounted" { return (processSpec (QREFCOUNTED)); }
293 "checked" { return (processSpec (QCHECKED)); }
294 "checkmod" { return (processSpec (QCHECKMOD)); }
295 "checkedstrict" { return (processSpec (QCHECKEDSTRICT)); }
296 "unchecked" { return (processSpec (QUNCHECKED)); }
297 "only" { return (processSpec (QONLY)); }
298 "owned" { return (processSpec (QOWNED)); }
299 "observer" { return (processSpec (QOBSERVER)); }
300 "dependent" { return (processSpec (QDEPENDENT)); }
301 "unused" { return (processSpec (QUNUSED)); }
302 "external" { return (processSpec (QEXTERNAL)); }
303 "sef" { return (processSpec (QSEF)); }
304 "shared" { return (processSpec (QSHARED)); }
305 "yield" { return (processSpec (QYIELD)); }
306 "undef" { return (processSpec (QUNDEF)); }
307 "killed" { return (processSpec (QKILLED)); }
308 "nullterminated" { return (processSpec (QNULLTERMINATED));}
309 "MaxSet" { return (processSpec (QMAXSET));}
310 "MaxRead" { return (processSpec (QMAXREAD));}
312 {Letter}({Letter}|{Digit})* { int tok;
313 context_saveLocation ();
314 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
315 tok = processIdentifier (makeIdentifier (yytext));
321 0[xX]{H}+ { setTokLengthT (mstring_length (yytext));
322 RETURN_INT (ctype_int, processHex ()); /* evs 2000-05-17 was ctype_uint */
324 0[xX]{H}+{L} { setTokLengthT (mstring_length (yytext));
325 RETURN_INT (ctype_lint, processHex ()); }
326 0[xX]{H}+{L}{L} { setTokLengthT (mstring_length (yytext));
327 RETURN_INT (ctype_llint, processHex ()); }
328 0[xX]{H}+{U} { setTokLengthT (mstring_length (yytext));
329 RETURN_INT (ctype_uint, processHex ()); }
330 0[xX]{H}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
331 RETURN_INT (ctype_ulint, processHex ()); }
332 0[xX]{H}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
333 RETURN_INT (ctype_ullint, processHex ()); }
334 0[xX]{H}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
335 RETURN_INT (ctype_ullint, processHex ()); }
336 0{Digit}+ { setTokLengthT (mstring_length (yytext));
337 RETURN_INT (ctype_int, processOctal ()); }
338 0{Digit}+{U} { setTokLengthT (mstring_length (yytext));
339 RETURN_INT (ctype_uint, processOctal ()); }
340 0{Digit}+{L} { setTokLengthT (mstring_length (yytext));
341 RETURN_INT (ctype_lint, processOctal ()); }
342 0{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
343 RETURN_INT (ctype_llint, processOctal ()); }
344 0{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
345 RETURN_INT (ctype_ulint, processOctal ()); }
346 0{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
347 RETURN_INT (ctype_ullint, processOctal ()); }
348 0{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
349 RETURN_INT (ctype_ullint, processOctal ()); }
350 {Digit}+ { setTokLengthT (mstring_length (yytext));
351 RETURN_INT (ctype_int, processDec ()); }
352 {Digit}+{U} { setTokLengthT (mstring_length (yytext));
353 RETURN_INT (ctype_uint, processDec ()); }
354 {Digit}+{L} { setTokLengthT (mstring_length (yytext));
355 RETURN_INT (ctype_lint, processDec ()); }
356 {Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
357 RETURN_INT (ctype_llint, processDec ()); }
358 {Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
359 RETURN_INT (ctype_ulint, processDec ()); }
360 {Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
361 RETURN_INT (ctype_ullint, processDec ()); }
362 {Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
363 RETURN_INT (ctype_ullint, processDec ()); }
364 '(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
365 RETURN_CHAR (processChar ()); }
366 {Digit}+{E}[fF] { setTokLengthT (mstring_length (yytext));
367 RETURN_FLOAT (ctype_float, processFloat ()); }
368 {Digit}+{E}[lL] { setTokLengthT (mstring_length (yytext));
369 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
370 {Digit}+{E} { setTokLengthT (mstring_length (yytext));
371 RETURN_FLOAT (ctype_double, processFloat ()); }
373 {Digit}*"."{Digit}+({E})?[fF] { setTokLengthT (mstring_length (yytext));
374 RETURN_FLOAT (ctype_float, processFloat ()); }
375 {Digit}*"."{Digit}+({E})?[lL] { setTokLengthT (mstring_length (yytext));
376 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
377 {Digit}*"."{Digit}+({E})? { setTokLengthT (mstring_length (yytext));
378 RETURN_FLOAT (ctype_double, processFloat ()); }
380 {Digit}+"."{Digit}*({E})?[fF] { setTokLengthT (mstring_length (yytext));
381 RETURN_FLOAT (ctype_float, processFloat ()); }
382 {Digit}+"."{Digit}*({E})?[lL] { setTokLengthT (mstring_length (yytext));
383 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
384 {Digit}+"."{Digit}*({E})? { setTokLengthT (mstring_length (yytext));
385 RETURN_FLOAT (ctype_double, processFloat ()); }
387 ">>=" { setTokLength (3); RETURN_TOK (RIGHT_ASSIGN); }
388 "<<=" { setTokLength (3); RETURN_TOK (LEFT_ASSIGN); }
389 "+=" { setTokLength (2); RETURN_TOK (ADD_ASSIGN); }
390 "-=" { setTokLength (2); RETURN_TOK (SUB_ASSIGN); }
391 "*=" { setTokLength (2); RETURN_TOK (MUL_ASSIGN); }
392 "/=" { setTokLength (2); RETURN_TOK (DIV_ASSIGN); }
393 "%=" { setTokLength (2); RETURN_TOK (MOD_ASSIGN); }
394 "&=" { setTokLength (2); RETURN_TOK (AND_ASSIGN); }
395 "^=" { setTokLength (2); RETURN_TOK (XOR_ASSIGN); }
396 "|=" { setTokLength (2); RETURN_TOK (OR_ASSIGN); }
397 ">>" { setTokLength (2); RETURN_TOK (RIGHT_OP); }
398 "<<" { setTokLength (2); RETURN_TOK (LEFT_OP); }
399 "++" { setTokLength (2); RETURN_TOK (INC_OP); }
400 "--" { setTokLength (2); RETURN_TOK (DEC_OP); }
401 "->" { setTokLength (2); RETURN_TOK (ARROW_OP); }
402 "&&" { setTokLength (2); RETURN_TOK (AND_OP); }
403 "||" { setTokLength (2); RETURN_TOK (OR_OP); }
404 "<=" { setTokLength (2); RETURN_TOK (LE_OP); }
405 ">=" { setTokLength (2); RETURN_TOK (GE_OP); }
406 "==" { setTokLength (2); RETURN_TOK (EQ_OP); }
407 "!=" { setTokLength (2); RETURN_TOK (NE_OP); }
408 ";" { setTokLength (1); RETURN_TOK (TSEMI); }
409 "{" { setTokLength (1); RETURN_TOK (TLBRACE); }
410 "}" { setTokLength (1); RETURN_TOK (TRBRACE); }
411 "," { setTokLength (1); RETURN_TOK (TCOMMA); }
412 ":" { setTokLength (1); RETURN_TOK (TCOLON); }
413 "=" { setTokLength (1); RETURN_TOK (TASSIGN); }
414 "(" { setTokLength (1); RETURN_TOK (TLPAREN); }
415 ")" { setTokLength (1); RETURN_TOK (TRPAREN); }
416 "[" { setTokLength (1); RETURN_TOK (TLSQBR); }
417 "]" { setTokLength (1); RETURN_TOK (TRSQBR); }
418 "." { setTokLength (1); RETURN_TOK (TDOT); }
419 "&" { setTokLength (1); RETURN_TOK (TAMPERSAND); }
420 "!" { setTokLength (1); RETURN_TOK (TEXCL); }
423 "~" { setTokLength (1); RETURN_TOK (TTILDE); }
424 "-" { setTokLength (1); RETURN_TOK (TMINUS); }
425 "+" { setTokLength (1); RETURN_TOK (TPLUS); }
426 "*" { setTokLength (1); RETURN_TOK (TMULT); }
427 "/" { setTokLength (1); RETURN_TOK (TDIV); }
428 "%" { setTokLength (1); RETURN_TOK (TPERCENT); }
429 "<" { setTokLength (1); RETURN_TOK (TLT); }
430 ">" { setTokLength (1); RETURN_TOK (TGT); }
431 "^" { setTokLength (1); RETURN_TOK (TCIRC); }
432 "|" { setTokLength (1); RETURN_TOK (TBAR); }
433 "?" { setTokLength (1); RETURN_TOK (TQUEST); }
436 "/\\" { setTokLength (1); RETURN_TOK (TCAND); }
439 [ \t\v\f] { incColumn (); }
440 \n { context_incLineno ();
443 continueLine = FALSE;
447 if (context_inMacro ())
449 /* Don't use RETURN_TOK */
450 yylval.tok = lltok_create (TENDMACRO, g_currentloc);
451 lastWasString = FALSE;
456 "@@MR@@" { setTokLength (6);
458 if (processMacro ()) {
459 if (context_inIterDef ())
461 RETURN_TOK (LLMACROITER);
463 if (context_inIterEnd ())
465 RETURN_TOK (LLMACROEND);
467 if (context_inMacro ())
469 RETURN_TOK (LLMACRO);
473 "@QLMR" { if (context_inHeader () || context_inFunction ())
479 int nspchar = ninput ();
483 ** This is a hack to get the column number correct.
486 llassert (nspchar >= '0' && nspchar <= '9');
488 nspaces = nspchar - '0';
490 setTokLength (5 + nspaces);
494 if (context_inIterDef ())
496 RETURN_TOK (LLMACROITER);
498 if (context_inIterEnd ())
500 RETURN_TOK (LLMACROEND);
502 if (context_inMacro ())
504 RETURN_TOK (LLMACRO);
509 "@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); }
510 "@.FA" { setTokLength (4); lldiagmsg (message ("Access types: %q", typeIdSet_unparse (context_fileAccessTypes ()))); }
511 "@.F" { setTokLength (3);
512 lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc)));
514 "@.L" { setTokLength (3); usymtab_printLocal (); }
515 "@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); }
516 "@.C" { setTokLength (3); lldiagmsg (context_unparse ()); }
517 "@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); }
518 "@.G" { setTokLength (3); usymtab_printGuards (); }
519 "@.S" { setTokLength (3); usymtab_printOut (); }
520 "@.X" { setTokLength (3); usymtab_printAll (); }
521 "@.Z" { setTokLength (3); usymtab_printComplete (); }
522 "@.T" { setTokLength (3); usymtab_printTypes (); }
523 "@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); }
524 "@.M" { setTokLength (3);
525 lldiagmsg (message ("Can modify: %q",
526 sRefSet_unparse (context_modList ())));
528 "%{" { /* BEFORE_COMMENT_MARKER */
530 incColumn (); incColumn ();
531 tok = handleLlSpecial ();
535 if (tok == CANNOTATION) {
538 /* Beware - this bashes yylval! */
543 "%}" { /* AFTER_COMMENT_MARKER */
546 RETURN_TOK (QENDMACRO); }
547 "\\" { incColumn (); continueLine = TRUE; }
549 if ((int) *yytext == 13 ) {
554 message ("Invalid character (ascii: %d), skipping character",
563 /*@null@*/ /*@observer@*/ char *name;
568 ** These tokens are followed by syntax that is parsed by the
572 struct skeyword s_parsetable[] = {
573 { "modifies", QMODIFIES } ,
574 { "globals", QGLOBALS } ,
577 { "constant", QCONSTANT } ,
578 { "function", QFUNCTION } ,
580 { "defines", QDEFINES } ,
582 { "allocates", QALLOCATES } ,
584 { "releases", QRELEASES } ,
585 { "pre", QPRECLAUSE } ,
586 { "post", QPOSTCLAUSE } ,
587 {"setBufferSize", QSETBUFFERSIZE},
588 {"LRequires", QBUFFERCONSTRAINT},
589 {"LEnsures", QENSURESCONSTRAINT},
590 {"setStringLength", QSETSTRINGLENGTH},
591 {"testinRange", QTESTINRANGE},
592 { "requires", QPRECLAUSE } ,
593 { "ensures", QPOSTCLAUSE } ,
598 ** These tokens are either stand-alone tokens, or followed by
599 ** token-specific text.
602 struct skeyword s_keytable[] = {
603 { "anytype", QANYTYPE } ,
604 { "integraltype", QINTEGRALTYPE } ,
605 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,
606 { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,
610 { "owned", QOWNED } ,
611 { "dependent", QDEPENDENT } ,
612 { "partial", QPARTIAL } ,
613 { "special", QSPECIAL } ,
614 { "truenull", QTRUENULL } ,
615 { "falsenull", QFALSENULL } ,
618 { "notnull", QNOTNULL } ,
619 { "abstract", QABSTRACT } ,
620 { "concrete", QCONCRETE } ,
621 { "mutable", QMUTABLE } ,
622 { "immutable", QIMMUTABLE } ,
623 { "unused", QUNUSED } ,
624 { "external", QEXTERNAL } ,
626 { "unique", QUNIQUE } ,
627 { "returned", QRETURNED } ,
628 { "exposed", QEXPOSED } ,
629 { "refcounted", QREFCOUNTED } ,
631 { "newref", QNEWREF } ,
632 { "tempref", QTEMPREF } ,
633 { "killref", QKILLREF } ,
635 { "relnull", QRELNULL } ,
636 { "nullterminated", QNULLTERMINATED },
637 { "setBufferSize", QSETBUFFERSIZE },
638 { "LRequires", QBUFFERCONSTRAINT },
639 { "LEnsures", QENSURESCONSTRAINT },
640 { "testInRange", QTESTINRANGE},
641 { "MaxSet", QMAXSET},
642 { "MaxRead", QMAXREAD},
643 { "reldef", QRELDEF } ,
644 { "observer", QOBSERVER } ,
645 { "exits", QEXITS } ,
646 { "mayexit", QMAYEXIT } ,
647 { "trueexit", QTRUEEXIT } ,
648 { "falseexit", QFALSEEXIT } ,
649 { "neverexit", QNEVEREXIT } ,
651 { "shared", QSHARED } ,
653 { "unchecked", QUNCHECKED } ,
654 { "checked", QCHECKED } ,
655 { "checkmod", QCHECKMOD } ,
656 { "checkedstrict", QCHECKEDSTRICT } ,
657 { "innercontinue", QINNERCONTINUE } ,
658 { "innerbreak", QINNERBREAK } ,
659 { "loopbreak", QLOOPBREAK } ,
660 { "switchbreak", QSWITCHBREAK } ,
661 { "safebreak", QSAFEBREAK } ,
662 { "fallthrough", QFALLTHROUGH } ,
663 { "l_fallthrou", QLINTFALLTHROUGH } ,
664 { "l_fallth", QLINTFALLTHRU } ,
665 { "notreached", QNOTREACHED } ,
666 { "l_notreach", QLINTNOTREACHED } ,
667 { "printflike", QPRINTFLIKE } ,
668 { "l_printfli", QLINTPRINTFLIKE } ,
669 { "scanflike", QSCANFLIKE } ,
670 { "messagelike", QMESSAGELIKE } ,
671 { "l_argsus", QARGSUSED } ,
676 ** would be better if these weren't hard coded...
679 static bool isArtificial (cstring s)
681 return (cstring_equalLit (s, "modifies")
682 || cstring_equalLit (s, "globals")
683 || cstring_equalLit (s, "warn")
684 || cstring_equalLit (s, "alt"));
687 void swallowMacro (void)
690 bool skipnext = FALSE;
692 while ((i = lminput ()) != EOF)
709 reader_checkUngetc (i, yyin);
717 reader_checkUngetc (i, yyin);
721 static int commentMarkerToken (cstring s)
725 while (s_parsetable[i].name != NULL)
727 DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name));
729 if (cstring_equalLit (s, s_parsetable[i].name))
731 return s_parsetable[i].token;
740 static int tokenMacroCode (cstring s)
744 while (s_keytable[i].name != NULL)
746 if (cstring_equalLit (s, s_keytable[i].name))
748 if (s_keytable[i].token == QLINTFALLTHROUGH)
751 (FLG_WARNLINTCOMMENTS,
753 ("Traditional lint comment /*FALLTHROUGH*/ used. "
754 "This is interpreted by "
755 "LCLint in the same way as most Unix lints, but it is "
756 "preferable to replace it with the /*@fallthrough@*/ "
761 else if (s_keytable[i].token == QLINTFALLTHRU)
764 (FLG_WARNLINTCOMMENTS,
766 ("Traditional lint comment /*FALLTHRU*/ used. "
767 "This is interpreted by "
768 "LCLint in the same way as most Unix lints, but it is "
769 "preferable to replace it with the /*@fallthrough@*/ "
774 else if (s_keytable[i].token == QLINTNOTREACHED)
777 (FLG_WARNLINTCOMMENTS,
779 ("Traditional lint comment /*NOTREACHED*/ used. "
780 "This is interpreted by "
781 "LCLint in the same way as most Unix lints, but it is "
782 "preferable to replace it with the /*@notreached@*/ "
783 "semantic comment."),
788 else if (s_keytable[i].token == QPRINTFLIKE)
790 setSpecialFunction (qual_createPrintfLike ());
793 else if (s_keytable[i].token == QLINTPRINTFLIKE)
796 (FLG_WARNLINTCOMMENTS,
798 ("Traditional lint comment /*PRINTFLIKE*/ used. "
799 "This is interpreted by "
800 "LCLint in the same way as most Unix lints, but it is "
801 "preferable to replace it with either /*@printflike@*/, "
802 "/*@scanflike@*/ or /*@messagelike@*/."),
805 setSpecialFunction (qual_createPrintfLike ());
808 else if (s_keytable[i].token == QSCANFLIKE)
810 setSpecialFunction (qual_createScanfLike ());
813 else if (s_keytable[i].token == QMESSAGELIKE)
815 setSpecialFunction (qual_createMessageLike ());
818 else if (s_keytable[i].token == QARGSUSED)
821 (FLG_WARNLINTCOMMENTS,
823 ("Traditional lint comment /*ARGSUSED*/ used. "
824 "This is interpreted by "
825 "LCLint in the same way as most Unix lints, but it is "
826 "preferable to use /*@unused@*/ annotations on "
827 "the unused parameters."),
834 return s_keytable[i].token;
843 static int lminput ()
845 if (savechar == '\0')
852 int save = (int) savechar;
858 static void lmsavechar (char c)
860 if (savechar == '\0') savechar = c;
863 llbuglit ("lmsavechar: override");
867 static int returnFloat (ctype ct, double f)
869 yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext),
870 fileloc_decColumn (g_currentloc, tokLength));
875 static int returnInt (ctype ct, long i)
879 if (ctype_equal (ct, ctype_int))
883 c = context_typeofZero ();
887 c = context_typeofOne ();
891 yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext),
892 fileloc_decColumn (g_currentloc, tokLength), i);
897 static int returnChar (char c)
899 yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext),
900 fileloc_decColumn (g_currentloc, tokLength));
909 if (c != EOF && ((char)c == '\n'))
911 context_incLineno ();
917 static char macro_nextChar ()
919 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
924 c = char_fromInt (ic);
926 if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
930 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
932 ; /* skip to newline */
935 context_incLineno ();
939 return macro_nextChar ();
946 else /* if (c == '@') */
948 llassert (FALSE); /*@i23@*/
949 if (handleLlSpecial () != BADTOK)
951 llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
954 return macro_nextChar ();
957 else if (!in_escape && c == '\"')
959 in_quote = !in_quote;
961 else if (!in_escape && c == '\'')
965 else if ((in_quote || in_char) && c == '\\')
967 in_escape = !in_escape;
969 else if ((in_quote || in_char) && in_escape)
973 else if (!in_quote && c == '/')
977 if ((c2 = char_fromInt (lminput ())) == '*')
981 while ((c2 = char_fromInt (lminput ())) != '\0'
982 && c2 != '\n' && c2 != '*')
989 while ((c2 = char_fromInt (lminput ())) != '\0'
1002 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1006 return macro_nextChar ();
1010 /*** putchar does not work! why? puts to stdio...??! ***/
1018 ** keeps semantic comments
1021 static char macro_nextCharC ()
1023 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
1026 c = char_fromInt (lminput ());
1028 if (!in_quote && !in_char && c == '\\')
1030 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
1032 ; /* skip to newline */
1035 context_incLineno ();
1039 return macro_nextCharC ();
1046 else if (!in_escape && c == '\"')
1048 in_quote = !in_quote;
1050 else if (!in_escape && c == '\'')
1054 else if ((in_quote || in_char) && c == '\\')
1056 in_escape = !in_escape;
1058 else if ((in_quote || in_char) && in_escape)
1062 else if (!in_quote && c == '/')
1066 if ((c2 = char_fromInt (lminput ())) == '*')
1070 while ((c2 = char_fromInt (lminput ())) != '\0'
1071 && c2 != '\n' && c2 != '*')
1078 while ((c2 = char_fromInt (lminput ())) != '\0'
1091 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1095 return macro_nextCharC ();
1106 ** skips whitespace (handles line continuations)
1107 ** returns first non-whitespace character
1110 static char skip_whitespace ()
1114 while ((c = macro_nextChar ()) == ' ' || c == '\t')
1122 static void handleMacro ()
1124 cstring mac = cstring_undefined;
1128 while (currentColumn () > 2)
1130 mac = cstring_appendChar (mac, ' ');
1134 c = macro_nextCharC ();
1136 if (c >= '0' && c <= '9')
1140 for (i = 0; i < ((c - '0') + 1); i++)
1142 mac = cstring_appendChar (mac, ' ');
1150 while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
1152 mac = cstring_appendChar (mac, c);
1156 macrocode = tokenMacroCode (mac);
1158 if (macrocode == BADTOK && !isArtificial (mac))
1160 context_addMacroCache (mac);
1169 context_incLineno ();
1173 static bool processMacro (void)
1178 cstring fname = cstring_undefined;
1180 bool isspecfcn = FALSE;
1181 bool isiter = FALSE;
1182 bool skipparam = FALSE;
1183 bool isenditer = FALSE;
1184 bool unknownm = FALSE;
1185 bool hasParams = FALSE;
1186 bool emptyMacro = FALSE;
1187 char c = skip_whitespace ();
1188 fileloc loc = fileloc_noColumn (g_currentloc);
1190 /* are both of these necessary? what do they mean? */
1191 uentryList specparams = uentryList_undefined;
1192 uentryList pn = uentryList_undefined;
1194 context_resetMacroMissingParams ();
1196 if (c == '\0' || c == '\n')
1198 llcontbug (cstring_makeLiteral ("Bad macro"));
1203 fname = cstring_appendChar (fname, c);
1205 while ((c = macro_nextChar ()) != '(' && c != '\0'
1206 && c != ' ' && c != '\t' && c != '\n')
1208 fname = cstring_appendChar (fname, c);
1211 if (c == ' ' || c == '\t' || c == '\n')
1217 while (c == ' ' || c == '\t')
1219 c = macro_nextChar ();
1233 hasParams = (c == '(');
1236 if (usymtab_exists (fname))
1238 e2 = usymtab_lookupExpose (fname);
1239 ct = uentry_getType (e2);
1242 if (uentry_isCodeDefined (e2)
1243 && fileloc_isUser (uentry_whereDefined (e2)))
1247 message ("Macro %s already defined", fname),
1250 uentry_showWhereDefined (e2);
1251 uentry_clearDefined (e2);
1254 if (uentry_isFunction (e2))
1256 uentry_setType (e2, ctype_unknown);
1259 context_enterUnknownMacro (e2);
1263 context_enterConstantMacro (e2);
1268 if (uentry_isForward (e2) && uentry_isFunction (e2))
1275 ("Parameterized macro has no prototype or specification: %s ",
1280 uentry_setType (e2, ctype_unknown);
1281 uentry_setFunctionDefined (e2, loc);
1282 uentry_setUsed (e2, fileloc_undefined);
1283 context_enterUnknownMacro (e2);
1287 if (uentry_isIter (e2))
1290 specparams = uentry_getParams (e2);
1291 noparams = uentryList_size (specparams);
1292 uentry_setDefined (e2, loc);
1293 context_enterIterDef (e2);
1295 else if (uentry_isEndIter (e2))
1298 uentry_setDefined (e2, loc);
1299 context_enterIterEnd (e2); /* don't care about it now */
1300 /* but should parse like an iter! */
1302 else if (uentry_isConstant (e2))
1308 message ("Constant %s implemented as parameterized macro",
1312 uentry_showWhereSpecified (e2);
1313 uentry_setType (e2, ctype_unknown);
1314 uentry_makeVarFunction (e2);
1315 uentry_setDefined (e2, g_currentloc);
1316 uentry_setFunctionDefined (e2, g_currentloc);
1317 context_enterUnknownMacro (e2);
1321 if (!uentry_isSpecified (e2))
1323 fileloc oloc = uentry_whereDeclared (e2);
1325 if (fileloc_isLib (oloc))
1329 else if (fileloc_isUndefined (oloc)
1330 || fileloc_isPreproc (oloc))
1335 (FLG_MACROCONSTDECL,
1337 ("Macro constant %q not declared",
1338 uentry_getName (e2)),
1342 else if (!fileloc_withinLines (oloc, loc, 2))
1343 { /* bogus! will give errors if there is too much whitespace */
1347 ("Macro constant name %s does not match name in "
1348 "previous constant declaration. This constant "
1349 "is declared at %q", fname,
1350 fileloc_unparse (oloc)),
1355 context_enterConstantMacro (e2);
1356 cstring_free (fname);
1362 else if (ctype_isFunction (ct))
1365 specparams = ctype_argsFunction (ct);
1366 noparams = uentryList_size (specparams);
1368 uentry_setFunctionDefined (e2, loc);
1369 context_enterMacro (e2);
1371 else if (uentry_isVar (e2))
1377 message ("Variable %s implemented as parameterized macro",
1381 uentry_showWhereSpecified (e2);
1382 uentry_setType (e2, ctype_unknown);
1383 uentry_makeVarFunction (e2);
1384 uentry_setDefined (e2, g_currentloc);
1385 uentry_setFunctionDefined (e2, g_currentloc);
1386 context_enterUnknownMacro (e2);
1390 uentry ucons = uentry_makeConstant (fname,
1393 if (uentry_isExpandedMacro (e2))
1401 message ("Variable %s implemented by a macro",
1405 uentry_showWhereSpecified (e2);
1409 uentry_setDefined (e2, loc);
1410 uentry_setUsed (ucons, loc);
1412 context_enterConstantMacro (ucons);
1413 uentry_markOwned (ucons);
1414 cstring_free (fname);
1420 if (uentry_isDatatype (e2))
1424 message ("Type implemented as macro: %x",
1425 uentry_getName (e2)),
1426 message ("A type is implemented using a macro definition. A "
1427 "typedef should be used instead."),
1431 /* Must exit scope (not sure why a new scope was entered?) */
1432 usymtab_quietExitScope (g_currentloc);
1433 uentry_setDefined (e2, g_currentloc);
1439 (message ("Unexpanded macro not function or constant: %q",
1440 uentry_unparse (e2)));
1441 uentry_setType (e2, ctype_unknown);
1445 uentry_makeVarFunction (e2);
1446 uentry_setDefined (e2, g_currentloc);
1447 uentry_setFunctionDefined (e2, g_currentloc);
1448 context_enterUnknownMacro (e2);
1460 (FLG_MACROMATCHNAME,
1461 message ("Unexpanded macro %s does not match name of a constant "
1462 "or iter declaration. The name used in the control "
1463 "comment on the previous line should match. "
1464 "(Assuming macro defines a constant.)",
1469 ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
1470 uentry_setUsed (ce, loc); /* perhaps bogus? */
1471 e2 = usymtab_supEntryReturn (ce);
1473 context_enterConstantMacro (e2);
1474 cstring_free (fname);
1479 /* in macros, ( must follow immediatetly after name */
1485 c = skip_whitespace ();
1487 while (c != ')' && c != '\0')
1490 bool suppress = context_inSuppressRegion ();
1491 cstring paramname = cstring_undefined;
1494 ** save the parameter location
1498 context_saveLocation ();
1501 while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
1503 paramname = cstring_appendChar (paramname, c);
1504 c = macro_nextChar ();
1507 if (c == ' ' || c == '\t') c = skip_whitespace ();
1511 c = macro_nextChar ();
1512 if (c == ' ' || c == '\t') c = skip_whitespace ();
1517 llfatalerror (cstring_makeLiteral
1518 ("Bad macro syntax: uentryList"));
1521 if ((isspecfcn || isiter) && (paramno < noparams)
1522 && !uentry_isElipsisMarker (uentryList_getN
1523 (specparams, paramno)))
1525 uentry decl = uentryList_getN (specparams, paramno);
1528 param = uentry_nameCopy (paramname, decl);
1531 uentry_setParam (param);
1532 sr = sRef_makeParam (paramno, uentry_getType (param));
1534 if (sRef_getNullState (sr) == NS_ABSNULL)
1536 ctype pt = ctype_realType (uentry_getType (param));
1538 if (ctype_isUser (pt))
1540 uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
1542 if (uentry_isValid (te))
1544 sRef_setStateFromUentry (sr, te);
1549 sRef_setNullState (sr, NS_UNKNOWN, g_currentloc);
1553 uentry_setSref (param, sr);
1554 uentry_setDeclaredForceOnly (param, context_getSaveLocation ());
1556 skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
1560 fileloc sloc = context_getSaveLocation ();
1562 param = uentry_makeVariableSrefParam
1563 (paramname, ctype_unknown, sRef_makeParam (paramno, ctype_unknown));
1564 cstring_free (paramname);
1566 sRef_setPosNull (uentry_getSref (param), sloc);
1568 uentry_setDeclaredForce (param, sloc);
1571 fileloc_free (sloc);
1576 llassert (!uentry_isElipsisMarker (param));
1580 sRef_makeUnsafe (uentry_getSref (param));
1583 pn = uentryList_add (pn, uentry_copy (param));
1584 usymtab_supEntry (param);
1588 /* don't add param */
1589 uentry_free (param);
1594 (void) macro_nextChar ();
1595 c = skip_whitespace ();
1603 if (isspecfcn || isiter)
1605 if (paramno != noparams && noparams >= 0)
1611 message ("Macro %s specified with %d args, defined with %d",
1612 fname, noparams, paramno),
1615 uentry_showWhereSpecified (e2);
1616 uentry_resetParams (e2, pn);
1621 uentry_resetParams (e2, pn);
1628 ** the form should be:
1630 ** # define newname oldname
1631 ** where oldname refers to a function matching the specification
1637 sRef_setGlobalScope ();
1638 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
1639 sRef_clearGlobalScope ();
1643 context_setMacroMissingParams ();
1648 /* context_setuentryList (pn); */
1649 usymtab_enterScope ();
1652 cstring_free (fname);
1657 static bool handleSpecial (char *yyt)
1659 char *l = mstring_create (MAX_NAME_LENGTH);
1660 static bool reportcpp = FALSE;
1666 strcpy (l, yyt + 1);
1668 /* Need to safe original l for deallocating. */
1671 l += strlen (yyt) - 1;
1673 while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
1679 olc = cstring_fromChars (ol);
1681 if (cstring_equalPrefix (olc, "pragma"))
1683 char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN));
1684 char *opname = pname;
1685 char *ptr = ol + 6; /* pragma is six characters, plus space */
1689 /* skip whitespace */
1690 while (((c = *ptr) != '\0') && isspace (c))
1696 while (((c = *ptr) != '\0') && !isspace (c))
1700 if (len > MAX_PRAGMA_LEN)
1711 if (len == PRAGMA_LEN_EXPAND
1712 && mstring_equal (opname, PRAGMA_EXPAND))
1714 cstring exname = cstring_undefined;
1718 while (((c = *ptr) != '\0') && !isspace (c))
1720 exname = cstring_appendChar (exname, c);
1725 ue = usymtab_lookupExposeGlob (exname);
1727 if (uentry_isExpandedMacro (ue))
1729 if (fileloc_isPreproc (uentry_whereDefined (ue)))
1731 fileloc_setColumn (g_currentloc, 1);
1732 uentry_setDefined (ue, g_currentloc);
1736 cstring_free (exname);
1739 else if (cstring_equalPrefix (olc, "ident"))
1741 /* Some pre-processors will leave these in the code. Ignore rest of line */
1744 ** Yuk...Win32 filenames can have spaces in them...we need to read
1745 ** to the matching end quote.
1747 else if ((sscanf (ol, "line %d \"", &lineno) == 1)
1748 || (sscanf (ol, " %d \"", &lineno) == 1))
1754 /*@access cstring@*/
1755 while (*tmp != '\"' && *tmp != '\0')
1760 llassert (*tmp == '\"');
1766 while (*tmp != '\"' && *tmp != '\0')
1771 llassert (*tmp == '\"');
1775 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
1778 ** DOS-like path delimiters get delivered in pairs, something like
1779 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
1780 ** remove the pre dirs yet as we usually specify tmp paths relative
1781 ** to the current directory, so tmp files would not get found in
1782 ** the hash table. If this method fails we try it again later.
1789 ** Skip past the drive marker.
1792 if (strchr (stmp, ':') != NULL)
1794 stmp = strchr (stmp, ':') + 1;
1797 while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
1799 if (*(stmp+1) == CONNECTCHAR)
1801 memmove (stmp, stmp+1, strlen (stmp));
1807 fid = fileTable_lookupBase (context_fileTable (), fname);
1808 if (!(fileId_isValid (fid)))
1810 fname = removePreDirs (fname);
1811 fid = fileTable_lookupBase (context_fileTable (), fname);
1814 # else /* !defined(OS2) && !defined(MSDOS) */
1815 fname = removePreDirs (fname);
1816 fid = fileTable_lookupBase (context_fileTable (), fname);
1817 # endif /* !defined(OS2) && !defined(MSDOS) */
1819 if (!(fileId_isValid (fid)))
1821 if (isHeaderFile (fname))
1823 fid = fileTable_addHeaderFile (context_fileTable (), fname);
1827 fid = fileTable_addFile (context_fileTable (), fname);
1831 setFileLine (fid, lineno);
1832 /*@noaccess cstring@*/
1834 else if ((sscanf (ol, "line %d", &lineno) == 1)
1835 || (sscanf (ol, " %d", &lineno) == 1))
1837 setLine (lineno); /* next line is <cr> */
1841 if (mstring_equal (ol, "")) {
1842 DPRINTF (("Empty pp command!"));
1844 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
1845 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
1854 llbug (message ("File contains preprocessor command: #%s",
1855 cstring_fromChars (ol)));
1868 static int handleLlSpecial ()
1872 char *s = mstring_createEmpty ();
1878 loc = fileloc_copy (g_currentloc);
1879 DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
1881 while (((ic = ninput ()) != 0) && isalpha (ic))
1884 s = mstring_append (s, c);
1888 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
1891 if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
1895 llassert (ic == AFTER_COMMENT_MARKER[1]);
1901 return QNOMODS; /* special token no modifications token */
1905 DPRINTF (("Coment marker: %s", os));
1906 tok = commentMarkerToken (cstring_fromChars (os));
1910 tokLength = charsread;
1917 DPRINTF (("Not a comment marker..."));
1918 /* Add rest of the comment */
1920 if (ic != 0 && ic != EOF)
1924 s = mstring_append (s, c);
1927 while (((ic = ninput ()) != 0) && (ic != EOF)
1928 && (ic != AFTER_COMMENT_MARKER[0]))
1931 s = mstring_append (s, c);
1936 DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
1938 if (ic == AFTER_COMMENT_MARKER[0])
1941 llassert ((char) nc == AFTER_COMMENT_MARKER[1]);
1947 while (*s == ' ' || *s == '\t' || *s == '\n')
1952 if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
1956 while (c == '-' || c == '+' || c == '=')
1958 ynm set = ynm_fromCodeChar (c);
1963 thisflag = cstring_fromChars (s);
1965 while ((c = *s) != '\0' && (c != '-') && (c != '=')
1966 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
1973 if (!context_getFlag (FLG_NOCOMMENTS))
1975 cstring flagname = thisflag;
1976 flagcode fflag = identifyFlag (flagname);
1978 if (flagcode_isSkip (fflag))
1982 else if (flagcode_isInvalid (fflag))
1984 if (isMode (flagname))
1986 if (ynm_isMaybe (set))
1991 ("Semantic comment attempts to restore flag %s. "
1992 "A mode flag cannot be restored.",
1997 context_setMode (flagname);
2004 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.",
2019 context_fileSetFlag (fflag, set);
2021 if (flagcode_hasArgument (fflag))
2023 if (ynm_isMaybe (set))
2028 ("Semantic comment attempts to restore flag %s. "
2029 "A flag for setting a value cannot be restored.",
2033 { /* cut-and-pastied from llmain...blecch */
2034 cstring extra = cstring_undefined;
2040 rest = mstring_copy (s);
2044 while ((rchar = *rest) != '\0'
2045 && (isspace (rchar)))
2051 while ((rchar = *rest) != '\0'
2052 && !isspace (rchar))
2054 extra = cstring_appendChar (extra, rchar);
2061 if (cstring_isUndefined (extra))
2066 ("Flag %s (in semantic comment) must be followed by an argument",
2067 flagcode_unparse (fflag)));
2073 if (flagcode_hasValue (fflag))
2075 setValueFlag (fflag, extra);
2077 else if (flagcode_hasString (fflag))
2079 setStringFlag (fflag, extra);
2096 while ((c == ' ') || (c == '\t') || (c == '\n'))
2102 if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
2104 DPRINTF (("Here adding comment: %s", os));
2105 context_addComment (cstring_fromCharsNew (os));
2117 annotationInfo ainfo;
2119 while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
2131 t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
2132 macrocode = tokenMacroCode (cstring_fromChars (t));
2134 if (macrocode != BADTOK)
2136 tokLength = mstring_length (t);
2142 if (macrocode == SKIPTOK)
2150 ainfo = context_lookupAnnotation (cstring_fromChars (os));
2152 if (annotationInfo_isDefined (ainfo)) {
2153 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
2154 /*@i324@*/ yylval.annotation = ainfo;
2162 if (context_inHeader ())
2169 if ((context_inMacro () || context_inGlobalContext ())
2170 && macrocode != SKIPTOK
2171 && !isArtificial (cstring_fromChars (os)))
2173 DPRINTF (("Add comment: %s", os));
2174 context_addComment (cstring_fromCharsNew (os));
2187 if (mstring_equal (t, "ignore"))
2189 if (!context_getFlag (FLG_NOCOMMENTS))
2191 context_enterSuppressRegion ();
2194 else if ((*t == 'i' || *t == 't')
2195 && (*(t + 1) == '\0'))
2197 if (!context_getFlag (FLG_NOCOMMENTS)
2198 && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
2200 context_enterSuppressLine (-1); /* infinite suppression */
2203 else if (((*t == 'i') || (*t == 't'))
2204 && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
2206 bool tmpcomment = (*t == 't');
2208 char *tt = t; /* don't mangle t, since it is free'd */
2211 if (lc >= '0' && lc <= '9')
2213 val = (int)(lc - '0');
2216 while (lc >= '0' && lc <= '9')
2225 if (!context_getFlag (FLG_NOCOMMENTS)
2226 && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
2228 context_enterSuppressLine (val);
2231 else if (mstring_equal (t, "end"))
2233 if (!context_getFlag (FLG_NOCOMMENTS))
2235 context_exitSuppressRegion ();
2238 else if (mstring_equal (t, "notfunction"))
2240 ; /* handled by pcpp */
2242 else if (mstring_equal (t, "access"))
2248 while ((c = *s) && (c == ' ' || c == '\t' || c == '\n'))
2258 tname = cstring_fromChars (s);
2260 while ((c = *s) != '\0' && c != ' '
2261 && c != '\t' && c != '\n' && c != ',')
2268 DPRINTF (("Access %s", tname));
2270 if (!context_getFlag (FLG_NOCOMMENTS)
2271 && !context_getFlag (FLG_NOACCESS))
2273 if (usymtab_existsType (tname))
2275 typeId uid = usymtab_getTypeId (tname);
2276 uentry ue = usymtab_getTypeEntry (uid);
2278 if (uentry_isAbstractDatatype (ue))
2280 context_addFileAccessType (uid);
2281 DPRINTF (("Adding access to: %s / %d", tname, uid));
2288 ("Non-abstract type %s used in access comment",
2295 if (!(context_inSuppressRegion ()
2296 || context_inSuppressZone (g_currentloc)))
2301 ("Unrecognized type %s used in access comment",
2313 if (c != ',' && c != ' ')
2319 else if (mstring_equal (t, "noaccess"))
2326 while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n'))
2336 tname = cstring_fromChars (s);
2338 while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
2339 && lc != '\n' && lc != ',')
2346 if (!context_getFlag (FLG_NOCOMMENTS)
2347 && !context_getFlag (FLG_NOACCESS))
2349 if (usymtab_existsType (tname))
2351 typeId tuid = usymtab_getTypeId (tname);
2353 if (context_couldHaveAccess (tuid))
2355 DPRINTF (("Removing access: %s", tname));
2356 context_removeFileAccessType (tuid);
2360 if (!(context_inSuppressRegion ()
2361 || context_inSuppressZone (g_currentloc)))
2363 uentry ue = usymtab_getTypeEntry (tuid);
2365 if (uentry_isAbstractDatatype (ue))
2370 ("Non-accessible abstract type %s used in noaccess comment",
2379 ("Non-abstract type %s used in noaccess comment",
2388 if (!(context_inSuppressRegion ()
2389 || context_inSuppressZone (g_currentloc)))
2394 ("Unrecognized type %s used in noaccess comment",
2406 if (lc != ',' && lc != ' ')
2414 voptgenerror (FLG_UNRECOGCOMMENTS,
2415 message ("Semantic comment unrecognized: %s",
2416 cstring_fromChars (os)), loc);
2427 static /*@only@*/ cstring makeIdentifier (char *s)
2429 char *c = mstring_create (size_toInt (strlen (s)) + 1);
2430 cstring id = cstring_fromChars (c);
2432 while (isalnum (*s) || (*s == '_') || (*s == '$'))
2441 /*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn)
2443 if (!(usymtab_exists (cn)))
2445 fileloc loc = fileloc_createExternal ();
2448 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
2451 uentry ce = uentry_makeUnrecognized (cn, loc);
2453 if (!context_inIterEnd ())
2457 message ("Unrecognized (possibly system) identifier: %q",
2458 uentry_getName (ce)),
2465 return (usymtab_lookup (cn));
2469 ** like, coerceId, but doesn't supercede for iters
2472 /*@observer@*/ uentry coerceIterId (cstring cn)
2474 if (!(usymtab_exists (cn)))
2476 return uentry_undefined;
2479 return (usymtab_lookup (cn));
2482 /*@observer@*/ cstring LastIdentifier ()
2484 return (lastidprocessed);
2487 static int processIdentifier (cstring id)
2491 DPRINTF (("Process identifier: %s / %s / %s", id, fileloc_unparse (g_currentloc),
2492 bool_unparse (context_inFunctionHeader ())));
2494 context_clearJustPopped ();
2495 lastidprocessed = id;
2497 if (context_inFunctionHeader ())
2499 int tok = commentMarkerToken (id);
2500 DPRINTF (("in function decl..."));
2508 tok = tokenMacroCode (id);
2516 annotationInfo ainfo = context_lookupAnnotation (id);
2518 if (annotationInfo_isDefined (ainfo))
2520 DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
2521 /*@i324@*/ yylval.annotation = ainfo;
2526 DPRINTF (("Not annotation: %s", id));
2532 /* Consider handling: Defined by C99 as static const char __func__[] */
2534 if (context_getFlag (FLG_GNUEXTENSIONS))
2538 if (cstring_equalLit (id, "__stdcall")
2539 || cstring_equalLit (id, "__cdecl")
2540 || cstring_equalLit (id, "__extension__"))
2544 else if (cstring_equalLit (id, "__volatile__"))
2548 else if (cstring_equalLit (id, "__signed"))
2552 else if (cstring_equalLit (id, "__unsigned"))
2556 else if (cstring_equalLit (id, "__const__"))
2560 else if (cstring_equalLit (id, "__alignof__"))
2562 tok = CALIGNOF; /* alignof is parsed like sizeof */
2564 else if (cstring_equalLit (id, "__FUNCTION__")
2565 || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
2567 /* These tokens hold the name of the current function as strings */
2568 yylval.expr = exprNode_stringLiteral (id, fileloc_copy (g_currentloc));
2570 lastWasString = TRUE;
2574 else if (cstring_equalLit (id, "__attribute__")
2575 || cstring_equalLit (id, "__asm__")
2576 || cstring_equalLit (id, "_asm")
2577 || cstring_equalLit (id, "__asm")
2578 || cstring_equalLit (id, "__declspec"))
2581 bool useparens = FALSE;
2582 bool usebraces = FALSE;
2583 bool inquote = FALSE;
2584 bool inescape = FALSE;
2587 while ((ic = input ()) != EOF)
2594 else if (ic == '\\')
2598 else if (ic == '\"')
2634 else if (ic == ')' && useparens)
2637 if (depth == 0) break;
2639 else if (ic == '}' && usebraces)
2642 if (depth == 0) break;
2645 && !usebraces && !useparens
2646 && cstring_equalLit (id, "__asm"))
2649 ** We need this because some MS VC++ include files
2650 ** have __asm mov ... }
2651 ** Its a kludge, but otherwise would need to parse
2660 context_incLineno ();
2662 if (cstring_equalLit (id, "__asm")
2663 && !useparens && !usebraces)
2670 llassert ((useparens && ic == ')')
2671 || (usebraces && ic == '}')
2672 || (!useparens && !usebraces));
2676 else if (cstring_equalLit (id, "inline")
2677 || cstring_equalLit (id, "__inline")
2678 || cstring_equalLit (id, "_inline")
2679 || cstring_equalLit (id, "__inline__"))
2690 le = usymtab_lookupSafe (id);
2692 /*@-dependenttrans@*/
2694 if (uentry_isIter (le))
2696 /*@i32@*/ yylval.entry = le;
2699 else if (uentry_isEndIter (le))
2701 /*@i32@*/ yylval.entry = le;
2702 return (ITER_ENDNAME);
2704 else if (uentry_isUndefined (le))
2708 /* avoid parse errors for certain system built ins */
2710 if (g_expectingTypeName && (cstring_firstChar (id) == '_')
2711 && (cstring_secondChar (id) == '_'))
2713 return (TYPE_NAME_OR_ID);
2716 return (NEW_IDENTIFIER);
2718 else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
2720 if (uentry_isDatatype (le))
2723 return (NEW_IDENTIFIER);
2727 /*@i32@*/ yylval.entry = le;
2728 return (IDENTIFIER);
2731 else if (uentry_isDatatype (le))
2733 if (!g_expectingTypeName)
2737 return (NEW_IDENTIFIER);
2741 yylval.ctyp = uentry_getAbstractType (le);
2743 uentry_setUsed (le, g_currentloc);
2749 /*@i32@*/ yylval.entry = le;
2750 return (IDENTIFIER);
2753 /*@=dependenttrans@*/
2756 static bool processHashIdentifier (/*@only@*/ cstring id)
2758 if (context_inMacro () || context_inIterDef () ||
2759 context_inIterEnd ())
2763 context_clearJustPopped ();
2765 lastidprocessed = id;
2766 le = usymtab_lookupSafe (id);
2768 if (uentry_isParam (le) || uentry_isRefParam (le))
2785 static /*@only@*/ exprNode processString ()
2789 char *nl = strchr (yytext, '\n');
2790 cstring ns = cstring_fromCharsNew (yytext);
2794 loc = fileloc_copy (g_currentloc);
2795 addColumn (cstring_length (ns));
2801 loc = fileloc_copy (g_currentloc);
2803 context_incLineno ();
2805 while ((nl = strchr ((nl + 1), '\n')) != NULL)
2807 context_incLineno ();
2813 res = exprNode_stringLiteral (ns, loc);
2823 llassert (*yytext != '\0');
2824 fchar = *(yytext + 1);
2825 if (fchar != '\\') return fchar;
2827 next = *(yytext + 2);
2831 case 'n': return '\n';
2832 case 't': return '\t';
2833 case '\"': return '\"';
2834 case '\'': return '\'';
2835 case '\\': return '\\';
2836 default: return '\0';
2841 double processFloat ()
2843 double ret = atof (yytext);
2854 llassert (yytext[0] == '0'
2855 && (yytext[1] == 'X' || yytext[1] == 'x'));
2857 while (yytext[index] != '\0') {
2859 char c = yytext[index];
2861 if (c >= '0' && c <= '9') {
2862 tval = (int) c - (int) '0';
2863 } else if (c >= 'A' && c <= 'F') {
2864 tval = (int) c - (int) 'A' + 10;
2865 } else if (c >= 'a' && c <= 'f') {
2866 tval = (int) c - (int) 'a' + 10;
2867 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2869 while (yytext[index] != '\0') {
2870 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2875 message ("Invalid character (%c) following specifier in hex constant: %s",
2876 c, cstring_fromChars (yytext)),
2886 message ("Invalid character (%c) in hex constant: %s",
2887 c, cstring_fromChars (yytext)),
2892 val = (val * 16) + tval;
2896 DPRINTF (("Hex constant: %s = %ld", yytext, val));
2901 long processOctal ()
2906 llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
2908 while (yytext[index] != '\0') {
2910 char c = yytext[index];
2912 if (c >= '0' && c <= '7') {
2913 tval = (int) c - (int) '0';
2917 message ("Invalid character (%c) in octal constant: %s",
2918 c, cstring_fromChars (yytext)),
2923 val = (val * 8) + tval;
2927 DPRINTF (("Octal constant: %s = %ld", yytext, val));
2934 return (atol (yytext));
2938 processSpec (int tok)
2940 size_t length = strlen (yytext);
2945 setTokLengthT (length);
2951 context_saveLocation ();
2952 setTokLengthT (length);
2953 return (processIdentifier (makeIdentifier (yytext)));