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 "sgrammar.h"
67 # include "sgrammar_tokens.h"
69 # include "cgrammar.h"
70 # include "cgrammar_tokens.h"
73 # include "fileIdList.h"
76 # if defined(OS2) && defined(__IBMC__)
77 /* needed for isatty()... */
81 static bool lastWasString = FALSE;
82 static char savechar = '\0';
85 # define yyinput() (incColumn (), getc (yyin))
89 extern /*@external@*/ int read ();
93 static /*@owned@*/ cstring lastidprocessed = cstring_undefined;
95 static int lminput (void);
96 static int tokLength = 0;
97 static bool inSpecPart = FALSE;
98 static bool continueLine = FALSE;
100 static int ninput (void);
101 static char processChar (void);
102 static double processFloat (void);
103 static /*@only@*/ exprNode processString (void);
104 static long processDec (void);
105 static long processHex (void);
106 static long processOctal (void);
107 static int processIdentifier (/*@only@*/ cstring)
108 /*@globals undef lastidprocessed@*/ ;
109 static bool processHashIdentifier (/*@only@*/ cstring)
110 /*@globals undef lastidprocessed@*/ ;
112 static int processSpec (int);
113 static bool handleSpecial (char *);
114 static int handleLlSpecial (void);
115 static void handleMacro (void);
116 static bool processMacro (void);
117 static /*@only@*/ cstring makeIdentifier (char *);
119 /* yes, this is exported! */
120 bool g_expectingTypeName = TRUE; /* beginning of file can be type name! */
122 static int returnInt (ctype, long);
123 static int returnFloat (ctype, double);
124 static int returnChar (char);
125 static void setTokLength (int) /*@modifies g_currentloc@*/ ;
126 static void setTokLengthT (size_t) /*@modifies g_currentloc@*/ ;
128 static void advanceLine (void)
135 # define RETURN_INT(c,i) \
136 do { lastWasString = FALSE; \
137 return (returnInt (c, i)); } while (FALSE)
139 # define RETURN_FLOAT(c,f) \
140 do { lastWasString = FALSE; \
141 return (returnFloat (c, f)); \
144 # define RETURN_CHAR(c) \
145 do { lastWasString = FALSE; \
146 return (returnChar (c)); \
149 # define RETURN_TOK(t) \
150 do { yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, tokLength)); \
152 lastWasString = FALSE; \
153 return (t); } while (FALSE)
155 # define RETURN_TYPE(t, ct) \
156 do { yylval.ctyp = ct; tokLength = 0; return (t); } while (FALSE)
158 /* don't fileloc_decColumn (g_currentloc, tokLength));
159 the string could have \n's in it!
162 # define RETURN_STRING(c) \
163 do { yylval.expr = exprNode_stringLiteral (c, fileloc_decColumn (g_currentloc, tokLength)); \
165 lastWasString = TRUE; \
166 return (CCONSTANT); } while (FALSE)
168 # define RETURN_EXPR(e) \
169 do { yylval.expr = e; \
171 lastWasString = TRUE; \
172 return (CCONSTANT); } while (FALSE)
176 static void setTokLength (int len)
182 static void setTokLengthT (size_t len)
184 setTokLength (size_toInt (len));
187 # include "flex.head"
192 "/*" { llfatalbug (cstring_makeLiteral ("Comment in pre-processor output")); }
194 "#"{Letter}({Letter}|{Digit})* {
195 context_saveLocation ();
196 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
198 if (processHashIdentifier (makeIdentifier (yytext + 1)))
206 RETURN_STRING (cstring_makeLiteral ("\"\""));
211 if (handleSpecial (yytext))
218 "#" { if (handleSpecial (yytext))
220 setTokLength (1); RETURN_TOK (0);
223 "..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); }
224 "break" { setTokLength (5); RETURN_TOK (BREAK); }
225 "case" { setTokLength (4); RETURN_TOK (CASE); }
226 "continue" { setTokLength (8); RETURN_TOK (CONTINUE); }
227 "default" { setTokLength (7); RETURN_TOK (DEFAULT); }
228 "do" { setTokLength (2); RETURN_TOK (DO); }
229 "else" { setTokLength (4); RETURN_TOK (CELSE); }
230 "for" { setTokLength (3); RETURN_TOK (CFOR); }
231 "goto" { setTokLength (4); RETURN_TOK (GOTO); }
232 "if" { setTokLength (2); RETURN_TOK (CIF); }
233 "return" { setTokLength (6); RETURN_TOK (RETURN); }
234 "sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); }
235 "offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); }
236 "switch" { setTokLength (6); RETURN_TOK (SWITCH); }
237 "while" { setTokLength (5); RETURN_TOK (WHILE); }
238 "va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); }
239 "va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); }
241 /* gcc extension...this might not be appropriate */
242 setTokLength (6); RETURN_TOK (QINLINE); }
244 "struct" { setTokLength (6); RETURN_TOK (CSTRUCT); }
245 "typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); }
247 "union" { setTokLength (5); RETURN_TOK (CUNION); }
248 "enum" { setTokLength (4); RETURN_TOK (CENUM); }
250 "void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); }
251 "int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); }
252 "double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); }
253 "char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); }
254 "float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); }
256 "long" { setTokLength (4); RETURN_TOK (QLONG); }
257 "short" { setTokLength (5); RETURN_TOK (QSHORT); }
258 "unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); }
259 "signed" { setTokLength (6); RETURN_TOK (QSIGNED); }
261 "volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); }
262 "const" { setTokLength (5); RETURN_TOK (QCONST); }
264 /* some systems expect this! [gack!] */
265 "__const" { setTokLength (7); RETURN_TOK (QCONST); }
267 "extern" { setTokLength (6); RETURN_TOK (QEXTERN); }
268 "auto" { setTokLength (4); RETURN_TOK (QAUTO); }
269 "register" { setTokLength (8); RETURN_TOK (QREGISTER); }
270 "static" { setTokLength (6); RETURN_TOK (QSTATIC); }
272 \"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
273 "out" { return (processSpec (QOUT)); }
274 "in" { return (processSpec (QIN)); }
275 "partial" { return (processSpec (QPARTIAL)); }
276 "special" { return (processSpec (QSPECIAL)); }
277 "anytype" { return (processSpec (QANYTYPE)); }
278 "integraltype" { return (processSpec (QINTEGRALTYPE)); }
279 "unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); }
280 "signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); }
281 "keep" { return (processSpec (QKEEP)); }
282 "null" { return (processSpec (QNULL)); }
283 "notnull" { return (processSpec (QNOTNULL)); }
284 "isnull" { return (processSpec (QISNULL)); }
285 "truenull" { return (processSpec (QTRUENULL)); }
286 "falsenull" { return (processSpec (QFALSENULL)); }
287 "relnull" { return (processSpec (QRELNULL)); }
288 "reldef" { return (processSpec (QRELDEF)); }
289 "exposed" { return (processSpec (QEXPOSED)); }
290 "newref" { return (processSpec (QNEWREF)); }
291 "tempref" { return (processSpec (QTEMPREF)); }
292 "killref" { return (processSpec (QKILLREF)); }
293 "refcounted" { return (processSpec (QREFCOUNTED)); }
294 "checked" { return (processSpec (QCHECKED)); }
295 "checkmod" { return (processSpec (QCHECKMOD)); }
296 "checkedstrict" { return (processSpec (QCHECKEDSTRICT)); }
297 "unchecked" { return (processSpec (QUNCHECKED)); }
298 "only" { return (processSpec (QONLY)); }
299 "owned" { return (processSpec (QOWNED)); }
300 "observer" { return (processSpec (QOBSERVER)); }
301 "dependent" { return (processSpec (QDEPENDENT)); }
302 "unused" { return (processSpec (QUNUSED)); }
303 "external" { return (processSpec (QEXTERNAL)); }
304 "sef" { return (processSpec (QSEF)); }
305 "shared" { return (processSpec (QSHARED)); }
306 "yield" { return (processSpec (QYIELD)); }
307 "undef" { return (processSpec (QUNDEF)); }
308 "killed" { return (processSpec (QKILLED)); }
309 "nullterminated" { return (processSpec (QNULLTERMINATED));}
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); }
434 [ \t\v\f] { incColumn (); }
435 \n { context_incLineno ();
438 continueLine = FALSE;
442 if (context_inMacro ())
444 /* Don't use RETURN_TOK */
445 yylval.tok = lltok_create (TENDMACRO, g_currentloc);
446 lastWasString = FALSE;
451 "@@MR@@" { setTokLength (6);
453 if (processMacro ()) {
454 if (context_inIterDef ())
456 RETURN_TOK (LLMACROITER);
458 if (context_inIterEnd ())
460 RETURN_TOK (LLMACROEND);
462 if (context_inMacro ())
464 RETURN_TOK (LLMACRO);
468 "@QLMR" { if (context_inHeader () || context_inFunction ())
474 int nspchar = ninput ();
478 ** This is a hack to get the column number correct.
481 llassert (nspchar >= '0' && nspchar <= '9');
483 nspaces = nspchar - '0';
485 setTokLength (5 + nspaces);
489 if (context_inIterDef ())
491 RETURN_TOK (LLMACROITER);
493 if (context_inIterEnd ())
495 RETURN_TOK (LLMACROEND);
497 if (context_inMacro ())
499 RETURN_TOK (LLMACRO);
504 "@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); }
505 "@.F" { setTokLength (3);
506 lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc)));
508 "@.L" { setTokLength (3); usymtab_printLocal (); }
509 "@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); }
510 "@.C" { setTokLength (3); lldiagmsg (context_unparse ()); }
511 "@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); }
512 "@.G" { setTokLength (3); usymtab_printGuards (); }
513 "@.S" { setTokLength (3); usymtab_printOut (); }
514 "@.X" { setTokLength (3); usymtab_printAll (); }
515 "@.Z" { setTokLength (3); usymtab_printComplete (); }
516 "@.T" { setTokLength (3); usymtab_printTypes (); }
517 "@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); }
518 "@.M" { setTokLength (3);
519 lldiagmsg (message ("Can modify: %q",
520 sRefSet_unparse (context_modList ())));
522 "%{" { /* BEFORE_COMMENT_MARKER */
524 incColumn (); incColumn ();
525 tok = handleLlSpecial ();
531 "%}" { /* AFTER_COMMENT_MARKER */
534 RETURN_TOK (QENDMACRO); }
535 "\\" { incColumn (); continueLine = TRUE; }
539 message ("Invalid character (ascii: %d), skipping character",
547 /*@null@*/ /*@observer@*/ char *name;
552 ** These tokens are followed by syntax that is parsed by the
556 struct skeyword s_parsetable[] = {
557 { "modifies", QMODIFIES } ,
558 { "globals", QGLOBALS } ,
560 { "constant", QCONSTANT } ,
561 { "function", QFUNCTION } ,
563 { "defines", QDEFINES } ,
565 { "allocates", QALLOCATES } ,
567 { "releases", QRELEASES } ,
568 { "pre", QPRECLAUSE } ,
569 { "post", QPOSTCLAUSE } ,
570 {"setBufferSize", QSETBUFFERSIZE},
571 {"setStringLength", QSETSTRINGLENGTH},
576 ** These tokens are either stand-alone tokens, or followed by
577 ** token-specific text.
580 struct skeyword s_keytable[] = {
581 { "anytype", QANYTYPE } ,
582 { "integraltype", QINTEGRALTYPE } ,
583 { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,
584 { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,
588 { "owned", QOWNED } ,
589 { "dependent", QDEPENDENT } ,
590 { "partial", QPARTIAL } ,
591 { "special", QSPECIAL } ,
592 { "truenull", QTRUENULL } ,
593 { "falsenull", QFALSENULL } ,
596 { "notnull", QNOTNULL } ,
597 { "abstract", QABSTRACT } ,
598 { "concrete", QCONCRETE } ,
599 { "mutable", QMUTABLE } ,
600 { "immutable", QIMMUTABLE } ,
601 { "unused", QUNUSED } ,
602 { "external", QEXTERNAL } ,
604 { "unique", QUNIQUE } ,
605 { "returned", QRETURNED } ,
606 { "exposed", QEXPOSED } ,
607 { "refcounted", QREFCOUNTED } ,
609 { "newref", QNEWREF } ,
610 { "tempref", QTEMPREF } ,
611 { "killref", QKILLREF } ,
613 { "relnull", QRELNULL } ,
614 { "nullterminated", QNULLTERMINATED },
615 { "setBufferSize", QSETBUFFERSIZE },
616 { "reldef", QRELDEF } ,
617 { "observer", QOBSERVER } ,
618 { "exits", QEXITS } ,
619 { "mayexit", QMAYEXIT } ,
620 { "trueexit", QTRUEEXIT } ,
621 { "falseexit", QFALSEEXIT } ,
622 { "neverexit", QNEVEREXIT } ,
624 { "shared", QSHARED } ,
626 { "unchecked", QUNCHECKED } ,
627 { "checked", QCHECKED } ,
628 { "checkmod", QCHECKMOD } ,
629 { "checkedstrict", QCHECKEDSTRICT } ,
630 { "innercontinue", QINNERCONTINUE } ,
631 { "innerbreak", QINNERBREAK } ,
632 { "loopbreak", QLOOPBREAK } ,
633 { "switchbreak", QSWITCHBREAK } ,
634 { "safebreak", QSAFEBREAK } ,
635 { "fallthrough", QFALLTHROUGH } ,
636 { "l_fallthrou", QLINTFALLTHROUGH } ,
637 { "l_fallth", QLINTFALLTHRU } ,
638 { "notreached", QNOTREACHED } ,
639 { "l_notreach", QLINTNOTREACHED } ,
640 { "printflike", QPRINTFLIKE } ,
641 { "l_printfli", QLINTPRINTFLIKE } ,
642 { "scanflike", QSCANFLIKE } ,
643 { "messagelike", QMESSAGELIKE } ,
644 { "l_argsus", QARGSUSED } ,
649 ** would be better if these weren't hard coded...
652 static bool isArtificial (cstring s)
654 return (cstring_equalLit (s, "modifies")
655 || cstring_equalLit (s, "globals")
656 || cstring_equalLit (s, "alt"));
659 void swallowMacro (void)
662 bool skipnext = FALSE;
664 while ((i = lminput ()) != EOF)
681 checkUngetc (i, yyin);
689 checkUngetc (i, yyin);
693 static int commentMarkerToken (cstring s)
697 while (s_parsetable[i].name != NULL)
699 if (cstring_equalLit (s, s_parsetable[i].name))
701 return s_parsetable[i].token;
710 static int tokenMacroCode (cstring s)
714 while (s_keytable[i].name != NULL)
716 if (cstring_equalLit (s, s_keytable[i].name))
718 if (s_keytable[i].token == QLINTFALLTHROUGH)
721 (FLG_WARNLINTCOMMENTS,
723 ("Traditional lint comment /*FALLTHROUGH*/ used. "
724 "This is interpreted by "
725 "LCLint in the same way as most Unix lints, but it is "
726 "preferable to replace it with the /*@fallthrough@*/ "
731 else if (s_keytable[i].token == QLINTFALLTHRU)
734 (FLG_WARNLINTCOMMENTS,
736 ("Traditional lint comment /*FALLTHRU*/ used. "
737 "This is interpreted by "
738 "LCLint in the same way as most Unix lints, but it is "
739 "preferable to replace it with the /*@fallthrough@*/ "
744 else if (s_keytable[i].token == QLINTNOTREACHED)
747 (FLG_WARNLINTCOMMENTS,
749 ("Traditional lint comment /*NOTREACHED*/ used. "
750 "This is interpreted by "
751 "LCLint in the same way as most Unix lints, but it is "
752 "preferable to replace it with the /*@notreached@*/ "
753 "stylized comment."),
758 else if (s_keytable[i].token == QPRINTFLIKE)
760 setSpecialFunction (QU_PRINTFLIKE);
763 else if (s_keytable[i].token == QLINTPRINTFLIKE)
766 (FLG_WARNLINTCOMMENTS,
768 ("Traditional lint comment /*PRINTFLIKE*/ used. "
769 "This is interpreted by "
770 "LCLint in the same way as most Unix lints, but it is "
771 "preferable to replace it with either /*@printflike@*/, "
772 "/*@scanflike@*/ or /*@messagelike@*/."),
775 setSpecialFunction (QU_PRINTFLIKE);
778 else if (s_keytable[i].token == QSCANFLIKE)
780 setSpecialFunction (QU_SCANFLIKE);
783 else if (s_keytable[i].token == QMESSAGELIKE)
785 setSpecialFunction (QU_MESSAGELIKE);
788 else if (s_keytable[i].token == QARGSUSED)
791 (FLG_WARNLINTCOMMENTS,
793 ("Traditional lint comment /*ARGSUSED*/ used. "
794 "This is interpreted by "
795 "LCLint in the same way as most Unix lints, but it is "
796 "preferable to use /*@unused@*/ annotations on "
797 "the unused parameters."),
804 return s_keytable[i].token;
813 static int lminput ()
815 if (savechar == '\0')
822 int save = (int) savechar;
828 static void lmsavechar (char c)
830 if (savechar == '\0') savechar = c;
833 llbuglit ("lmsavechar: override");
837 static int returnFloat (ctype ct, double f)
839 yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext),
840 fileloc_decColumn (g_currentloc, tokLength));
845 static int returnInt (ctype ct, long i)
849 if (ctype_equal (ct, ctype_int))
853 c = context_typeofZero ();
857 c = context_typeofOne ();
861 yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext),
862 fileloc_decColumn (g_currentloc, tokLength), i);
867 static int returnChar (char c)
869 yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext),
870 fileloc_decColumn (g_currentloc, tokLength));
879 if (c != EOF && ((char)c == '\n'))
881 context_incLineno ();
887 static char macro_nextChar ()
889 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
894 c = char_fromInt (ic);
896 if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
900 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
902 ; /* skip to newline */
905 context_incLineno ();
909 return macro_nextChar ();
916 else /* if (c == '@') */
918 if (handleLlSpecial () != BADTOK)
920 llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
923 return macro_nextChar ();
926 else if (!in_escape && c == '\"')
928 in_quote = !in_quote;
930 else if (!in_escape && c == '\'')
934 else if ((in_quote || in_char) && c == '\\')
936 in_escape = !in_escape;
938 else if ((in_quote || in_char) && in_escape)
942 else if (!in_quote && c == '/')
946 if ((c2 = char_fromInt (lminput ())) == '*')
950 while ((c2 = char_fromInt (lminput ())) != '\0'
951 && c2 != '\n' && c2 != '*')
958 while ((c2 = char_fromInt (lminput ())) != '\0'
971 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
975 return macro_nextChar ();
979 /*** putchar does not work! why? puts to stdio...??! ***/
987 ** keeps stylized comments
990 static char macro_nextCharC ()
992 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
995 c = char_fromInt (lminput ());
997 if (!in_quote && !in_char && c == '\\')
999 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
1001 ; /* skip to newline */
1004 context_incLineno ();
1008 return macro_nextCharC ();
1015 else if (!in_escape && c == '\"')
1017 in_quote = !in_quote;
1019 else if (!in_escape && c == '\'')
1023 else if ((in_quote || in_char) && c == '\\')
1025 in_escape = !in_escape;
1027 else if ((in_quote || in_char) && in_escape)
1031 else if (!in_quote && c == '/')
1035 if ((c2 = char_fromInt (lminput ())) == '*')
1039 while ((c2 = char_fromInt (lminput ())) != '\0'
1040 && c2 != '\n' && c2 != '*')
1047 while ((c2 = char_fromInt (lminput ())) != '\0'
1060 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1064 return macro_nextCharC ();
1075 ** skips whitespace (handles line continuations)
1076 ** returns first non-whitespace character
1079 static char skip_whitespace ()
1083 while ((c = macro_nextChar ()) == ' ' || c == '\t')
1091 static void handleMacro ()
1093 cstring mac = cstring_undefined;
1097 while (currentColumn () > 2)
1099 mac = cstring_appendChar (mac, ' ');
1103 c = macro_nextCharC ();
1105 if (c >= '0' && c <= '9')
1109 for (i = 0; i < ((c - '0') + 1); i++)
1111 mac = cstring_appendChar (mac, ' ');
1119 while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
1121 mac = cstring_appendChar (mac, c);
1125 macrocode = tokenMacroCode (mac);
1127 if (macrocode == BADTOK && !isArtificial (mac))
1129 DPRINTF (("Add macro: %s", mac));
1130 context_addMacroCache (mac);
1139 context_incLineno ();
1143 static bool processMacro (void)
1148 cstring fname = cstring_undefined;
1150 bool isspecfcn = FALSE;
1151 bool isiter = FALSE;
1152 bool skipparam = FALSE;
1153 bool isenditer = FALSE;
1154 bool unknownm = FALSE;
1155 bool hasParams = FALSE;
1156 bool emptyMacro = FALSE;
1157 char c = skip_whitespace ();
1158 fileloc loc = fileloc_noColumn (g_currentloc);
1160 /* are both of these necessary? what do they mean? */
1161 uentryList specparams = uentryList_undefined;
1162 uentryList pn = uentryList_undefined;
1164 context_resetMacroMissingParams ();
1166 if (c == '\0' || c == '\n')
1168 llcontbug (cstring_makeLiteral ("Bad macro"));
1173 fname = cstring_appendChar (fname, c);
1175 while ((c = macro_nextChar ()) != '(' && c != '\0'
1176 && c != ' ' && c != '\t' && c != '\n')
1178 fname = cstring_appendChar (fname, c);
1181 if (c == ' ' || c == '\t' || c == '\n')
1187 while (c == ' ' || c == '\t')
1189 c = macro_nextChar ();
1203 hasParams = (c == '(');
1206 if (usymtab_exists (fname))
1208 e2 = usymtab_lookupExpose (fname);
1209 ct = uentry_getType (e2);
1212 if (uentry_isCodeDefined (e2)
1213 && fileloc_isUser (uentry_whereDefined (e2)))
1217 message ("Macro %s already defined", fname),
1220 uentry_showWhereDefined (e2);
1221 uentry_clearDefined (e2);
1224 if (uentry_isFunction (e2))
1226 uentry_setType (e2, ctype_unknown);
1229 context_enterUnknownMacro (e2);
1233 context_enterConstantMacro (e2);
1238 if (uentry_isForward (e2) && uentry_isFunction (e2))
1245 ("Parameterized macro has no prototype or specification: %s ",
1250 uentry_setType (e2, ctype_unknown);
1251 uentry_setFunctionDefined (e2, loc);
1252 uentry_setUsed (e2, fileloc_undefined);
1253 context_enterUnknownMacro (e2);
1257 if (uentry_isIter (e2))
1260 specparams = uentry_getParams (e2);
1261 noparams = uentryList_size (specparams);
1262 uentry_setDefined (e2, loc);
1263 context_enterIterDef (e2);
1265 else if (uentry_isEndIter (e2))
1268 uentry_setDefined (e2, loc);
1269 context_enterIterEnd (e2); /* don't care about it now */
1270 /* but should parse like an iter! */
1272 else if (uentry_isConstant (e2))
1278 message ("Constant %s implemented as parameterized macro",
1282 uentry_showWhereSpecified (e2);
1283 uentry_setType (e2, ctype_unknown);
1284 uentry_makeVarFunction (e2);
1285 uentry_setDefined (e2, g_currentloc);
1286 uentry_setFunctionDefined (e2, g_currentloc);
1287 context_enterUnknownMacro (e2);
1291 if (!uentry_isSpecified (e2))
1293 fileloc oloc = uentry_whereDeclared (e2);
1295 if (fileloc_isLib (oloc))
1299 else if (fileloc_isUndefined (oloc)
1300 || fileloc_isPreproc (oloc))
1305 (FLG_MACROCONSTDECL,
1307 ("Macro constant %q not declared",
1308 uentry_getName (e2)),
1312 else if (!fileloc_withinLines (oloc, loc, 2))
1313 { /* bogus! will give errors if there is too much whitespace */
1317 ("Macro constant name %s does not match name in "
1318 "previous constant declaration. This constant "
1319 "is declared at %q", fname,
1320 fileloc_unparse (oloc)),
1325 context_enterConstantMacro (e2);
1326 cstring_free (fname);
1332 else if (ctype_isFunction (ct))
1335 specparams = ctype_argsFunction (ct);
1336 noparams = uentryList_size (specparams);
1338 uentry_setFunctionDefined (e2, loc);
1339 context_enterMacro (e2);
1341 else if (uentry_isVar (e2))
1347 message ("Variable %s implemented as parameterized macro",
1351 uentry_showWhereSpecified (e2);
1352 uentry_setType (e2, ctype_unknown);
1353 uentry_makeVarFunction (e2);
1354 uentry_setDefined (e2, g_currentloc);
1355 uentry_setFunctionDefined (e2, g_currentloc);
1356 context_enterUnknownMacro (e2);
1360 uentry ucons = uentry_makeConstant (fname,
1363 if (uentry_isExpandedMacro (e2))
1371 message ("Variable %s implemented by a macro",
1375 uentry_showWhereSpecified (e2);
1379 uentry_setDefined (e2, loc);
1380 uentry_setUsed (ucons, loc);
1382 context_enterConstantMacro (ucons);
1383 uentry_markOwned (ucons);
1384 cstring_free (fname);
1390 if (uentry_isDatatype (e2))
1394 message ("Type implemented as macro: %x",
1395 uentry_getName (e2)),
1396 message ("A type is implemented using a macro definition. A "
1397 "typedef should be used instead."),
1401 /* Must exit scope (not sure why a new scope was entered?) */
1402 usymtab_quietExitScope (g_currentloc);
1403 uentry_setDefined (e2, g_currentloc);
1409 (message ("Unexpanded macro not function or constant: %q",
1410 uentry_unparse (e2)));
1411 uentry_setType (e2, ctype_unknown);
1415 uentry_makeVarFunction (e2);
1416 uentry_setDefined (e2, g_currentloc);
1417 uentry_setFunctionDefined (e2, g_currentloc);
1418 context_enterUnknownMacro (e2);
1430 (FLG_MACROMATCHNAME,
1431 message ("Unexpanded macro %s does not match name of a constant "
1432 "or iter declaration. The name used in the control "
1433 "comment on the previous line should match. "
1434 "(Assuming macro defines a constant.)",
1439 ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
1440 uentry_setUsed (ce, loc); /* perhaps bogus? */
1441 e2 = usymtab_supEntryReturn (ce);
1443 context_enterConstantMacro (e2);
1444 cstring_free (fname);
1449 /* in macros, ( must follow immediatetly after name */
1455 c = skip_whitespace ();
1457 while (c != ')' && c != '\0')
1460 bool suppress = context_inSuppressRegion ();
1461 cstring paramname = cstring_undefined;
1464 ** save the parameter location
1468 context_saveLocation ();
1471 while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
1473 paramname = cstring_appendChar (paramname, c);
1474 c = macro_nextChar ();
1477 if (c == ' ' || c == '\t') c = skip_whitespace ();
1481 c = macro_nextChar ();
1482 if (c == ' ' || c == '\t') c = skip_whitespace ();
1487 llfatalerror (cstring_makeLiteral
1488 ("Bad macro syntax: uentryList"));
1491 if ((isspecfcn || isiter) && (paramno < noparams)
1492 && !uentry_isElipsisMarker (uentryList_getN
1493 (specparams, paramno)))
1495 uentry decl = uentryList_getN (specparams, paramno);
1498 param = uentry_nameCopy (paramname, decl);
1501 uentry_setParam (param);
1502 sr = sRef_makeParam (paramno, uentry_getType (param));
1504 if (sRef_getNullState (sr) == NS_ABSNULL)
1506 ctype pt = ctype_realType (uentry_getType (param));
1508 if (ctype_isUser (pt))
1510 uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
1512 if (uentry_isValid (te))
1514 sRef_setStateFromUentry (sr, te);
1519 sRef_setNullState (sr, NS_UNKNOWN, g_currentloc);
1523 uentry_setSref (param, sr);
1524 uentry_setDeclaredForceOnly (param, context_getSaveLocation ());
1526 skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
1530 fileloc sloc = context_getSaveLocation ();
1532 param = uentry_makeVariableSrefParam
1533 (paramname, ctype_unknown, sRef_makeParam (paramno, ctype_unknown));
1534 cstring_free (paramname);
1536 sRef_setPosNull (uentry_getSref (param), sloc);
1538 uentry_setDeclaredForce (param, sloc);
1541 fileloc_free (sloc);
1546 llassert (!uentry_isElipsisMarker (param));
1550 sRef_makeUnsafe (uentry_getSref (param));
1553 pn = uentryList_add (pn, uentry_copy (param));
1554 usymtab_supEntry (param);
1558 /* don't add param */
1559 uentry_free (param);
1564 (void) macro_nextChar ();
1565 c = skip_whitespace ();
1573 if (isspecfcn || isiter)
1575 if (paramno != noparams && noparams >= 0)
1581 message ("Macro %s specified with %d args, defined with %d",
1582 fname, noparams, paramno),
1585 uentry_showWhereSpecified (e2);
1586 uentry_resetParams (e2, pn);
1591 uentry_resetParams (e2, pn);
1598 ** the form should be:
1600 ** # define newname oldname
1601 ** where oldname refers to a function matching the specification
1607 sRef_setGlobalScope ();
1608 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
1609 sRef_clearGlobalScope ();
1613 context_setMacroMissingParams ();
1618 /* context_setuentryList (pn); */
1619 usymtab_enterScope ();
1622 cstring_free (fname);
1627 static bool handleSpecial (char *yyt)
1629 char *l = mstring_create (MAX_NAME_LENGTH);
1630 static bool reportcpp = FALSE;
1636 strcpy (l, yyt + 1);
1638 /* Need to safe original l for deallocating. */
1641 l += strlen (yyt) - 1;
1643 while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
1649 olc = cstring_fromChars (ol);
1651 if (cstring_equalPrefix (olc, "pragma"))
1653 char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN));
1654 char *opname = pname;
1655 char *ptr = ol + 6; /* pragma is six characters, plus space */
1659 /* skip whitespace */
1660 while (((c = *ptr) != '\0') && isspace (c))
1666 while (((c = *ptr) != '\0') && !isspace (c))
1670 if (len > MAX_PRAGMA_LEN)
1681 if (len == PRAGMA_LEN_EXPAND
1682 && mstring_equal (opname, PRAGMA_EXPAND))
1684 cstring exname = cstring_undefined;
1688 while (((c = *ptr) != '\0') && !isspace (c))
1690 exname = cstring_appendChar (exname, c);
1695 ue = usymtab_lookupExposeGlob (exname);
1697 if (uentry_isExpandedMacro (ue))
1699 if (fileloc_isPreproc (uentry_whereDefined (ue)))
1701 fileloc_setColumn (g_currentloc, 1);
1702 uentry_setDefined (ue, g_currentloc);
1706 cstring_free (exname);
1709 else if (cstring_equalPrefix (olc, "ident"))
1711 /* Some pre-processors will leave these in the code. Ignore rest of line */
1714 ** Yuk...Win32 filenames can have spaces in them...we need to read
1715 ** to the matching end quote.
1717 else if ((sscanf (ol, "line %d \"", &lineno) == 1)
1718 || (sscanf (ol, " %d \"", &lineno) == 1))
1724 while (*tmp != '\"' && *tmp != '\0')
1729 llassert (*tmp == '\"');
1734 while (*tmp != '\"' && *tmp != '\0')
1739 llassert (*tmp == '\"');
1743 DPRINTF (("fname: %s", fname));
1745 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
1748 ** DOS-like path delimiters get delivered in pairs, something like
1749 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
1750 ** remove the pre dirs yet as we usually specify tmp paths relative
1751 ** to the current directory, so tmp files would not get found in
1752 ** the hash table. If this method fails we try it again later.
1759 ** Skip past the drive marker.
1762 DPRINTF (("stmp: %s / %s", stmp, fname));
1764 if (strchr (stmp, ':') != NULL)
1766 stmp = strchr (stmp, ':') + 1;
1769 DPRINTF (("stmp: %s / %s", stmp, fname));
1771 while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
1773 if (*(stmp+1) == CONNECTCHAR)
1775 memmove (stmp, stmp+1, strlen (stmp));
1779 DPRINTF (("stmp: %s / %s", stmp, fname));
1782 DPRINTF (("Now: base = %s", fname));
1784 fid = fileTable_lookupBase (context_fileTable (),
1785 cstring_fromChars (fname));
1786 if (!(fileId_isValid (fid)))
1788 fname = removePreDirs (fname);
1789 fid = fileTable_lookupBase (context_fileTable (),
1790 cstring_fromChars (fname));
1793 # else /* !defined(OS2) && !defined(MSDOS) */
1794 fname = removePreDirs (fname);
1795 fid = fileTable_lookupBase (context_fileTable (),
1796 cstring_fromChars (fname));
1797 # endif /* !defined(OS2) && !defined(MSDOS) */
1799 if (!(fileId_isValid (fid)))
1801 if (isHeaderFile (cstring_fromChars (fname)))
1803 fid = fileTable_addHeaderFile (context_fileTable (),
1804 cstring_fromChars (fname));
1808 fid = fileTable_addFile (context_fileTable (),
1809 cstring_fromChars (fname));
1813 setFileLine (fid, lineno);
1815 else if ((sscanf (ol, "line %d", &lineno) == 1)
1816 || (sscanf (ol, " %d", &lineno) == 1))
1818 setLine (lineno); /* next line is <cr> */
1822 if (mstring_equal (ol, "")) {
1823 DPRINTF (("Empty pp command!"));
1825 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
1826 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
1835 llbug (message ("File contains preprocessor command: #%s",
1836 cstring_fromChars (ol)));
1849 static int handleLlSpecial ()
1853 char *s = mstring_createEmpty ();
1858 while (((ic = ninput ()) != 0) && isalpha (ic))
1861 s = mstring_append (s, c);
1867 if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
1871 llassert (ic == AFTER_COMMENT_MARKER[1]);
1874 if (isProcessingGlobMods () && (*s == '\0'))
1877 return QNOMODS; /* special token no modifications token */
1885 tok = commentMarkerToken (cstring_fromChars (os));
1889 tokLength = charsread;
1895 /* Add rest of the comment */
1897 if (ic != 0 && ic != EOF)
1902 s = mstring_append (s, c);
1905 while (((ic = ninput ()) != 0) && (ic != EOF)
1906 && (ic != AFTER_COMMENT_MARKER[0]))
1909 s = mstring_append (s, c);
1914 if (ic == AFTER_COMMENT_MARKER[0])
1917 llassert ((char) nc == AFTER_COMMENT_MARKER[1]);
1924 while (*s == ' ' || *s == '\t' || *s == '\n')
1929 if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
1933 while (c == '-' || c == '+' || c == '=')
1935 ynm set = ynm_fromCodeChar (c);
1940 thisflag = cstring_fromChars (s);
1942 while ((c = *s) != '\0' && (c != '-') && (c != '=')
1943 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
1950 if (!context_getFlag (FLG_NOCOMMENTS))
1952 cstring flagname = thisflag;
1953 flagcode fflag = identifyFlag (flagname);
1955 if (flagcode_isSkip (fflag))
1959 else if (flagcode_isInvalid (fflag))
1961 if (isMode (flagname))
1963 if (ynm_isMaybe (set))
1968 ("Stylized comment attempts to restore flag %s. "
1969 "A mode flag cannot be restored.",
1974 context_setMode (flagname);
1981 message ("Unrecognized option in stylized comment: %s",
1985 else if (flagcode_isGlobalFlag (fflag))
1990 ("Stylized comment attempts to set global flag %s. "
1991 "A global flag cannot be set locally.",
1996 context_fileSetFlag (fflag, set);
1998 if (flagcode_hasArgument (fflag))
2000 if (ynm_isMaybe (set))
2005 ("Stylized comment attempts to restore flag %s. "
2006 "A flag for setting a value cannot be restored.",
2010 { /* cut-and-pastied from llmain...blecch */
2011 cstring extra = cstring_undefined;
2017 rest = mstring_copy (s);
2021 while ((rchar = *rest) != '\0'
2022 && (isspace (rchar)))
2028 while ((rchar = *rest) != '\0'
2029 && !isspace (rchar))
2031 extra = cstring_appendChar (extra, rchar);
2038 if (cstring_isUndefined (extra))
2043 ("Flag %s (in stylized comment) must be followed by an argument",
2044 flagcode_unparse (fflag)));
2050 if (flagcode_hasValue (fflag))
2052 setValueFlag (fflag, extra);
2054 else if (flagcode_hasString (fflag))
2056 setStringFlag (fflag, extra);
2072 while ((c == ' ') || (c == '\t') || (c == '\n'))
2078 if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
2080 context_addComment (cstring_fromCharsNew (os));
2093 while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
2105 t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
2106 macrocode = tokenMacroCode (cstring_fromChars (t));
2108 if (macrocode != BADTOK)
2110 tokLength = mstring_length (t);
2116 if (macrocode == SKIPTOK)
2124 if (context_inHeader ())
2131 if ((context_inMacro () || context_inGlobalContext ())
2132 && macrocode != SKIPTOK
2133 && !isArtificial (cstring_fromChars (os)))
2135 context_addComment (cstring_fromCharsNew (os));
2148 if (mstring_equal (t, "ignore"))
2150 if (!context_getFlag (FLG_NOCOMMENTS))
2152 context_enterSuppressRegion ();
2155 else if ((*t == 'i' || *t == 't')
2156 && (*(t + 1) == '\0'))
2158 if (!context_getFlag (FLG_NOCOMMENTS)
2159 && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
2161 context_enterSuppressLine (-1); /* infinite suppression */
2164 else if (((*t == 'i') || (*t == 't'))
2165 && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
2167 bool tmpcomment = (*t == 't');
2169 char *tt = t; /* don't mangle t, since it is free'd */
2172 if (lc >= '0' && lc <= '9')
2174 val = (int)(lc - '0');
2177 while (lc >= '0' && lc <= '9')
2186 if (!context_getFlag (FLG_NOCOMMENTS)
2187 && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
2189 context_enterSuppressLine (val);
2192 else if (mstring_equal (t, "end"))
2194 if (!context_getFlag (FLG_NOCOMMENTS))
2196 context_exitSuppressRegion ();
2199 else if (mstring_equal (t, "notfunction"))
2201 ; /* handled by pcpp */
2203 else if (mstring_equal (t, "access"))
2209 while ((c = *s) && (c == ' ' || c == '\t' || c == '\n'))
2219 tname = cstring_fromChars (s);
2221 while ((c = *s) != '\0' && c != ' '
2222 && c != '\t' && c != '\n' && c != ',')
2230 if (!context_getFlag (FLG_NOCOMMENTS)
2231 && !context_getFlag (FLG_NOACCESS))
2233 if (usymtab_existsType (tname))
2235 usymId uid = usymtab_getTypeId (tname);
2237 context_addFileAccessType (uid);
2241 if (!(context_inSuppressRegion ()
2242 || context_inSuppressZone (g_currentloc)))
2246 ("%q: Unrecognized type %s used in access comment",
2247 fileloc_unparse (g_currentloc), tname));
2257 if (c != ',' && c != ' ')
2263 else if (mstring_equal (t, "noaccess"))
2270 while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n'))
2280 tname = cstring_fromChars (s);
2282 while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
2283 && lc != '\n' && lc != ',')
2290 if (!context_getFlag (FLG_NOCOMMENTS)
2291 && !context_getFlag (FLG_NOACCESS))
2293 if (usymtab_existsType (tname))
2295 typeId tuid = usymtab_getTypeId (tname);
2297 if (context_couldHaveAccess (tuid))
2299 context_removeFileAccessType (tuid);
2303 if (!(context_inSuppressRegion ()
2304 || context_inSuppressZone (g_currentloc)))
2306 uentry ue = usymtab_getTypeEntry (tuid);
2308 if (uentry_isAbstractDatatype (ue))
2312 ("%q: Non-accessible abstract type %s used in noaccess comment",
2313 fileloc_unparse (g_currentloc), tname));
2319 ("%q: Non-abstract type %s used in noaccess comment",
2320 fileloc_unparse (g_currentloc), tname));
2327 if (!(context_inSuppressRegion ()
2328 || context_inSuppressZone (g_currentloc)))
2332 ("%q: Unrecognized type %s used in noaccess comment",
2333 fileloc_unparse (g_currentloc), tname));
2343 if (lc != ',' && lc != ' ')
2351 setTokLength (- (2 + charsread));
2353 voptgenerror (FLG_UNRECOGCOMMENTS,
2354 message ("Stylized comment unrecognized: %s",
2355 cstring_fromChars (os)),
2366 static /*@only@*/ cstring makeIdentifier (char *s)
2368 char *c = mstring_create (size_toInt (strlen (s)) + 1);
2369 cstring id = cstring_fromChars (c);
2371 while (isalnum (*s) || (*s == '_') || (*s == '$'))
2380 /*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn)
2382 if (!(usymtab_exists (cn)))
2384 fileloc loc = fileloc_createExternal ();
2387 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
2390 uentry ce = uentry_makeUnrecognized (cn, loc);
2392 if (!context_inIterEnd ())
2396 message ("Unrecognized (possibly system) identifier: %q",
2397 uentry_getName (ce)),
2404 return (usymtab_lookup (cn));
2408 ** like, coerceId, but doesn't supercede for iters
2411 /*@observer@*/ uentry coerceIterId (cstring cn)
2413 if (!(usymtab_exists (cn)))
2415 return uentry_undefined;
2418 return (usymtab_lookup (cn));
2421 /*@observer@*/ cstring LastIdentifier ()
2423 return (lastidprocessed);
2426 static int processIdentifier (cstring id)
2430 DPRINTF (("Process identifier: %s", id));
2432 context_clearJustPopped ();
2433 lastidprocessed = id;
2435 if (context_inFunctionDecl ())
2437 int tok = commentMarkerToken (id);
2445 tok = tokenMacroCode (id);
2454 /* Consider handling: Defined by C99 as static const char __func__[] */
2456 if (context_getFlag (FLG_GNUEXTENSIONS))
2460 if (cstring_equalLit (id, "__stdcall")
2461 || cstring_equalLit (id, "__cdecl")
2462 || cstring_equalLit (id, "__extension__"))
2466 else if (cstring_equalLit (id, "__volatile__"))
2470 else if (cstring_equalLit (id, "__signed"))
2474 else if (cstring_equalLit (id, "__unsigned"))
2478 else if (cstring_equalLit (id, "__const__"))
2482 else if (cstring_equalLit (id, "__alignof__"))
2484 tok = CALIGNOF; /* alignof is parsed like sizeof */
2486 else if (cstring_equalLit (id, "__FUNCTION__")
2487 || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
2489 /* These tokens hold the name of the current function as strings */
2490 yylval.expr = exprNode_stringLiteral (id, fileloc_copy (g_currentloc));
2492 lastWasString = TRUE;
2496 else if (cstring_equalLit (id, "__attribute__")
2497 || cstring_equalLit (id, "__asm__")
2498 || cstring_equalLit (id, "_asm")
2499 || cstring_equalLit (id, "__asm")
2500 || cstring_equalLit (id, "__declspec"))
2503 bool useparens = FALSE;
2504 bool usebraces = FALSE;
2505 bool inquote = FALSE;
2506 bool inescape = FALSE;
2509 while ((ic = input ()) != EOF)
2516 else if (ic == '\\')
2520 else if (ic == '\"')
2556 else if (ic == ')' && useparens)
2559 if (depth == 0) break;
2561 else if (ic == '}' && usebraces)
2564 if (depth == 0) break;
2567 && !usebraces && !useparens
2568 && cstring_equalLit (id, "__asm"))
2571 ** We need this because some MS VC++ include files
2572 ** have __asm mov ... }
2573 ** Its a kludge, but otherwise would need to parse
2582 context_incLineno ();
2584 if (cstring_equalLit (id, "__asm")
2585 && !useparens && !usebraces)
2592 llassert ((useparens && ic == ')')
2593 || (usebraces && ic == '}')
2594 || (!useparens && !usebraces));
2598 else if (cstring_equalLit (id, "inline")
2599 || cstring_equalLit (id, "__inline")
2600 || cstring_equalLit (id, "_inline")
2601 || cstring_equalLit (id, "__inline__"))
2612 le = usymtab_lookupSafe (id);
2614 /*@-dependenttrans@*/
2616 if (uentry_isIter (le))
2621 else if (uentry_isEndIter (le))
2624 return (ITER_ENDNAME);
2626 else if (uentry_isUndefined (le))
2630 /* avoid parse errors for certain system built ins */
2632 if (g_expectingTypeName && (cstring_firstChar (id) == '_')
2633 && (cstring_secondChar (id) == '_'))
2635 return (TYPE_NAME_OR_ID);
2638 return (NEW_IDENTIFIER);
2640 else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
2642 if (uentry_isDatatype (le))
2645 return (NEW_IDENTIFIER);
2650 return (IDENTIFIER);
2653 else if (uentry_isDatatype (le))
2655 if (!g_expectingTypeName)
2659 return (NEW_IDENTIFIER);
2663 yylval.ctyp = uentry_getAbstractType (le);
2665 uentry_setUsed (le, g_currentloc);
2672 return (IDENTIFIER);
2675 /*@=dependenttrans@*/
2678 static bool processHashIdentifier (/*@only@*/ cstring id)
2680 if (context_inMacro () || context_inIterDef () ||
2681 context_inIterEnd ())
2685 context_clearJustPopped ();
2687 lastidprocessed = id;
2688 le = usymtab_lookupSafe (id);
2690 if (uentry_isParam (le) || uentry_isRefParam (le))
2707 static /*@only@*/ exprNode processString ()
2711 char *nl = strchr (yytext, '\n');
2712 cstring ns = cstring_fromCharsNew (yytext);
2716 loc = fileloc_copy (g_currentloc);
2717 addColumn (cstring_length (ns));
2723 loc = fileloc_copy (g_currentloc);
2725 context_incLineno ();
2727 while ((nl = strchr ((nl + 1), '\n')) != NULL)
2729 context_incLineno ();
2735 res = exprNode_stringLiteral (ns, loc);
2745 llassert (*yytext != '\0');
2746 fchar = *(yytext + 1);
2747 if (fchar != '\\') return fchar;
2749 next = *(yytext + 2);
2753 case 'n': return '\n';
2754 case 't': return '\t';
2755 case '\"': return '\"';
2756 case '\'': return '\'';
2757 case '\\': return '\\';
2758 default: return '\0';
2763 double processFloat ()
2765 double ret = atof (yytext);
2776 llassert (yytext[0] == '0'
2777 && (yytext[1] == 'X' || yytext[1] == 'x'));
2779 while (yytext[index] != '\0') {
2781 char c = yytext[index];
2783 if (c >= '0' && c <= '9') {
2784 tval = (int) c - (int) '0';
2785 } else if (c >= 'A' && c <= 'F') {
2786 tval = (int) c - (int) 'A' + 10;
2787 } else if (c >= 'a' && c <= 'f') {
2788 tval = (int) c - (int) 'a' + 10;
2792 message ("Invalid character (%c) in hex constant: %s",
2793 c, cstring_fromChars (yytext)),
2798 val = (val * 16) + tval;
2802 DPRINTF (("Hex constant: %s = %ld", yytext, val));
2807 long processOctal ()
2812 llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
2814 while (yytext[index] != '\0') {
2816 char c = yytext[index];
2818 if (c >= '0' && c <= '7') {
2819 tval = (int) c - (int) '0';
2823 message ("Invalid character (%c) in octal constant: %s",
2824 c, cstring_fromChars (yytext)),
2829 val = (val * 8) + tval;
2833 DPRINTF (("Octal constant: %s = %ld", yytext, val));
2840 return (atol (yytext));
2844 processSpec (int tok)
2846 size_t length = strlen (yytext);
2851 setTokLengthT (length);
2857 context_saveLocation ();
2858 setTokLengthT (length);
2859 return (processIdentifier (makeIdentifier (yytext)));