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"
187 "/*" { llfatalbug (cstring_makeLiteral ("Comment in pre-processor output")); }
189 "#"{Letter}({Letter}|{Digit})* {
190 context_saveLocation ();
191 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
193 if (processHashIdentifier (makeIdentifier (yytext + 1)))
201 RETURN_STRING (cstring_makeLiteral ("\"\""));
206 if (handleSpecial (yytext))
213 "#" { if (handleSpecial (yytext))
215 setTokLength (1); RETURN_TOK (0);
218 "..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); }
219 "break" { setTokLength (5); RETURN_TOK (BREAK); }
220 "case" { setTokLength (4); RETURN_TOK (CASE); }
221 "continue" { setTokLength (8); RETURN_TOK (CONTINUE); }
222 "default" { setTokLength (7); RETURN_TOK (DEFAULT); }
223 "do" { setTokLength (2); RETURN_TOK (DO); }
224 "else" { setTokLength (4); RETURN_TOK (CELSE); }
225 "for" { setTokLength (3); RETURN_TOK (CFOR); }
226 "goto" { setTokLength (4); RETURN_TOK (GOTO); }
227 "if" { setTokLength (2); RETURN_TOK (CIF); }
228 "return" { setTokLength (6); RETURN_TOK (RETURN); }
229 "sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); }
230 "offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); }
231 "switch" { setTokLength (6); RETURN_TOK (SWITCH); }
232 "while" { setTokLength (5); RETURN_TOK (WHILE); }
233 "va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); }
234 "va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); }
236 /* gcc extension...this might not be appropriate */
237 setTokLength (6); RETURN_TOK (QINLINE); }
239 "struct" { setTokLength (6); RETURN_TOK (CSTRUCT); }
240 "typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); }
242 "union" { setTokLength (5); RETURN_TOK (CUNION); }
243 "enum" { setTokLength (4); RETURN_TOK (CENUM); }
245 "void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); }
246 "int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); }
247 "double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); }
248 "char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); }
249 "float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); }
251 "long" { setTokLength (4); RETURN_TOK (QLONG); }
252 "short" { setTokLength (5); RETURN_TOK (QSHORT); }
253 "unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); }
254 "signed" { setTokLength (6); RETURN_TOK (QSIGNED); }
256 "volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); }
257 "const" { setTokLength (5); RETURN_TOK (QCONST); }
259 /* some systems expect this! [gack!] */
260 "__const" { setTokLength (7); RETURN_TOK (QCONST); }
262 "extern" { setTokLength (6); RETURN_TOK (QEXTERN); }
263 "auto" { setTokLength (4); RETURN_TOK (QAUTO); }
264 "register" { setTokLength (8); RETURN_TOK (QREGISTER); }
265 "static" { setTokLength (6); RETURN_TOK (QSTATIC); }
267 \"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
268 "out" { return (processSpec (QOUT)); }
269 "in" { return (processSpec (QIN)); }
270 "partial" { return (processSpec (QPARTIAL)); }
271 "special" { return (processSpec (QSPECIAL)); }
272 "anytype" { return (processSpec (QANYTYPE)); }
273 "integraltype" { return (processSpec (QINTEGRALTYPE)); }
274 "unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); }
275 "signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); }
276 "keep" { return (processSpec (QKEEP)); }
277 "null" { return (processSpec (QNULL)); }
278 "notnull" { return (processSpec (QNOTNULL)); }
279 "isnull" { return (processSpec (QISNULL)); }
280 "truenull" { return (processSpec (QTRUENULL)); }
281 "falsenull" { return (processSpec (QFALSENULL)); }
282 "relnull" { return (processSpec (QRELNULL)); }
283 "reldef" { return (processSpec (QRELDEF)); }
284 "exposed" { return (processSpec (QEXPOSED)); }
285 "newref" { return (processSpec (QNEWREF)); }
286 "tempref" { return (processSpec (QTEMPREF)); }
287 "killref" { return (processSpec (QKILLREF)); }
288 "refcounted" { return (processSpec (QREFCOUNTED)); }
289 "checked" { return (processSpec (QCHECKED)); }
290 "checkmod" { return (processSpec (QCHECKMOD)); }
291 "checkedstrict" { return (processSpec (QCHECKEDSTRICT)); }
292 "unchecked" { return (processSpec (QUNCHECKED)); }
293 "only" { return (processSpec (QONLY)); }
294 "owned" { return (processSpec (QOWNED)); }
295 "observer" { return (processSpec (QOBSERVER)); }
296 "dependent" { return (processSpec (QDEPENDENT)); }
297 "unused" { return (processSpec (QUNUSED)); }
298 "external" { return (processSpec (QEXTERNAL)); }
299 "sef" { return (processSpec (QSEF)); }
300 "shared" { return (processSpec (QSHARED)); }
301 "yield" { return (processSpec (QYIELD)); }
302 "undef" { return (processSpec (QUNDEF)); }
303 "killed" { return (processSpec (QKILLED)); }
304 "nullterminated" { return (processSpec (QNULLTERMINATED));}
305 "MaxSet" { return (processSpec (QMAXSET));}
306 "MaxRead" { return (processSpec (QMAXREAD));}
308 {Letter}({Letter}|{Digit})* { int tok;
309 context_saveLocation ();
310 setTokLength (longUnsigned_toInt (mstring_length (yytext)));
311 tok = processIdentifier (makeIdentifier (yytext));
317 0[xX]{H}+ { setTokLengthT (mstring_length (yytext));
318 RETURN_INT (ctype_int, processHex ()); /* evs 2000-05-17 was ctype_uint */
320 0[xX]{H}+{L} { setTokLengthT (mstring_length (yytext));
321 RETURN_INT (ctype_lint, processHex ()); }
322 0[xX]{H}+{L}{L} { setTokLengthT (mstring_length (yytext));
323 RETURN_INT (ctype_llint, processHex ()); }
324 0[xX]{H}+{U} { setTokLengthT (mstring_length (yytext));
325 RETURN_INT (ctype_uint, processHex ()); }
326 0[xX]{H}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
327 RETURN_INT (ctype_ulint, processHex ()); }
328 0[xX]{H}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
329 RETURN_INT (ctype_ullint, processHex ()); }
330 0[xX]{H}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
331 RETURN_INT (ctype_ullint, processHex ()); }
332 0{Digit}+ { setTokLengthT (mstring_length (yytext));
333 RETURN_INT (ctype_int, processOctal ()); }
334 0{Digit}+{U} { setTokLengthT (mstring_length (yytext));
335 RETURN_INT (ctype_uint, processOctal ()); }
336 0{Digit}+{L} { setTokLengthT (mstring_length (yytext));
337 RETURN_INT (ctype_lint, processOctal ()); }
338 0{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
339 RETURN_INT (ctype_llint, processOctal ()); }
340 0{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
341 RETURN_INT (ctype_ulint, processOctal ()); }
342 0{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
343 RETURN_INT (ctype_ullint, processOctal ()); }
344 0{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
345 RETURN_INT (ctype_ullint, processOctal ()); }
346 {Digit}+ { setTokLengthT (mstring_length (yytext));
347 RETURN_INT (ctype_int, processDec ()); }
348 {Digit}+{U} { setTokLengthT (mstring_length (yytext));
349 RETURN_INT (ctype_uint, processDec ()); }
350 {Digit}+{L} { setTokLengthT (mstring_length (yytext));
351 RETURN_INT (ctype_lint, processDec ()); }
352 {Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
353 RETURN_INT (ctype_llint, processDec ()); }
354 {Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
355 RETURN_INT (ctype_ulint, processDec ()); }
356 {Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
357 RETURN_INT (ctype_ullint, processDec ()); }
358 {Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
359 RETURN_INT (ctype_ullint, processDec ()); }
360 '(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
361 RETURN_CHAR (processChar ()); }
362 {Digit}+{E}[fF] { setTokLengthT (mstring_length (yytext));
363 RETURN_FLOAT (ctype_float, processFloat ()); }
364 {Digit}+{E}[lL] { setTokLengthT (mstring_length (yytext));
365 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
366 {Digit}+{E} { setTokLengthT (mstring_length (yytext));
367 RETURN_FLOAT (ctype_double, processFloat ()); }
369 {Digit}*"."{Digit}+({E})?[fF] { setTokLengthT (mstring_length (yytext));
370 RETURN_FLOAT (ctype_float, processFloat ()); }
371 {Digit}*"."{Digit}+({E})?[lL] { setTokLengthT (mstring_length (yytext));
372 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
373 {Digit}*"."{Digit}+({E})? { setTokLengthT (mstring_length (yytext));
374 RETURN_FLOAT (ctype_double, processFloat ()); }
376 {Digit}+"."{Digit}*({E})?[fF] { setTokLengthT (mstring_length (yytext));
377 RETURN_FLOAT (ctype_float, processFloat ()); }
378 {Digit}+"."{Digit}*({E})?[lL] { setTokLengthT (mstring_length (yytext));
379 RETURN_FLOAT (ctype_ldouble, processFloat ()); }
380 {Digit}+"."{Digit}*({E})? { setTokLengthT (mstring_length (yytext));
381 RETURN_FLOAT (ctype_double, processFloat ()); }
383 ">>=" { setTokLength (3); RETURN_TOK (RIGHT_ASSIGN); }
384 "<<=" { setTokLength (3); RETURN_TOK (LEFT_ASSIGN); }
385 "+=" { setTokLength (2); RETURN_TOK (ADD_ASSIGN); }
386 "-=" { setTokLength (2); RETURN_TOK (SUB_ASSIGN); }
387 "*=" { setTokLength (2); RETURN_TOK (MUL_ASSIGN); }
388 "/=" { setTokLength (2); RETURN_TOK (DIV_ASSIGN); }
389 "%=" { setTokLength (2); RETURN_TOK (MOD_ASSIGN); }
390 "&=" { setTokLength (2); RETURN_TOK (AND_ASSIGN); }
391 "^=" { setTokLength (2); RETURN_TOK (XOR_ASSIGN); }
392 "|=" { setTokLength (2); RETURN_TOK (OR_ASSIGN); }
393 ">>" { setTokLength (2); RETURN_TOK (RIGHT_OP); }
394 "<<" { setTokLength (2); RETURN_TOK (LEFT_OP); }
395 "++" { setTokLength (2); RETURN_TOK (INC_OP); }
396 "--" { setTokLength (2); RETURN_TOK (DEC_OP); }
397 "->" { setTokLength (2); RETURN_TOK (ARROW_OP); }
398 "&&" { setTokLength (2); RETURN_TOK (AND_OP); }
399 "||" { setTokLength (2); RETURN_TOK (OR_OP); }
400 "<=" { setTokLength (2); RETURN_TOK (LE_OP); }
401 ">=" { setTokLength (2); RETURN_TOK (GE_OP); }
402 "==" { setTokLength (2); RETURN_TOK (EQ_OP); }
403 "!=" { setTokLength (2); RETURN_TOK (NE_OP); }
404 ";" { setTokLength (1); RETURN_TOK (TSEMI); }
405 "{" { setTokLength (1); RETURN_TOK (TLBRACE); }
406 "}" { setTokLength (1); RETURN_TOK (TRBRACE); }
407 "," { setTokLength (1); RETURN_TOK (TCOMMA); }
408 ":" { setTokLength (1); RETURN_TOK (TCOLON); }
409 "=" { setTokLength (1); RETURN_TOK (TASSIGN); }
410 "(" { setTokLength (1); RETURN_TOK (TLPAREN); }
411 ")" { setTokLength (1); RETURN_TOK (TRPAREN); }
412 "[" { setTokLength (1); RETURN_TOK (TLSQBR); }
413 "]" { setTokLength (1); RETURN_TOK (TRSQBR); }
414 "." { setTokLength (1); RETURN_TOK (TDOT); }
415 "&" { setTokLength (1); RETURN_TOK (TAMPERSAND); }
416 "!" { setTokLength (1); RETURN_TOK (TEXCL); }
419 "~" { setTokLength (1); RETURN_TOK (TTILDE); }
420 "-" { setTokLength (1); RETURN_TOK (TMINUS); }
421 "+" { setTokLength (1); RETURN_TOK (TPLUS); }
422 "*" { setTokLength (1); RETURN_TOK (TMULT); }
423 "/" { setTokLength (1); RETURN_TOK (TDIV); }
424 "%" { setTokLength (1); RETURN_TOK (TPERCENT); }
425 "<" { setTokLength (1); RETURN_TOK (TLT); }
426 ">" { setTokLength (1); RETURN_TOK (TGT); }
427 "^" { setTokLength (1); RETURN_TOK (TCIRC); }
428 "|" { setTokLength (1); RETURN_TOK (TBAR); }
429 "?" { setTokLength (1); RETURN_TOK (TQUEST); }
431 [ \t\v\f] { incColumn (); }
432 \n { context_incLineno ();
435 continueLine = FALSE;
439 if (context_inMacro ())
441 /* Don't use RETURN_TOK */
442 yylval.tok = lltok_create (TENDMACRO, g_currentloc);
443 lastWasString = FALSE;
448 "@@MR@@" { setTokLength (6);
450 if (processMacro ()) {
451 if (context_inIterDef ())
453 RETURN_TOK (LLMACROITER);
455 if (context_inIterEnd ())
457 RETURN_TOK (LLMACROEND);
459 if (context_inMacro ())
461 RETURN_TOK (LLMACRO);
465 "@QLMR" { if (context_inHeader () || context_inFunction ())
471 int nspchar = ninput ();
475 ** This is a hack to get the column number correct.
478 llassert (nspchar >= '0' && nspchar <= '9');
480 nspaces = nspchar - '0';
482 setTokLength (5 + nspaces);
486 if (context_inIterDef ())
488 RETURN_TOK (LLMACROITER);
490 if (context_inIterEnd ())
492 RETURN_TOK (LLMACROEND);
494 if (context_inMacro ())
496 RETURN_TOK (LLMACRO);
501 "@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); }
502 "@.F" { setTokLength (3);
503 lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc)));
505 "@.L" { setTokLength (3); usymtab_printLocal (); }
506 "@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); }
507 "@.C" { setTokLength (3); lldiagmsg (context_unparse ()); }
508 "@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); }
509 "@.G" { setTokLength (3); usymtab_printGuards (); }
510 "@.S" { setTokLength (3); usymtab_printOut (); }
511 "@.X" { setTokLength (3); usymtab_printAll (); }
512 "@.Z" { setTokLength (3); usymtab_printComplete (); }
513 "@.T" { setTokLength (3); usymtab_printTypes (); }
514 "@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); }
515 "@.M" { setTokLength (3);
516 lldiagmsg (message ("Can modify: %q",
517 sRefSet_unparse (context_modList ())));
519 "%{" { /* BEFORE_COMMENT_MARKER */
521 incColumn (); incColumn ();
522 tok = handleLlSpecial ();
528 "%}" { /* AFTER_COMMENT_MARKER */
531 RETURN_TOK (QENDMACRO); }
532 "\\" { incColumn (); continueLine = TRUE; }
536 message ("Invalid character (ascii: %d), skipping character",
544 /*@null@*/ /*@observer@*/ char *name;
549 ** These tokens are followed by syntax that is parsed by the
553 struct skeyword s_parsetable[] = {
554 { "modifies", QMODIFIES } ,
555 { "globals", QGLOBALS } ,
557 { "constant", QCONSTANT } ,
558 { "function", QFUNCTION } ,
560 { "defines", QDEFINES } ,
562 { "allocates", QALLOCATES } ,
564 { "releases", QRELEASES } ,
565 { "pre", QPRECLAUSE } ,
566 { "post", QPOSTCLAUSE } ,
567 {"setBufferSize", QSETBUFFERSIZE},
568 {"bufferConstraint", QBUFFERCONSTRAINT},
569 {"ensuresConstraint", QENSURESCONSTRAINT},
570 {"setStringLength", QSETSTRINGLENGTH},
571 {"testinRange", QTESTINRANGE},
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 { "bufferConstraint", QBUFFERCONSTRAINT },
617 { "ensuresConstraint", QENSURESCONSTRAINT },
618 { "testInRange", QTESTINRANGE},
619 { "MaxSet", QMAXSET},
620 { "MaxRead", QMAXREAD},
621 { "reldef", QRELDEF } ,
622 { "observer", QOBSERVER } ,
623 { "exits", QEXITS } ,
624 { "mayexit", QMAYEXIT } ,
625 { "trueexit", QTRUEEXIT } ,
626 { "falseexit", QFALSEEXIT } ,
627 { "neverexit", QNEVEREXIT } ,
629 { "shared", QSHARED } ,
631 { "unchecked", QUNCHECKED } ,
632 { "checked", QCHECKED } ,
633 { "checkmod", QCHECKMOD } ,
634 { "checkedstrict", QCHECKEDSTRICT } ,
635 { "innercontinue", QINNERCONTINUE } ,
636 { "innerbreak", QINNERBREAK } ,
637 { "loopbreak", QLOOPBREAK } ,
638 { "switchbreak", QSWITCHBREAK } ,
639 { "safebreak", QSAFEBREAK } ,
640 { "fallthrough", QFALLTHROUGH } ,
641 { "l_fallthrou", QLINTFALLTHROUGH } ,
642 { "l_fallth", QLINTFALLTHRU } ,
643 { "notreached", QNOTREACHED } ,
644 { "l_notreach", QLINTNOTREACHED } ,
645 { "printflike", QPRINTFLIKE } ,
646 { "l_printfli", QLINTPRINTFLIKE } ,
647 { "scanflike", QSCANFLIKE } ,
648 { "messagelike", QMESSAGELIKE } ,
649 { "l_argsus", QARGSUSED } ,
654 ** would be better if these weren't hard coded...
657 static bool isArtificial (cstring s)
659 return (cstring_equalLit (s, "modifies")
660 || cstring_equalLit (s, "globals")
661 || cstring_equalLit (s, "alt"));
664 void swallowMacro (void)
667 bool skipnext = FALSE;
669 while ((i = lminput ()) != EOF)
686 checkUngetc (i, yyin);
694 checkUngetc (i, yyin);
698 static int commentMarkerToken (cstring s)
702 while (s_parsetable[i].name != NULL)
704 if (cstring_equalLit (s, s_parsetable[i].name))
706 return s_parsetable[i].token;
715 static int tokenMacroCode (cstring s)
719 while (s_keytable[i].name != NULL)
721 if (cstring_equalLit (s, s_keytable[i].name))
723 if (s_keytable[i].token == QLINTFALLTHROUGH)
726 (FLG_WARNLINTCOMMENTS,
728 ("Traditional lint comment /*FALLTHROUGH*/ used. "
729 "This is interpreted by "
730 "LCLint in the same way as most Unix lints, but it is "
731 "preferable to replace it with the /*@fallthrough@*/ "
736 else if (s_keytable[i].token == QLINTFALLTHRU)
739 (FLG_WARNLINTCOMMENTS,
741 ("Traditional lint comment /*FALLTHRU*/ used. "
742 "This is interpreted by "
743 "LCLint in the same way as most Unix lints, but it is "
744 "preferable to replace it with the /*@fallthrough@*/ "
749 else if (s_keytable[i].token == QLINTNOTREACHED)
752 (FLG_WARNLINTCOMMENTS,
754 ("Traditional lint comment /*NOTREACHED*/ used. "
755 "This is interpreted by "
756 "LCLint in the same way as most Unix lints, but it is "
757 "preferable to replace it with the /*@notreached@*/ "
758 "stylized comment."),
763 else if (s_keytable[i].token == QPRINTFLIKE)
765 setSpecialFunction (QU_PRINTFLIKE);
768 else if (s_keytable[i].token == QLINTPRINTFLIKE)
771 (FLG_WARNLINTCOMMENTS,
773 ("Traditional lint comment /*PRINTFLIKE*/ used. "
774 "This is interpreted by "
775 "LCLint in the same way as most Unix lints, but it is "
776 "preferable to replace it with either /*@printflike@*/, "
777 "/*@scanflike@*/ or /*@messagelike@*/."),
780 setSpecialFunction (QU_PRINTFLIKE);
783 else if (s_keytable[i].token == QSCANFLIKE)
785 setSpecialFunction (QU_SCANFLIKE);
788 else if (s_keytable[i].token == QMESSAGELIKE)
790 setSpecialFunction (QU_MESSAGELIKE);
793 else if (s_keytable[i].token == QARGSUSED)
796 (FLG_WARNLINTCOMMENTS,
798 ("Traditional lint comment /*ARGSUSED*/ used. "
799 "This is interpreted by "
800 "LCLint in the same way as most Unix lints, but it is "
801 "preferable to use /*@unused@*/ annotations on "
802 "the unused parameters."),
809 return s_keytable[i].token;
818 static int lminput ()
820 if (savechar == '\0')
827 int save = (int) savechar;
833 static void lmsavechar (char c)
835 if (savechar == '\0') savechar = c;
838 llbuglit ("lmsavechar: override");
842 static int returnFloat (ctype ct, double f)
844 yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext),
845 fileloc_decColumn (g_currentloc, tokLength));
850 static int returnInt (ctype ct, long i)
854 if (ctype_equal (ct, ctype_int))
858 c = context_typeofZero ();
862 c = context_typeofOne ();
866 yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext),
867 fileloc_decColumn (g_currentloc, tokLength), i);
872 static int returnChar (char c)
874 yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext),
875 fileloc_decColumn (g_currentloc, tokLength));
884 if (c != EOF && ((char)c == '\n'))
886 context_incLineno ();
892 static char macro_nextChar ()
894 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
899 c = char_fromInt (ic);
901 if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
905 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
907 ; /* skip to newline */
910 context_incLineno ();
914 return macro_nextChar ();
921 else /* if (c == '@') */
923 if (handleLlSpecial () != BADTOK)
925 llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
928 return macro_nextChar ();
931 else if (!in_escape && c == '\"')
933 in_quote = !in_quote;
935 else if (!in_escape && c == '\'')
939 else if ((in_quote || in_char) && c == '\\')
941 in_escape = !in_escape;
943 else if ((in_quote || in_char) && in_escape)
947 else if (!in_quote && c == '/')
951 if ((c2 = char_fromInt (lminput ())) == '*')
955 while ((c2 = char_fromInt (lminput ())) != '\0'
956 && c2 != '\n' && c2 != '*')
963 while ((c2 = char_fromInt (lminput ())) != '\0'
976 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
980 return macro_nextChar ();
984 /*** putchar does not work! why? puts to stdio...??! ***/
992 ** keeps stylized comments
995 static char macro_nextCharC ()
997 static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
1000 c = char_fromInt (lminput ());
1002 if (!in_quote && !in_char && c == '\\')
1004 while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
1006 ; /* skip to newline */
1009 context_incLineno ();
1013 return macro_nextCharC ();
1020 else if (!in_escape && c == '\"')
1022 in_quote = !in_quote;
1024 else if (!in_escape && c == '\'')
1028 else if ((in_quote || in_char) && c == '\\')
1030 in_escape = !in_escape;
1032 else if ((in_quote || in_char) && in_escape)
1036 else if (!in_quote && c == '/')
1040 if ((c2 = char_fromInt (lminput ())) == '*')
1044 while ((c2 = char_fromInt (lminput ())) != '\0'
1045 && c2 != '\n' && c2 != '*')
1052 while ((c2 = char_fromInt (lminput ())) != '\0'
1065 llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
1069 return macro_nextCharC ();
1080 ** skips whitespace (handles line continuations)
1081 ** returns first non-whitespace character
1084 static char skip_whitespace ()
1088 while ((c = macro_nextChar ()) == ' ' || c == '\t')
1096 static void handleMacro ()
1098 cstring mac = cstring_undefined;
1102 while (currentColumn () > 2)
1104 mac = cstring_appendChar (mac, ' ');
1108 c = macro_nextCharC ();
1110 if (c >= '0' && c <= '9')
1114 for (i = 0; i < ((c - '0') + 1); i++)
1116 mac = cstring_appendChar (mac, ' ');
1124 while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
1126 mac = cstring_appendChar (mac, c);
1130 macrocode = tokenMacroCode (mac);
1132 if (macrocode == BADTOK && !isArtificial (mac))
1134 DPRINTF (("Add macro: %s", mac));
1135 context_addMacroCache (mac);
1144 context_incLineno ();
1148 static bool processMacro (void)
1153 cstring fname = cstring_undefined;
1155 bool isspecfcn = FALSE;
1156 bool isiter = FALSE;
1157 bool skipparam = FALSE;
1158 bool isenditer = FALSE;
1159 bool unknownm = FALSE;
1160 bool hasParams = FALSE;
1161 bool emptyMacro = FALSE;
1162 char c = skip_whitespace ();
1163 fileloc loc = fileloc_noColumn (g_currentloc);
1165 /* are both of these necessary? what do they mean? */
1166 uentryList specparams = uentryList_undefined;
1167 uentryList pn = uentryList_undefined;
1169 context_resetMacroMissingParams ();
1171 if (c == '\0' || c == '\n')
1173 llcontbug (cstring_makeLiteral ("Bad macro"));
1178 fname = cstring_appendChar (fname, c);
1180 while ((c = macro_nextChar ()) != '(' && c != '\0'
1181 && c != ' ' && c != '\t' && c != '\n')
1183 fname = cstring_appendChar (fname, c);
1186 if (c == ' ' || c == '\t' || c == '\n')
1192 while (c == ' ' || c == '\t')
1194 c = macro_nextChar ();
1208 hasParams = (c == '(');
1211 if (usymtab_exists (fname))
1213 e2 = usymtab_lookupExpose (fname);
1214 ct = uentry_getType (e2);
1217 if (uentry_isCodeDefined (e2)
1218 && fileloc_isUser (uentry_whereDefined (e2)))
1222 message ("Macro %s already defined", fname),
1225 uentry_showWhereDefined (e2);
1226 uentry_clearDefined (e2);
1229 if (uentry_isFunction (e2))
1231 uentry_setType (e2, ctype_unknown);
1234 context_enterUnknownMacro (e2);
1238 context_enterConstantMacro (e2);
1243 if (uentry_isForward (e2) && uentry_isFunction (e2))
1250 ("Parameterized macro has no prototype or specification: %s ",
1255 uentry_setType (e2, ctype_unknown);
1256 uentry_setFunctionDefined (e2, loc);
1257 uentry_setUsed (e2, fileloc_undefined);
1258 context_enterUnknownMacro (e2);
1262 if (uentry_isIter (e2))
1265 specparams = uentry_getParams (e2);
1266 noparams = uentryList_size (specparams);
1267 uentry_setDefined (e2, loc);
1268 context_enterIterDef (e2);
1270 else if (uentry_isEndIter (e2))
1273 uentry_setDefined (e2, loc);
1274 context_enterIterEnd (e2); /* don't care about it now */
1275 /* but should parse like an iter! */
1277 else if (uentry_isConstant (e2))
1283 message ("Constant %s implemented as parameterized macro",
1287 uentry_showWhereSpecified (e2);
1288 uentry_setType (e2, ctype_unknown);
1289 uentry_makeVarFunction (e2);
1290 uentry_setDefined (e2, g_currentloc);
1291 uentry_setFunctionDefined (e2, g_currentloc);
1292 context_enterUnknownMacro (e2);
1296 if (!uentry_isSpecified (e2))
1298 fileloc oloc = uentry_whereDeclared (e2);
1300 if (fileloc_isLib (oloc))
1304 else if (fileloc_isUndefined (oloc)
1305 || fileloc_isPreproc (oloc))
1310 (FLG_MACROCONSTDECL,
1312 ("Macro constant %q not declared",
1313 uentry_getName (e2)),
1317 else if (!fileloc_withinLines (oloc, loc, 2))
1318 { /* bogus! will give errors if there is too much whitespace */
1322 ("Macro constant name %s does not match name in "
1323 "previous constant declaration. This constant "
1324 "is declared at %q", fname,
1325 fileloc_unparse (oloc)),
1330 context_enterConstantMacro (e2);
1331 cstring_free (fname);
1337 else if (ctype_isFunction (ct))
1340 specparams = ctype_argsFunction (ct);
1341 noparams = uentryList_size (specparams);
1343 uentry_setFunctionDefined (e2, loc);
1344 context_enterMacro (e2);
1346 else if (uentry_isVar (e2))
1352 message ("Variable %s implemented as parameterized macro",
1356 uentry_showWhereSpecified (e2);
1357 uentry_setType (e2, ctype_unknown);
1358 uentry_makeVarFunction (e2);
1359 uentry_setDefined (e2, g_currentloc);
1360 uentry_setFunctionDefined (e2, g_currentloc);
1361 context_enterUnknownMacro (e2);
1365 uentry ucons = uentry_makeConstant (fname,
1368 if (uentry_isExpandedMacro (e2))
1376 message ("Variable %s implemented by a macro",
1380 uentry_showWhereSpecified (e2);
1384 uentry_setDefined (e2, loc);
1385 uentry_setUsed (ucons, loc);
1387 context_enterConstantMacro (ucons);
1388 uentry_markOwned (ucons);
1389 cstring_free (fname);
1395 if (uentry_isDatatype (e2))
1399 message ("Type implemented as macro: %x",
1400 uentry_getName (e2)),
1401 message ("A type is implemented using a macro definition. A "
1402 "typedef should be used instead."),
1406 /* Must exit scope (not sure why a new scope was entered?) */
1407 usymtab_quietExitScope (g_currentloc);
1408 uentry_setDefined (e2, g_currentloc);
1414 (message ("Unexpanded macro not function or constant: %q",
1415 uentry_unparse (e2)));
1416 uentry_setType (e2, ctype_unknown);
1420 uentry_makeVarFunction (e2);
1421 uentry_setDefined (e2, g_currentloc);
1422 uentry_setFunctionDefined (e2, g_currentloc);
1423 context_enterUnknownMacro (e2);
1435 (FLG_MACROMATCHNAME,
1436 message ("Unexpanded macro %s does not match name of a constant "
1437 "or iter declaration. The name used in the control "
1438 "comment on the previous line should match. "
1439 "(Assuming macro defines a constant.)",
1444 ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
1445 uentry_setUsed (ce, loc); /* perhaps bogus? */
1446 e2 = usymtab_supEntryReturn (ce);
1448 context_enterConstantMacro (e2);
1449 cstring_free (fname);
1454 /* in macros, ( must follow immediatetly after name */
1460 c = skip_whitespace ();
1462 while (c != ')' && c != '\0')
1465 bool suppress = context_inSuppressRegion ();
1466 cstring paramname = cstring_undefined;
1469 ** save the parameter location
1473 context_saveLocation ();
1476 while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
1478 paramname = cstring_appendChar (paramname, c);
1479 c = macro_nextChar ();
1482 if (c == ' ' || c == '\t') c = skip_whitespace ();
1486 c = macro_nextChar ();
1487 if (c == ' ' || c == '\t') c = skip_whitespace ();
1492 llfatalerror (cstring_makeLiteral
1493 ("Bad macro syntax: uentryList"));
1496 if ((isspecfcn || isiter) && (paramno < noparams)
1497 && !uentry_isElipsisMarker (uentryList_getN
1498 (specparams, paramno)))
1500 uentry decl = uentryList_getN (specparams, paramno);
1503 param = uentry_nameCopy (paramname, decl);
1506 uentry_setParam (param);
1507 sr = sRef_makeParam (paramno, uentry_getType (param));
1509 if (sRef_getNullState (sr) == NS_ABSNULL)
1511 ctype pt = ctype_realType (uentry_getType (param));
1513 if (ctype_isUser (pt))
1515 uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
1517 if (uentry_isValid (te))
1519 sRef_setStateFromUentry (sr, te);
1524 sRef_setNullState (sr, NS_UNKNOWN, g_currentloc);
1528 uentry_setSref (param, sr);
1529 uentry_setDeclaredForceOnly (param, context_getSaveLocation ());
1531 skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
1535 fileloc sloc = context_getSaveLocation ();
1537 param = uentry_makeVariableSrefParam
1538 (paramname, ctype_unknown, sRef_makeParam (paramno, ctype_unknown));
1539 cstring_free (paramname);
1541 sRef_setPosNull (uentry_getSref (param), sloc);
1543 uentry_setDeclaredForce (param, sloc);
1546 fileloc_free (sloc);
1551 llassert (!uentry_isElipsisMarker (param));
1555 sRef_makeUnsafe (uentry_getSref (param));
1558 pn = uentryList_add (pn, uentry_copy (param));
1559 usymtab_supEntry (param);
1563 /* don't add param */
1564 uentry_free (param);
1569 (void) macro_nextChar ();
1570 c = skip_whitespace ();
1578 if (isspecfcn || isiter)
1580 if (paramno != noparams && noparams >= 0)
1586 message ("Macro %s specified with %d args, defined with %d",
1587 fname, noparams, paramno),
1590 uentry_showWhereSpecified (e2);
1591 uentry_resetParams (e2, pn);
1596 uentry_resetParams (e2, pn);
1603 ** the form should be:
1605 ** # define newname oldname
1606 ** where oldname refers to a function matching the specification
1612 sRef_setGlobalScope ();
1613 usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
1614 sRef_clearGlobalScope ();
1618 context_setMacroMissingParams ();
1623 /* context_setuentryList (pn); */
1624 usymtab_enterScope ();
1627 cstring_free (fname);
1632 static bool handleSpecial (char *yyt)
1634 char *l = mstring_create (MAX_NAME_LENGTH);
1635 static bool reportcpp = FALSE;
1641 strcpy (l, yyt + 1);
1643 /* Need to safe original l for deallocating. */
1646 l += strlen (yyt) - 1;
1648 while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
1654 olc = cstring_fromChars (ol);
1656 if (cstring_equalPrefix (olc, "pragma"))
1658 char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN));
1659 char *opname = pname;
1660 char *ptr = ol + 6; /* pragma is six characters, plus space */
1664 /* skip whitespace */
1665 while (((c = *ptr) != '\0') && isspace (c))
1671 while (((c = *ptr) != '\0') && !isspace (c))
1675 if (len > MAX_PRAGMA_LEN)
1686 if (len == PRAGMA_LEN_EXPAND
1687 && mstring_equal (opname, PRAGMA_EXPAND))
1689 cstring exname = cstring_undefined;
1693 while (((c = *ptr) != '\0') && !isspace (c))
1695 exname = cstring_appendChar (exname, c);
1700 ue = usymtab_lookupExposeGlob (exname);
1702 if (uentry_isExpandedMacro (ue))
1704 if (fileloc_isPreproc (uentry_whereDefined (ue)))
1706 fileloc_setColumn (g_currentloc, 1);
1707 uentry_setDefined (ue, g_currentloc);
1711 cstring_free (exname);
1714 else if (cstring_equalPrefix (olc, "ident"))
1716 /* Some pre-processors will leave these in the code. Ignore rest of line */
1719 ** Yuk...Win32 filenames can have spaces in them...we need to read
1720 ** to the matching end quote.
1722 else if ((sscanf (ol, "line %d \"", &lineno) == 1)
1723 || (sscanf (ol, " %d \"", &lineno) == 1))
1729 while (*tmp != '\"' && *tmp != '\0')
1734 llassert (*tmp == '\"');
1739 while (*tmp != '\"' && *tmp != '\0')
1744 llassert (*tmp == '\"');
1748 DPRINTF (("fname: %s", fname));
1750 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
1753 ** DOS-like path delimiters get delivered in pairs, something like
1754 ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
1755 ** remove the pre dirs yet as we usually specify tmp paths relative
1756 ** to the current directory, so tmp files would not get found in
1757 ** the hash table. If this method fails we try it again later.
1764 ** Skip past the drive marker.
1767 DPRINTF (("stmp: %s / %s", stmp, fname));
1769 if (strchr (stmp, ':') != NULL)
1771 stmp = strchr (stmp, ':') + 1;
1774 DPRINTF (("stmp: %s / %s", stmp, fname));
1776 while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
1778 if (*(stmp+1) == CONNECTCHAR)
1780 memmove (stmp, stmp+1, strlen (stmp));
1784 DPRINTF (("stmp: %s / %s", stmp, fname));
1787 DPRINTF (("Now: base = %s", fname));
1789 fid = fileTable_lookupBase (context_fileTable (),
1790 cstring_fromChars (fname));
1791 if (!(fileId_isValid (fid)))
1793 fname = removePreDirs (fname);
1794 fid = fileTable_lookupBase (context_fileTable (),
1795 cstring_fromChars (fname));
1798 # else /* !defined(OS2) && !defined(MSDOS) */
1799 fname = removePreDirs (fname);
1800 fid = fileTable_lookupBase (context_fileTable (),
1801 cstring_fromChars (fname));
1802 # endif /* !defined(OS2) && !defined(MSDOS) */
1804 if (!(fileId_isValid (fid)))
1806 if (isHeaderFile (cstring_fromChars (fname)))
1808 fid = fileTable_addHeaderFile (context_fileTable (),
1809 cstring_fromChars (fname));
1813 fid = fileTable_addFile (context_fileTable (),
1814 cstring_fromChars (fname));
1818 setFileLine (fid, lineno);
1820 else if ((sscanf (ol, "line %d", &lineno) == 1)
1821 || (sscanf (ol, " %d", &lineno) == 1))
1823 setLine (lineno); /* next line is <cr> */
1827 if (mstring_equal (ol, "")) {
1828 DPRINTF (("Empty pp command!"));
1830 ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
1831 ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
1840 llbug (message ("File contains preprocessor command: #%s",
1841 cstring_fromChars (ol)));
1854 static int handleLlSpecial ()
1858 char *s = mstring_createEmpty ();
1863 while (((ic = ninput ()) != 0) && isalpha (ic))
1866 s = mstring_append (s, c);
1872 if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
1876 llassert (ic == AFTER_COMMENT_MARKER[1]);
1879 if (isProcessingGlobMods () && (*s == '\0'))
1882 return QNOMODS; /* special token no modifications token */
1890 tok = commentMarkerToken (cstring_fromChars (os));
1894 tokLength = charsread;
1900 /* Add rest of the comment */
1902 if (ic != 0 && ic != EOF)
1907 s = mstring_append (s, c);
1910 while (((ic = ninput ()) != 0) && (ic != EOF)
1911 && (ic != AFTER_COMMENT_MARKER[0]))
1914 s = mstring_append (s, c);
1919 if (ic == AFTER_COMMENT_MARKER[0])
1922 llassert ((char) nc == AFTER_COMMENT_MARKER[1]);
1929 while (*s == ' ' || *s == '\t' || *s == '\n')
1934 if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
1938 while (c == '-' || c == '+' || c == '=')
1940 ynm set = ynm_fromCodeChar (c);
1945 thisflag = cstring_fromChars (s);
1947 while ((c = *s) != '\0' && (c != '-') && (c != '=')
1948 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
1955 if (!context_getFlag (FLG_NOCOMMENTS))
1957 cstring flagname = thisflag;
1958 flagcode fflag = identifyFlag (flagname);
1960 if (flagcode_isSkip (fflag))
1964 else if (flagcode_isInvalid (fflag))
1966 if (isMode (flagname))
1968 if (ynm_isMaybe (set))
1973 ("Stylized comment attempts to restore flag %s. "
1974 "A mode flag cannot be restored.",
1979 context_setMode (flagname);
1986 message ("Unrecognized option in stylized comment: %s",
1990 else if (flagcode_isGlobalFlag (fflag))
1995 ("Stylized comment attempts to set global flag %s. "
1996 "A global flag cannot be set locally.",
2001 context_fileSetFlag (fflag, set);
2003 if (flagcode_hasArgument (fflag))
2005 if (ynm_isMaybe (set))
2010 ("Stylized comment attempts to restore flag %s. "
2011 "A flag for setting a value cannot be restored.",
2015 { /* cut-and-pastied from llmain...blecch */
2016 cstring extra = cstring_undefined;
2022 rest = mstring_copy (s);
2026 while ((rchar = *rest) != '\0'
2027 && (isspace (rchar)))
2033 while ((rchar = *rest) != '\0'
2034 && !isspace (rchar))
2036 extra = cstring_appendChar (extra, rchar);
2043 if (cstring_isUndefined (extra))
2048 ("Flag %s (in stylized comment) must be followed by an argument",
2049 flagcode_unparse (fflag)));
2055 if (flagcode_hasValue (fflag))
2057 setValueFlag (fflag, extra);
2059 else if (flagcode_hasString (fflag))
2061 setStringFlag (fflag, extra);
2078 while ((c == ' ') || (c == '\t') || (c == '\n'))
2084 if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
2086 context_addComment (cstring_fromCharsNew (os));
2099 while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
2111 t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
2112 macrocode = tokenMacroCode (cstring_fromChars (t));
2114 if (macrocode != BADTOK)
2116 tokLength = mstring_length (t);
2122 if (macrocode == SKIPTOK)
2130 if (context_inHeader ())
2137 if ((context_inMacro () || context_inGlobalContext ())
2138 && macrocode != SKIPTOK
2139 && !isArtificial (cstring_fromChars (os)))
2141 context_addComment (cstring_fromCharsNew (os));
2154 if (mstring_equal (t, "ignore"))
2156 if (!context_getFlag (FLG_NOCOMMENTS))
2158 context_enterSuppressRegion ();
2161 else if ((*t == 'i' || *t == 't')
2162 && (*(t + 1) == '\0'))
2164 if (!context_getFlag (FLG_NOCOMMENTS)
2165 && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
2167 context_enterSuppressLine (-1); /* infinite suppression */
2170 else if (((*t == 'i') || (*t == 't'))
2171 && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
2173 bool tmpcomment = (*t == 't');
2175 char *tt = t; /* don't mangle t, since it is free'd */
2178 if (lc >= '0' && lc <= '9')
2180 val = (int)(lc - '0');
2183 while (lc >= '0' && lc <= '9')
2192 if (!context_getFlag (FLG_NOCOMMENTS)
2193 && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
2195 context_enterSuppressLine (val);
2198 else if (mstring_equal (t, "end"))
2200 if (!context_getFlag (FLG_NOCOMMENTS))
2202 context_exitSuppressRegion ();
2205 else if (mstring_equal (t, "notfunction"))
2207 ; /* handled by pcpp */
2209 else if (mstring_equal (t, "access"))
2215 while ((c = *s) && (c == ' ' || c == '\t' || c == '\n'))
2225 tname = cstring_fromChars (s);
2227 while ((c = *s) != '\0' && c != ' '
2228 && c != '\t' && c != '\n' && c != ',')
2236 if (!context_getFlag (FLG_NOCOMMENTS)
2237 && !context_getFlag (FLG_NOACCESS))
2239 if (usymtab_existsType (tname))
2241 usymId uid = usymtab_getTypeId (tname);
2242 context_addFileAccessType (uid);
2246 if (!(context_inSuppressRegion ()
2247 || context_inSuppressZone (g_currentloc)))
2251 ("%q: Unrecognized type %s used in access comment",
2252 fileloc_unparse (g_currentloc), tname));
2262 if (c != ',' && c != ' ')
2268 else if (mstring_equal (t, "noaccess"))
2275 while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n'))
2285 tname = cstring_fromChars (s);
2287 while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
2288 && lc != '\n' && lc != ',')
2295 if (!context_getFlag (FLG_NOCOMMENTS)
2296 && !context_getFlag (FLG_NOACCESS))
2298 if (usymtab_existsType (tname))
2300 typeId tuid = usymtab_getTypeId (tname);
2302 if (context_couldHaveAccess (tuid))
2304 context_removeFileAccessType (tuid);
2308 if (!(context_inSuppressRegion ()
2309 || context_inSuppressZone (g_currentloc)))
2311 uentry ue = usymtab_getTypeEntry (tuid);
2313 if (uentry_isAbstractDatatype (ue))
2317 ("%q: Non-accessible abstract type %s used in noaccess comment",
2318 fileloc_unparse (g_currentloc), tname));
2324 ("%q: Non-abstract type %s used in noaccess comment",
2325 fileloc_unparse (g_currentloc), tname));
2332 if (!(context_inSuppressRegion ()
2333 || context_inSuppressZone (g_currentloc)))
2337 ("%q: Unrecognized type %s used in noaccess comment",
2338 fileloc_unparse (g_currentloc), tname));
2348 if (lc != ',' && lc != ' ')
2356 setTokLength (- (2 + charsread));
2358 voptgenerror (FLG_UNRECOGCOMMENTS,
2359 message ("Stylized comment unrecognized: %s",
2360 cstring_fromChars (os)),
2371 static /*@only@*/ cstring makeIdentifier (char *s)
2373 char *c = mstring_create (size_toInt (strlen (s)) + 1);
2374 cstring id = cstring_fromChars (c);
2376 while (isalnum (*s) || (*s == '_') || (*s == '$'))
2385 /*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn)
2387 if (!(usymtab_exists (cn)))
2389 fileloc loc = fileloc_createExternal ();
2392 ** We need to put this in a global scope, otherwise the sRef will be deallocated.
2395 uentry ce = uentry_makeUnrecognized (cn, loc);
2397 if (!context_inIterEnd ())
2401 message ("Unrecognized (possibly system) identifier: %q",
2402 uentry_getName (ce)),
2409 return (usymtab_lookup (cn));
2413 ** like, coerceId, but doesn't supercede for iters
2416 /*@observer@*/ uentry coerceIterId (cstring cn)
2418 if (!(usymtab_exists (cn)))
2420 return uentry_undefined;
2423 return (usymtab_lookup (cn));
2426 /*@observer@*/ cstring LastIdentifier ()
2428 return (lastidprocessed);
2431 static int processIdentifier (cstring id)
2435 DPRINTF (("Process identifier: %s", id));
2437 context_clearJustPopped ();
2438 lastidprocessed = id;
2440 if (context_inFunctionDecl ())
2442 int tok = commentMarkerToken (id);
2450 tok = tokenMacroCode (id);
2459 /* Consider handling: Defined by C99 as static const char __func__[] */
2461 if (context_getFlag (FLG_GNUEXTENSIONS))
2465 if (cstring_equalLit (id, "__stdcall")
2466 || cstring_equalLit (id, "__cdecl")
2467 || cstring_equalLit (id, "__extension__"))
2471 else if (cstring_equalLit (id, "__volatile__"))
2475 else if (cstring_equalLit (id, "__signed"))
2479 else if (cstring_equalLit (id, "__unsigned"))
2483 else if (cstring_equalLit (id, "__const__"))
2487 else if (cstring_equalLit (id, "__alignof__"))
2489 tok = CALIGNOF; /* alignof is parsed like sizeof */
2491 else if (cstring_equalLit (id, "__FUNCTION__")
2492 || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
2494 /* These tokens hold the name of the current function as strings */
2495 yylval.expr = exprNode_stringLiteral (id, fileloc_copy (g_currentloc));
2497 lastWasString = TRUE;
2501 else if (cstring_equalLit (id, "__attribute__")
2502 || cstring_equalLit (id, "__asm__")
2503 || cstring_equalLit (id, "_asm")
2504 || cstring_equalLit (id, "__asm")
2505 || cstring_equalLit (id, "__declspec"))
2508 bool useparens = FALSE;
2509 bool usebraces = FALSE;
2510 bool inquote = FALSE;
2511 bool inescape = FALSE;
2514 while ((ic = input ()) != EOF)
2521 else if (ic == '\\')
2525 else if (ic == '\"')
2561 else if (ic == ')' && useparens)
2564 if (depth == 0) break;
2566 else if (ic == '}' && usebraces)
2569 if (depth == 0) break;
2572 && !usebraces && !useparens
2573 && cstring_equalLit (id, "__asm"))
2576 ** We need this because some MS VC++ include files
2577 ** have __asm mov ... }
2578 ** Its a kludge, but otherwise would need to parse
2587 context_incLineno ();
2589 if (cstring_equalLit (id, "__asm")
2590 && !useparens && !usebraces)
2597 llassert ((useparens && ic == ')')
2598 || (usebraces && ic == '}')
2599 || (!useparens && !usebraces));
2603 else if (cstring_equalLit (id, "inline")
2604 || cstring_equalLit (id, "__inline")
2605 || cstring_equalLit (id, "_inline")
2606 || cstring_equalLit (id, "__inline__"))
2617 le = usymtab_lookupSafe (id);
2619 /*@-dependenttrans@*/
2621 if (uentry_isIter (le))
2626 else if (uentry_isEndIter (le))
2629 return (ITER_ENDNAME);
2631 else if (uentry_isUndefined (le))
2635 /* avoid parse errors for certain system built ins */
2637 if (g_expectingTypeName && (cstring_firstChar (id) == '_')
2638 && (cstring_secondChar (id) == '_'))
2640 return (TYPE_NAME_OR_ID);
2643 return (NEW_IDENTIFIER);
2645 else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
2647 if (uentry_isDatatype (le))
2650 return (NEW_IDENTIFIER);
2655 return (IDENTIFIER);
2658 else if (uentry_isDatatype (le))
2660 if (!g_expectingTypeName)
2664 return (NEW_IDENTIFIER);
2668 yylval.ctyp = uentry_getAbstractType (le);
2670 uentry_setUsed (le, g_currentloc);
2677 return (IDENTIFIER);
2680 /*@=dependenttrans@*/
2683 static bool processHashIdentifier (/*@only@*/ cstring id)
2685 if (context_inMacro () || context_inIterDef () ||
2686 context_inIterEnd ())
2690 context_clearJustPopped ();
2692 lastidprocessed = id;
2693 le = usymtab_lookupSafe (id);
2695 if (uentry_isParam (le) || uentry_isRefParam (le))
2712 static /*@only@*/ exprNode processString ()
2716 char *nl = strchr (yytext, '\n');
2717 cstring ns = cstring_fromCharsNew (yytext);
2721 loc = fileloc_copy (g_currentloc);
2722 addColumn (cstring_length (ns));
2728 loc = fileloc_copy (g_currentloc);
2730 context_incLineno ();
2732 while ((nl = strchr ((nl + 1), '\n')) != NULL)
2734 context_incLineno ();
2740 res = exprNode_stringLiteral (ns, loc);
2750 llassert (*yytext != '\0');
2751 fchar = *(yytext + 1);
2752 if (fchar != '\\') return fchar;
2754 next = *(yytext + 2);
2758 case 'n': return '\n';
2759 case 't': return '\t';
2760 case '\"': return '\"';
2761 case '\'': return '\'';
2762 case '\\': return '\\';
2763 default: return '\0';
2768 double processFloat ()
2770 double ret = atof (yytext);
2781 llassert (yytext[0] == '0'
2782 && (yytext[1] == 'X' || yytext[1] == 'x'));
2784 while (yytext[index] != '\0') {
2786 char c = yytext[index];
2788 if (c >= '0' && c <= '9') {
2789 tval = (int) c - (int) '0';
2790 } else if (c >= 'A' && c <= 'F') {
2791 tval = (int) c - (int) 'A' + 10;
2792 } else if (c >= 'a' && c <= 'f') {
2793 tval = (int) c - (int) 'a' + 10;
2794 } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2796 while (yytext[index] != '\0') {
2797 if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2802 message ("Invalid character (%c) following specifier in hex constant: %s",
2803 c, cstring_fromChars (yytext)),
2813 message ("Invalid character (%c) in hex constant: %s",
2814 c, cstring_fromChars (yytext)),
2819 val = (val * 16) + tval;
2823 DPRINTF (("Hex constant: %s = %ld", yytext, val));
2828 long processOctal ()
2833 llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
2835 while (yytext[index] != '\0') {
2837 char c = yytext[index];
2839 if (c >= '0' && c <= '7') {
2840 tval = (int) c - (int) '0';
2844 message ("Invalid character (%c) in octal constant: %s",
2845 c, cstring_fromChars (yytext)),
2850 val = (val * 8) + tval;
2854 DPRINTF (("Octal constant: %s = %ld", yytext, val));
2861 return (atol (yytext));
2865 processSpec (int tok)
2867 size_t length = strlen (yytext);
2872 setTokLengthT (length);
2878 context_saveLocation ();
2879 setTokLengthT (length);
2880 return (processIdentifier (makeIdentifier (yytext)));