/*;-*-C-*-; ** Splint - annotation-assisted static program checker ** Copyright (C) 1994-2002 University of Virginia, ** Massachusetts Institute of Technology ** ** This program is free software; you can redistribute it and/or modify it ** under the terms of the GNU General Public License as published by the ** Free Software Foundation; either version 2 of the License, or (at your ** option) any later version. ** ** This program is distributed in the hope that it will be useful, but ** WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** ** The GNU General Public License is available from http://www.gnu.org/ or ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ** MA 02111-1307, USA. ** ** For information on splint: splint@cs.virginia.edu ** To report a bug: splint-bug@cs.virginia.edu ** For more information: http://www.splint.org */ /* ** cscanner.l ** ** Flex lexer for C. ** Based on a C lexer by Nate Osgood ** from hacrat@catfish.lcs.mit.edu Mon Jun 14 13:06:32 1993 */ /* ** Modified by Herbert 08/19/97: ** - added #include for IBM's OS/2 compiler. ** - fixed weird bug with lookup of tmp files (OS/2 and MSDOS only). */ /* ** Modified by Mike Smith ** Corrected missing 'line' in scanf() calls in handleSpecial(). ** Without this, I get an error when Splint hits a '#line' directive ** in the pre-pre-processed source files. For safety, I have made these ** conditional on OS2 and MSDOS because I don't understand why noone else ** has seen this problem. ** ** Modified by Mike Smith, 4th June 1997 ** Finally resolved the #line problem. The scanf() calls have been fixed to ** allow the following #line forms:- ** ** #line 123 "filename" ** #line 123 ** # 123 "filename" ** # 123 ** ** The last two are generated by the GNU pre-processor, apparently */ Digit [0-9] Letter [a-zA-Z_$] H [a-fA-F0-9] E [Ee][+-]?{Digit}+ U (u|U) L (l|L) FS (f|F|l|L) IS (u|U|l|L)* ULSuffix ({U}{L}|{L}{U}) %{ # include "splintMacros.nf" # if defined(OS2) && defined(__IBMC__) /* needed for isatty()... */ # include # else /* ** Win32 doesn't have unistd.h */ # ifndef WIN32 # include # endif # endif # include "basic.h" # include "cgrammar.h" # include "cgrammar_tokens.h" # include "portab.h" static bool lastWasString = FALSE; static char savechar = '\0'; /*@notfunction@*/ # define yyinput() (incColumn (), getc (yyin)) static /*@owned@*/ cstring lastidprocessed = cstring_undefined; static int lminput (void); static int tokLength = 0; static bool inSpecPart = FALSE; static bool continueLine = FALSE; static int ninput (void); static char processChar (void); static double processFloat (void); static /*@only@*/ exprNode processString (void) ; static /*@only@*/ exprNode processWideString (void) ; static long processDec (void); static long processHex (void); static long processOctal (void); static int processIdentifier (/*@only@*/ cstring) /*@globals undef lastidprocessed@*/ ; static bool processHashIdentifier (/*@only@*/ cstring) /*@globals undef lastidprocessed@*/ ; static int processSpec (int); static bool handleSpecial (char *); static int handleLlSpecial (void); static void handleMacro (void); static bool processMacro (void); static /*@only@*/ cstring makeIdentifier (char *); /* yes, this is exported! */ bool g_expectingTypeName = TRUE; /* beginning of file can be type name! */ static bool expectingMetaStateName = FALSE; static int returnInt (ctype, long); static int returnFloat (ctype, double); static int returnChar (char); static void setTokLength (int) /*@modifies g_currentloc@*/ ; static void setTokLengthT (size_t) /*@modifies g_currentloc@*/ ; static void advanceLine (void) { tokLength = 0; beginLine (); } /*@-allmacros@*/ # define RETURN_INT(c,i) \ do { lastWasString = FALSE; \ return (returnInt (c, i)); } while (FALSE) # define RETURN_FLOAT(c,f) \ do { lastWasString = FALSE; \ return (returnFloat (c, f)); \ } while (FALSE) # define RETURN_CHAR(c) \ do { lastWasString = FALSE; \ return (returnChar (c)); \ } while (FALSE) # define RETURN_TOK(t) \ do { yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, tokLength)); \ tokLength = 0; \ lastWasString = FALSE; \ return (t); } while (FALSE) # define RETURN_TYPE(t, ct) \ do { yylval.ctyp = ct; tokLength = 0; return (t); } while (FALSE) /* don't fileloc_decColumn (g_currentloc, tokLength)); the string could have \n's in it! */ # define RETURN_STRING(c) \ do { yylval.expr = exprNode_stringLiteral (c, fileloc_decColumn (g_currentloc, tokLength)); \ tokLength = 0; \ lastWasString = TRUE; \ return (CCONSTANT); } while (FALSE) # define RETURN_EXPR(e) \ do { yylval.expr = e; \ tokLength = 0; \ lastWasString = TRUE; \ return (CCONSTANT); } while (FALSE) /*@=allmacros@*/ static void setTokLength (int len) { addColumn (len); tokLength = len; DPRINTF (("Set tok length: %d", len)); } static void setTokLengthT (size_t len) { setTokLength (size_toInt (len)); } # include "flex.head" /*@-unrecog@*/ /*@i5343@*/ %} %% "/*" { llfatalerror (cstring_makeLiteral ("Comment in pre-processor output")); } "#"{Letter}({Letter}|{Digit})* { context_saveLocation (); setTokLength (longUnsigned_toInt (mstring_length (yytext))); if (processHashIdentifier (makeIdentifier (yytext + 1))) { if (lastWasString) { /* was nothing! */ /*@i32@*/ RETURN_STRING (cstring_makeLiteral ("\"\"")); } else { RETURN_STRING (cstring_makeLiteral ("\"\"")); } } else { if (handleSpecial (yytext)) { setTokLength (1); RETURN_TOK (0); } } } "#" { if (handleSpecial (yytext)) { setTokLength (1); RETURN_TOK (0); } } "..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); } "break" { setTokLength (5); RETURN_TOK (BREAK); } "case" { setTokLength (4); RETURN_TOK (CASE); } "continue" { setTokLength (8); RETURN_TOK (CONTINUE); } "default" { setTokLength (7); RETURN_TOK (DEFAULT); } "do" { setTokLength (2); RETURN_TOK (DO); } "else" { setTokLength (4); RETURN_TOK (CELSE); } "for" { setTokLength (3); RETURN_TOK (CFOR); } "goto" { setTokLength (4); RETURN_TOK (GOTO); } "if" { setTokLength (2); RETURN_TOK (CIF); } "return" { setTokLength (6); RETURN_TOK (RETURN); } "sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); } "offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); } "switch" { setTokLength (6); RETURN_TOK (SWITCH); } "while" { setTokLength (5); RETURN_TOK (WHILE); } "va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); } "va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); } "inline" { /* gcc extension...this might not be appropriate */ setTokLength (6); RETURN_TOK (QINLINE); } "struct" { setTokLength (6); RETURN_TOK (CSTRUCT); } "typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); } "union" { setTokLength (5); RETURN_TOK (CUNION); } "enum" { setTokLength (4); RETURN_TOK (CENUM); } "void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); } "int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); } "double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); } "char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); } "float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); } "long" { setTokLength (4); RETURN_TOK (QLONG); } "short" { setTokLength (5); RETURN_TOK (QSHORT); } "unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); } "signed" { setTokLength (6); RETURN_TOK (QSIGNED); } "volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); } "const" { setTokLength (5); RETURN_TOK (QCONST); } /* some systems expect this! [gack!] */ "__const" { setTokLength (7); RETURN_TOK (QCONST); } "extern" { setTokLength (6); RETURN_TOK (QEXTERN); } "auto" { setTokLength (4); RETURN_TOK (QAUTO); } "register" { setTokLength (8); RETURN_TOK (QREGISTER); } "static" { setTokLength (6); RETURN_TOK (QSTATIC); } \"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); } L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processWideString ()); } "out" { return (processSpec (QOUT)); } "in" { return (processSpec (QIN)); } "partial" { return (processSpec (QPARTIAL)); } "special" { return (processSpec (QSPECIAL)); } "anytype" { return (processSpec (QANYTYPE)); } "integraltype" { return (processSpec (QINTEGRALTYPE)); } "unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); } "signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); } "keep" { return (processSpec (QKEEP)); } "null" { return (processSpec (QNULL)); } "notnull" { return (processSpec (QNOTNULL)); } "isnull" { return (processSpec (QISNULL)); } "truenull" { return (processSpec (QTRUENULL)); } "falsenull" { return (processSpec (QFALSENULL)); } "nullwhentrue" { return (processSpec (QTRUENULL)); } "nullwhenfalse" { return (processSpec (QFALSENULL)); } "relnull" { return (processSpec (QRELNULL)); } "reldef" { return (processSpec (QRELDEF)); } "exposed" { return (processSpec (QEXPOSED)); } "newref" { return (processSpec (QNEWREF)); } "tempref" { return (processSpec (QTEMPREF)); } "killref" { return (processSpec (QKILLREF)); } "refcounted" { return (processSpec (QREFCOUNTED)); } "checked" { return (processSpec (QCHECKED)); } "checkmod" { return (processSpec (QCHECKMOD)); } "checkedstrict" { return (processSpec (QCHECKEDSTRICT)); } "unchecked" { return (processSpec (QUNCHECKED)); } "only" { return (processSpec (QONLY)); } "owned" { return (processSpec (QOWNED)); } "observer" { return (processSpec (QOBSERVER)); } "dependent" { return (processSpec (QDEPENDENT)); } "unused" { return (processSpec (QUNUSED)); } "external" { return (processSpec (QEXTERNAL)); } "sef" { return (processSpec (QSEF)); } "shared" { return (processSpec (QSHARED)); } "yield" { return (processSpec (QYIELD)); } "undef" { return (processSpec (QUNDEF)); } "killed" { return (processSpec (QKILLED)); } "nullterminated" { return (processSpec (QNULLTERMINATED));} "MaxSet" { return (processSpec (QMAXSET));} "MaxRead" { return (processSpec (QMAXREAD));} "maxSet" { return (processSpec (QMAXSET));} "maxRead" { return (processSpec (QMAXREAD));} {Letter}({Letter}|{Digit})* { int tok; context_saveLocation (); setTokLength (longUnsigned_toInt (mstring_length (yytext))); tok = processIdentifier (makeIdentifier (yytext)); if (tok != BADTOK) { return (tok); } } 0[xX]{H}+ { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_int, processHex ()); /* evs 2000-05-17 was ctype_uint */ } 0[xX]{H}+{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_lint, processHex ()); } 0[xX]{H}+{L}{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_llint, processHex ()); } 0[xX]{H}+{U} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_uint, processHex ()); } 0[xX]{H}+{ULSuffix} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ulint, processHex ()); } 0[xX]{H}+{U}{L}{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ullint, processHex ()); } 0[xX]{H}+{L}{L}{U} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ullint, processHex ()); } 0{Digit}+ { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_int, processOctal ()); } 0{Digit}+{U} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_uint, processOctal ()); } 0{Digit}+{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_lint, processOctal ()); } 0{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_llint, processOctal ()); } 0{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ulint, processOctal ()); } 0{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ullint, processOctal ()); } 0{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ullint, processOctal ()); } {Digit}+ { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_int, processDec ()); } {Digit}+{U} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_uint, processDec ()); } {Digit}+{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_lint, processDec ()); } {Digit}+{L}{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_llint, processDec ()); } {Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ulint, processDec ()); } {Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ullint, processDec ()); } {Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext)); RETURN_INT (ctype_ullint, processDec ()); } '(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext)); RETURN_CHAR (processChar ()); } L'(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext)); RETURN_CHAR (processChar ()); } {Digit}+{E}[fF] { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_float, processFloat ()); } {Digit}+{E}[lL] { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_ldouble, processFloat ()); } {Digit}+{E} { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_double, processFloat ()); } {Digit}*"."{Digit}+({E})?[fF] { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_float, processFloat ()); } {Digit}*"."{Digit}+({E})?[lL] { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_ldouble, processFloat ()); } {Digit}*"."{Digit}+({E})? { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_double, processFloat ()); } {Digit}+"."{Digit}*({E})?[fF] { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_float, processFloat ()); } {Digit}+"."{Digit}*({E})?[lL] { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_ldouble, processFloat ()); } {Digit}+"."{Digit}*({E})? { setTokLengthT (mstring_length (yytext)); RETURN_FLOAT (ctype_double, processFloat ()); } ">>=" { setTokLength (3); RETURN_TOK (RIGHT_ASSIGN); } "<<=" { setTokLength (3); RETURN_TOK (LEFT_ASSIGN); } "+=" { setTokLength (2); RETURN_TOK (ADD_ASSIGN); } "-=" { setTokLength (2); RETURN_TOK (SUB_ASSIGN); } "*=" { setTokLength (2); RETURN_TOK (MUL_ASSIGN); } "/=" { setTokLength (2); RETURN_TOK (DIV_ASSIGN); } "%=" { setTokLength (2); RETURN_TOK (MOD_ASSIGN); } "&=" { setTokLength (2); RETURN_TOK (AND_ASSIGN); } "^=" { setTokLength (2); RETURN_TOK (XOR_ASSIGN); } "|=" { setTokLength (2); RETURN_TOK (OR_ASSIGN); } ">>" { setTokLength (2); RETURN_TOK (RIGHT_OP); } "<<" { setTokLength (2); RETURN_TOK (LEFT_OP); } "++" { setTokLength (2); RETURN_TOK (INC_OP); } "--" { setTokLength (2); RETURN_TOK (DEC_OP); } "->" { setTokLength (2); RETURN_TOK (ARROW_OP); } "&&" { setTokLength (2); RETURN_TOK (AND_OP); } "||" { setTokLength (2); RETURN_TOK (OR_OP); } "<=" { setTokLength (2); RETURN_TOK (LE_OP); } ">=" { setTokLength (2); RETURN_TOK (GE_OP); } "==" { setTokLength (2); RETURN_TOK (EQ_OP); } "!=" { setTokLength (2); RETURN_TOK (NE_OP); } ";" { setTokLength (1); RETURN_TOK (TSEMI); } "{" { setTokLength (1); RETURN_TOK (TLBRACE); } "}" { setTokLength (1); RETURN_TOK (TRBRACE); } "," { setTokLength (1); RETURN_TOK (TCOMMA); } ":" { setTokLength (1); RETURN_TOK (TCOLON); } "=" { setTokLength (1); RETURN_TOK (TASSIGN); } "(" { setTokLength (1); RETURN_TOK (TLPAREN); } ")" { setTokLength (1); RETURN_TOK (TRPAREN); } "[" { setTokLength (1); RETURN_TOK (TLSQBR); } "]" { setTokLength (1); RETURN_TOK (TRSQBR); } "." { setTokLength (1); RETURN_TOK (TDOT); } "&" { setTokLength (1); RETURN_TOK (TAMPERSAND); } "!" { setTokLength (1); RETURN_TOK (TEXCL); } "~" { setTokLength (1); RETURN_TOK (TTILDE); } "-" { setTokLength (1); RETURN_TOK (TMINUS); } "+" { setTokLength (1); RETURN_TOK (TPLUS); } "*" { setTokLength (1); RETURN_TOK (TMULT); } "/" { setTokLength (1); RETURN_TOK (TDIV); } "%" { setTokLength (1); RETURN_TOK (TPERCENT); } "<" { setTokLength (1); RETURN_TOK (TLT); } ">" { setTokLength (1); RETURN_TOK (TGT); } "^" { setTokLength (1); RETURN_TOK (TCIRC); } "|" { setTokLength (1); RETURN_TOK (TBAR); } "?" { setTokLength (1); RETURN_TOK (TQUEST); } "/\\" { setTokLength (1); RETURN_TOK (TCAND); } [ \t\v\f] { incColumn (); } \n { context_incLineno (); if (tokLength != 0) { tokLength = 0; /* No error to report voptgenerror (FLG_SYNTAX, message ("Likely parse error: token spans multiple lines."), g_currentloc); */ } if (continueLine) { continueLine = FALSE; } else { if (context_inMacro ()) { /* Don't use RETURN_TOK */ yylval.tok = lltok_create (TENDMACRO, fileloc_copy (g_currentloc)); /* !!! evans 2002-03-13 */ lastWasString = FALSE; return (TENDMACRO); } } } "@@MR@@" { setTokLength (6); if (processMacro ()) { if (context_inIterDef ()) { RETURN_TOK (LLMACROITER); } if (context_inIterEnd ()) { RETURN_TOK (LLMACROEND); } if (context_inMacro ()) { RETURN_TOK (LLMACRO); } } } "@QLMR" { if (context_inHeader () || context_inFunction ()) { handleMacro (); } else { int nspchar = ninput (); int nspaces; /* ** This is a hack to get the column number correct. */ llassert (nspchar >= '0' && nspchar <= '9'); nspaces = nspchar - '0'; setTokLength (5 + nspaces); if (processMacro ()) { DPRINTF (("Here we are: %s", context_unparse ())); if (context_inIterDef ()) { RETURN_TOK (LLMACROITER); } if (context_inIterEnd ()) { RETURN_TOK (LLMACROEND); } if (context_inMacro ()) { RETURN_TOK (LLMACRO); } } } } "@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); } "@.FA" { setTokLength (4); lldiagmsg (message ("Access types: %q", typeIdSet_unparse (context_fileAccessTypes ()))); } "@.F" { setTokLength (3); lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc))); } "@.L" { setTokLength (3); usymtab_printLocal (); } "@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); } "@.C" { setTokLength (3); lldiagmsg (context_unparse ()); } "@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); } "@.G" { setTokLength (3); usymtab_printGuards (); } "@.S" { setTokLength (3); usymtab_printOut (); } "@.X" { setTokLength (3); usymtab_printAll (); } "@.Z" { setTokLength (3); usymtab_printComplete (); } "@.T" { setTokLength (3); usymtab_printTypes (); } "@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); } "@.M" { setTokLength (3); lldiagmsg (message ("Can modify: %q", sRefSet_unparse (context_modList ()))); } "%{" { /* BEFORE_COMMENT_MARKER */ int tok; incColumn (); incColumn (); tok = handleLlSpecial (); if (tok != BADTOK) { if (tok == CANNOTATION) { return (tok); } else { /* Beware - this bashes yylval! */ RETURN_TOK (tok); } } } "%}" { /* AFTER_COMMENT_MARKER */ setTokLength (2); inSpecPart = FALSE; RETURN_TOK (QENDMACRO); } "\\" { incColumn (); continueLine = TRUE; } . { incColumn (); if ((int) *yytext == 13 ) { ; } else { voptgenerror (FLG_SYNTAX, message ("Invalid character (ascii: %d), skipping character", (int)(*yytext)), g_currentloc); } } %% struct skeyword { /*@null@*/ /*@observer@*/ char *name; int token; } ; /* ** These tokens are followed by syntax that is parsed by the ** grammar proper. */ struct skeyword s_parsetable[] = { { "modifies", QMODIFIES } , { "globals", QGLOBALS } , { "alt", QALT } , { "warn", QWARN } , { "constant", QCONSTANT } , { "function", QFUNCTION } , { "iter", QITER } , { "defines", QDEFINES } , { "uses", QUSES } , { "allocates", QALLOCATES } , { "sets", QSETS } , { "releases", QRELEASES } , { "pre", QPRECLAUSE } , { "post", QPOSTCLAUSE } , { "setBufferSize", QSETBUFFERSIZE}, { "setStringLength", QSETSTRINGLENGTH}, { "testinRange", QTESTINRANGE}, { "requires", QPRECLAUSE } , { "ensures", QPOSTCLAUSE } , { "invariant", QINVARIANT} , { NULL, BADTOK } } ; /* ** These tokens are either stand-alone tokens, or followed by ** token-specific text. */ struct skeyword s_keytable[] = { { "anytype", QANYTYPE } , { "integraltype", QINTEGRALTYPE } , { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } , { "signedintegraltype", QSIGNEDINTEGRALTYPE } , { "out", QOUT } , { "in", QIN } , { "only", QONLY } , { "owned", QOWNED } , { "dependent", QDEPENDENT } , { "partial", QPARTIAL } , { "special", QSPECIAL } , { "truenull", QTRUENULL } , { "falsenull", QFALSENULL } , { "nullwhentrue", QTRUENULL } , { "falsewhennull", QFALSENULL } , { "keep", QKEEP } , { "kept", QKEPT } , { "notnull", QNOTNULL } , { "abstract", QABSTRACT } , { "concrete", QCONCRETE } , { "mutable", QMUTABLE } , { "immutable", QIMMUTABLE } , { "unused", QUNUSED } , { "external", QEXTERNAL } , { "sef", QSEF } , { "unique", QUNIQUE } , { "returned", QRETURNED } , { "exposed", QEXPOSED } , { "refcounted", QREFCOUNTED } , { "refs", QREFS } , { "newref", QNEWREF } , { "tempref", QTEMPREF } , { "killref", QKILLREF } , { "null", QNULL } , { "relnull", QRELNULL } , { "nullterminated", QNULLTERMINATED }, { "setBufferSize", QSETBUFFERSIZE }, { "testInRange", QTESTINRANGE}, { "MaxSet", QMAXSET}, { "MaxRead", QMAXREAD}, { "reldef", QRELDEF } , { "observer", QOBSERVER } , { "exits", QEXITS } , { "noreturn", QEXITS } , { "mayexit", QMAYEXIT } , { "maynotreturn", QMAYEXIT } , { "trueexit", QTRUEEXIT } , { "falseexit", QFALSEEXIT } , { "noreturnwhentrue", QTRUEEXIT } , { "noreturnwhenfalse", QFALSEEXIT } , { "neverexit", QNEVEREXIT } , { "alwaysreturns", QNEVEREXIT } , { "temp", QTEMP } , { "shared", QSHARED } , { "ref", QREF } , { "unchecked", QUNCHECKED } , { "checked", QCHECKED } , { "checkmod", QCHECKMOD } , { "checkedstrict", QCHECKEDSTRICT } , { "innercontinue", QINNERCONTINUE } , { "innerbreak", QINNERBREAK } , { "loopbreak", QLOOPBREAK } , { "switchbreak", QSWITCHBREAK } , { "safebreak", QSAFEBREAK } , { "fallthrough", QFALLTHROUGH } , { "l_fallthrou", QLINTFALLTHROUGH } , { "l_fallth", QLINTFALLTHRU } , { "notreached", QNOTREACHED } , { "l_notreach", QLINTNOTREACHED } , { "printflike", QPRINTFLIKE } , { "l_printfli", QLINTPRINTFLIKE } , { "scanflike", QSCANFLIKE } , { "messagelike", QMESSAGELIKE } , { "l_argsus", QARGSUSED } , { NULL, BADTOK } } ; /* ** would be better if these weren't hard coded... */ static bool isArtificial (cstring s) { return (cstring_equalLit (s, "modifies") || cstring_equalLit (s, "globals") || cstring_equalLit (s, "warn") || cstring_equalLit (s, "alt")); } void swallowMacro (void) { int i; bool skipnext = FALSE; while ((i = lminput ()) != EOF) { char c = (char) i; if (c == '\\') { skipnext = TRUE; } else if (c == '\n') { if (skipnext) { skipnext = FALSE; } else { reader_checkUngetc (i, yyin); return; } } } if (i != EOF) { reader_checkUngetc (i, yyin); } } static int commentMarkerToken (cstring s) { int i = 0; while (s_parsetable[i].name != NULL) { DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name)); if (cstring_equalLit (s, s_parsetable[i].name)) { return s_parsetable[i].token; } i++; } return BADTOK; } static int tokenMacroCode (cstring s) { int i = 0; while (s_keytable[i].name != NULL) { if (cstring_equalLit (s, s_keytable[i].name)) { if (s_keytable[i].token == QLINTFALLTHROUGH) { voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral ("Traditional lint comment /*FALLTHROUGH*/ used. " "Splint interprets this in the same way as most Unix lints, but it is " "preferable to replace it with the /*@fallthrough@*/ " "semantic comment"), g_currentloc); return QFALLTHROUGH; } else if (s_keytable[i].token == QLINTFALLTHRU) { voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral ("Traditional lint comment /*FALLTHRU*/ used. " "Splint interprets this in the same way as most Unix lints, but it is " "preferable to replace it with the /*@fallthrough@*/ " "semantic comment"), g_currentloc); return QFALLTHROUGH; } else if (s_keytable[i].token == QLINTNOTREACHED) { voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral ("Traditional lint comment /*NOTREACHED*/ used. " "Splint interprets this in the same way as most Unix lints, but it is " "preferable to replace it with the /*@notreached@*/ " "semantic comment."), g_currentloc); return QNOTREACHED; } else if (s_keytable[i].token == QPRINTFLIKE) { setSpecialFunction (qual_createPrintfLike ()); return SKIPTOK; } else if (s_keytable[i].token == QLINTPRINTFLIKE) { voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral ("Traditional lint comment /*PRINTFLIKE*/ used. " "Splint interprets this in the same way as most Unix lints, but it is " "preferable to replace it with either /*@printflike@*/, " "/*@scanflike@*/ or /*@messagelike@*/."), g_currentloc); setSpecialFunction (qual_createPrintfLike ()); return SKIPTOK; } else if (s_keytable[i].token == QSCANFLIKE) { setSpecialFunction (qual_createScanfLike ()); return SKIPTOK; } else if (s_keytable[i].token == QMESSAGELIKE) { setSpecialFunction (qual_createMessageLike ()); return SKIPTOK; } else if (s_keytable[i].token == QARGSUSED) { voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral ("Traditional lint comment /*ARGSUSED*/ used. " "Splint interprets this in the same way as most Unix lints, but it is " "preferable to use /*@unused@*/ annotations on " "the unused parameters."), g_currentloc); setArgsUsed (); return SKIPTOK; } return s_keytable[i].token; } i++; } return BADTOK; } static int lminput () { if (savechar == '\0') { incColumn (); return (input ()); } else { int save = (int) savechar; savechar = '\0'; return save; } } static void lmsavechar (char c) { if (savechar == '\0') savechar = c; else { llbuglit ("lmsavechar: override"); } } static int returnFloat (ctype ct, double f) { yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext), fileloc_decColumn (g_currentloc, tokLength)); tokLength = 0; return (CCONSTANT); } static int returnInt (ctype ct, long i) { ctype c = ct; if (ctype_equal (ct, ctype_int)) { if (i == 0) { c = context_typeofZero (); } else if (i == 1) { c = context_typeofOne (); } } yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext), fileloc_decColumn (g_currentloc, tokLength), i); tokLength = 0; return (CCONSTANT); } static int returnChar (char c) { yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext), fileloc_decColumn (g_currentloc, tokLength)); tokLength = 0; return (CCONSTANT); } static int ninput () { int c = lminput (); if (c != EOF && ((char)c == '\n')) { context_incLineno (); } return c; } static char macro_nextChar () { static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE; int ic; char c; ic = lminput (); c = char_fromInt (ic); if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0])) { if (c == '\\') { while ((c = char_fromInt (lminput ())) != '\0' && c != '\n') { ; /* skip to newline */ } context_incLineno (); if (c != '\0') { return macro_nextChar (); } else { return c; } } else /* if (c == '@') */ { llassert (FALSE); /*@i23@*/ if (handleLlSpecial () != BADTOK) { llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax"); } return macro_nextChar (); } } else if (!in_escape && c == '\"') { in_quote = !in_quote; } else if (!in_escape && c == '\'') { in_char = !in_char; } else if ((in_quote || in_char) && c == '\\') { in_escape = !in_escape; } else if ((in_quote || in_char) && in_escape) { in_escape = FALSE; } else if (!in_quote && c == '/') { char c2; if ((c2 = char_fromInt (lminput ())) == '*') { while (c2 != '\0') { while ((c2 = char_fromInt (lminput ())) != '\0' && c2 != '\n' && c2 != '*') { ; } if (c2 == '*') { while ((c2 = char_fromInt (lminput ())) != '\0' && c2 == '*') { ; } if (c2 == '/') { goto outofcomment; } } else { llfatalerror (cstring_makeLiteral ("Macro: bad comment!")); } } outofcomment: return macro_nextChar (); } else { /*** putchar does not work! why? puts to stdio...??! ***/ lmsavechar (c2); } } return c; } /* ** keeps semantic comments */ static char macro_nextCharC () { static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE; char c; c = char_fromInt (lminput ()); if (!in_quote && !in_char && c == '\\') { while ((c = char_fromInt (lminput ())) != '\0' && c != '\n') { ; /* skip to newline */ } context_incLineno (); if (c != '\0') { return macro_nextCharC (); } else { return c; } } else if (!in_escape && c == '\"') { in_quote = !in_quote; } else if (!in_escape && c == '\'') { in_char = !in_char; } else if ((in_quote || in_char) && c == '\\') { in_escape = !in_escape; } else if ((in_quote || in_char) && in_escape) { in_escape = FALSE; } else if (!in_quote && c == '/') { char c2; if ((c2 = char_fromInt (lminput ())) == '*') { while (c2 != '\0') { while ((c2 = char_fromInt (lminput ())) != '\0' && c2 != '\n' && c2 != '*') { ; } if (c2 == '*') { while ((c2 = char_fromInt (lminput ())) != '\0' && c2 == '*') { ; } if (c2 == '/') { goto outofcomment; } } else { llfatalerror (cstring_makeLiteral ("Macro: bad comment!")); } } outofcomment: return macro_nextCharC (); } else { lmsavechar (c2); } } return c; } /* ** skips whitespace (handles line continuations) ** returns first non-whitespace character */ static char skip_whitespace () { char c; while ((c = macro_nextChar ()) == ' ' || c == '\t') { ; } return c; } static void handleMacro () { cstring mac = cstring_undefined; int macrocode; char c; while (currentColumn () > 2) { mac = cstring_appendChar (mac, ' '); setTokLength (-1); } c = macro_nextCharC (); if (c >= '0' && c <= '9') { int i; for (i = 0; i < ((c - '0') + 1); i++) { mac = cstring_appendChar (mac, ' '); } } else { BADBRANCH; } while (((c = macro_nextCharC ()) != '\0') && (c != '\n')) { mac = cstring_appendChar (mac, c); } macrocode = tokenMacroCode (mac); if (macrocode == BADTOK && !isArtificial (mac)) { context_addMacroCache (mac); } else { cstring_free (mac); } if (c == '\n') { context_incLineno (); } } static bool processMacro (void) { uentry e2; ctype ct; int noparams = 0; cstring fname = cstring_undefined; bool res = TRUE; bool isspecfcn = FALSE; bool isiter = FALSE; bool skipparam = FALSE; bool isenditer = FALSE; bool unknownm = FALSE; bool hasParams = FALSE; bool emptyMacro = FALSE; char c = skip_whitespace (); fileloc loc = fileloc_noColumn (g_currentloc); /* are both of these necessary? what do they mean? */ uentryList specparams = uentryList_undefined; uentryList pn = uentryList_undefined; context_resetMacroMissingParams (); if (c == '\0' || c == '\n') { llcontbug (cstring_makeLiteral ("Bad macro")); fileloc_free (loc); return FALSE; } fname = cstring_appendChar (fname, c); while ((c = macro_nextChar ()) != '(' && c != '\0' && c != ' ' && c != '\t' && c != '\n') { fname = cstring_appendChar (fname, c); } if (c == ' ' || c == '\t' || c == '\n') { char oldc = c; if (c != '\n') { while (c == ' ' || c == '\t') { c = macro_nextChar (); } unput (c); } if (c == '\n') { emptyMacro = TRUE; unput (c); } c = oldc; } hasParams = (c == '('); if (usymtab_exists (fname)) { e2 = usymtab_lookupExpose (fname); ct = uentry_getType (e2); if (uentry_isCodeDefined (e2) && fileloc_isUser (uentry_whereDefined (e2))) { if (optgenerror (FLG_MACROREDEF, message ("Macro %s already defined", fname), loc)) { uentry_showWhereDefined (e2); uentry_clearDefined (e2); } if (uentry_isFunction (e2)) { uentry_setType (e2, ctype_unknown); ct = ctype_unknown; unknownm = TRUE; context_enterUnknownMacro (e2); } else { context_enterConstantMacro (e2); } } else { if (uentry_isForward (e2) && uentry_isFunction (e2)) { unknownm = TRUE; voptgenerror (FLG_MACROFCNDECL, message ("Parameterized macro has no prototype or specification: %s ", fname), loc); ct = ctype_unknown; uentry_setType (e2, ctype_unknown); uentry_setFunctionDefined (e2, loc); uentry_setUsed (e2, fileloc_undefined); context_enterUnknownMacro (e2); } else { if (uentry_isIter (e2)) { isiter = TRUE; specparams = uentry_getParams (e2); noparams = uentryList_size (specparams); uentry_setDefined (e2, loc); context_enterIterDef (e2); } else if (uentry_isEndIter (e2)) { isenditer = TRUE; uentry_setDefined (e2, loc); context_enterIterEnd (e2); /* don't care about it now */ /* but should parse like an iter! */ } else if (uentry_isConstant (e2)) { if (hasParams) { voptgenerror (FLG_INCONDEFS, message ("Constant %s implemented as parameterized macro", fname), g_currentloc); uentry_showWhereSpecified (e2); uentry_setType (e2, ctype_unknown); uentry_makeConstantFunction (e2); uentry_setDefined (e2, g_currentloc); uentry_setFunctionDefined (e2, g_currentloc); context_enterUnknownMacro (e2); } else { if (!uentry_isSpecified (e2)) { fileloc oloc = uentry_whereDeclared (e2); if (fileloc_isLib (oloc)) { ; } else if (fileloc_isUndefined (oloc) || fileloc_isPreproc (oloc)) { if (!emptyMacro) { voptgenerror (FLG_MACROCONSTDECL, message ("Macro constant %q not declared", uentry_getName (e2)), loc); } } else if (!fileloc_withinLines (oloc, loc, 2)) { /* bogus! will give errors if there is too much whitespace */ voptgenerror (FLG_SYNTAX, message ("Macro constant name %s does not match name in " "previous constant declaration. This constant " "is declared at %q", fname, fileloc_unparse (oloc)), loc); } } context_enterConstantMacro (e2); cstring_free (fname); fileloc_free (loc); return res; } } else if (ctype_isFunction (ct)) { isspecfcn = TRUE; specparams = ctype_argsFunction (ct); noparams = uentryList_size (specparams); uentry_setFunctionDefined (e2, loc); context_enterMacro (e2); } else if (uentry_isVar (e2)) { if (hasParams) { voptgenerror (FLG_INCONDEFS, message ("Variable %s implemented as parameterized macro", fname), loc); uentry_showWhereSpecified (e2); uentry_setType (e2, ctype_unknown); uentry_makeVarFunction (e2); uentry_setDefined (e2, g_currentloc); uentry_setFunctionDefined (e2, g_currentloc); context_enterUnknownMacro (e2); } else { uentry ucons = uentry_makeConstant (fname, ctype_unknown, loc); if (uentry_isExpandedMacro (e2)) { ; /* okay */ } else { if (optgenerror (FLG_INCONDEFS, message ("Variable %s implemented by a macro", fname), loc)) { uentry_showWhereSpecified (e2); } } uentry_setDefined (e2, loc); uentry_setUsed (ucons, loc); context_enterConstantMacro (ucons); uentry_markOwned (ucons); cstring_free (fname); return res; } } else { if (uentry_isDatatype (e2)) { vgenhinterror (FLG_SYNTAX, message ("Type implemented as macro: %x", uentry_getName (e2)), message ("A type is implemented using a macro definition. A " "typedef should be used instead."), g_currentloc); swallowMacro (); /* Must exit scope (not sure why a new scope was entered?) */ usymtab_quietExitScope (g_currentloc); uentry_setDefined (e2, g_currentloc); res = FALSE; } else { llcontbug (message ("Unexpanded macro not function or constant: %q", uentry_unparse (e2))); uentry_setType (e2, ctype_unknown); if (hasParams) { uentry_makeVarFunction (e2); uentry_setDefined (e2, g_currentloc); uentry_setFunctionDefined (e2, g_currentloc); context_enterUnknownMacro (e2); } } } } } } else { uentry ce; /* evans 2001-09-09 - if it has params, assume a function */ if (hasParams) { voptgenerror (FLG_MACROMATCHNAME, message ("Unexpanded macro %s does not match name of a declared " "function. The name used in the control " "comment on the previous line should match.", fname), loc); ce = uentry_makeFunction (fname, ctype_unknown, typeId_invalid, globSet_undefined, sRefSet_undefined, warnClause_undefined, fileloc_undefined); uentry_setUsed (ce, loc); /* perhaps bogus? */ e2 = usymtab_supEntryReturn (ce); context_enterUnknownMacro (e2); } else { voptgenerror (FLG_MACROMATCHNAME, message ("Unexpanded macro %s does not match name of a constant " "or iter declaration. The name used in the control " "comment on the previous line should match. " "(Assuming macro defines a constant.)", fname), loc); ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined); uentry_setUsed (ce, loc); /* perhaps bogus? */ e2 = usymtab_supEntryReturn (ce); context_enterConstantMacro (e2); cstring_free (fname); fileloc_free (loc); return res; } } /* in macros, ( must follow immediatetly after name */ if (hasParams) { int paramno = 0; c = skip_whitespace (); while (c != ')' && c != '\0') { uentry param; bool suppress = context_inSuppressRegion (); cstring paramname = cstring_undefined; /* ** save the parameter location */ decColumn (); context_saveLocation (); incColumn (); while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')') { paramname = cstring_appendChar (paramname, c); c = macro_nextChar (); } if (c == ' ' || c == '\t') c = skip_whitespace (); if (c == ',') { c = macro_nextChar (); if (c == ' ' || c == '\t') c = skip_whitespace (); } if (c == '\0') { llfatalerror (cstring_makeLiteral ("Bad macro syntax: uentryList")); } if ((isspecfcn || isiter) && (paramno < noparams) && !uentry_isElipsisMarker (uentryList_getN (specparams, paramno))) { fileloc sloc = context_getSaveLocation (); uentry decl = uentryList_getN (specparams, paramno); sRef sr; param = uentry_nameCopy (paramname, decl); uentry_setParam (param); sr = sRef_makeParam (paramno, uentry_getType (param), stateInfo_makeLoc (sloc)); if (sRef_getNullState (sr) == NS_ABSNULL) { ctype pt = ctype_realType (uentry_getType (param)); if (ctype_isUser (pt)) { uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt)); if (uentry_isValid (te)) { sRef_setStateFromUentry (sr, te); } } else { sRef_setNullState (sr, NS_UNKNOWN, sloc); } } uentry_setSref (param, sr); uentry_setDeclaredForceOnly (param, sloc); skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno)); } else { fileloc sloc = context_getSaveLocation (); param = uentry_makeVariableSrefParam (paramname, ctype_unknown, fileloc_copy (sloc), sRef_makeParam (paramno, ctype_unknown, stateInfo_makeLoc (sloc))); DPRINTF (("Unknown param: %s", uentry_unparseFull (param))); cstring_free (paramname); sRef_setPosNull (uentry_getSref (param), sloc); uentry_setDeclaredForce (param, sloc); skipparam = FALSE; fileloc_free (sloc); } if (!skipparam) { llassert (!uentry_isElipsisMarker (param)); if (!suppress) { sRef_makeUnsafe (uentry_getSref (param)); } pn = uentryList_add (pn, uentry_copy (param)); usymtab_supEntry (param); } else { /* don't add param */ uentry_free (param); } if (c == ',') { (void) macro_nextChar (); c = skip_whitespace (); } paramno++; } if (c == ')') { if (isspecfcn || isiter) { if (paramno != noparams && noparams >= 0) { advanceLine (); voptgenerror (FLG_INCONDEFS, message ("Macro %s specified with %d args, defined with %d", fname, noparams, paramno), g_currentloc); uentry_showWhereSpecified (e2); uentry_resetParams (e2, pn); } } else { uentry_resetParams (e2, pn); } } } else { /* ** the form should be: ** ** # define newname oldname ** where oldname refers to a function matching the specification ** of newname. */ if (unknownm) { sRef_setGlobalScope (); usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown)); sRef_clearGlobalScope (); } else { context_setMacroMissingParams (); } } /* context_setuentryList (pn); */ usymtab_enterScope (); fileloc_free (loc); cstring_free (fname); return res; } static bool handleSpecial (char *yyt) { char *l = mstring_create (MAX_NAME_LENGTH); int lineno = 0; char c; char *ol; cstring olc; int len_yyt; len_yyt = strlen (yyt +1) ; l = mstring_copy (yyt + 1); while ((c = char_fromInt (lminput ())) != '\n' && c != '\0') { l = mstring_append(l, c); } /* Need to safe original l for deallocating. */ ol = l; l += strlen (l); olc = cstring_fromChars (ol); if (cstring_equalPrefixLit (olc, "pragma")) { char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN)); char *opname = pname; char *ptr = ol + 6; /* pragma is six characters, plus space */ int len = 0; /* skip whitespace */ while (((c = *ptr) != '\0') && isspace (c)) { ptr++; } while (((c = *ptr) != '\0') && !isspace (c)) { len++; if (len > MAX_PRAGMA_LEN) { break; } ptr++; *pname++ = c; } *pname = '\0'; if (len == PRAGMA_LEN_EXPAND && mstring_equal (opname, PRAGMA_EXPAND)) { cstring exname = cstring_undefined; uentry ue; ptr++; while (((c = *ptr) != '\0') && !isspace (c)) { exname = cstring_appendChar (exname, c); ptr++; } ue = usymtab_lookupExposeGlob (exname); if (uentry_isExpandedMacro (ue)) { if (fileloc_isPreproc (uentry_whereDefined (ue))) { fileloc_setColumn (g_currentloc, 1); uentry_setDefined (ue, g_currentloc); } } cstring_free (exname); } } else if (cstring_equalPrefixLit (olc, "ident")) { /* Some pre-processors will leave these in the code. Ignore rest of line */ } /* ** Yuk...Win32 filenames can have spaces in them...we need to read ** to the matching end quote. */ else if ((sscanf (ol, "line %d \"", &lineno) == 1) || (sscanf (ol, " %d \"", &lineno) == 1)) { char *tmp = ol; cstring fname; fileId fid; /*@access cstring@*/ while (*tmp != '\"' && *tmp != '\0') { tmp++; } llassert (*tmp == '\"'); tmp++; fname = tmp; while (*tmp != '\"' && *tmp != '\0') { tmp++; } llassert (*tmp == '\"'); *tmp = '\0'; # if defined(OS2) || defined(MSDOS) || defined(WIN32) /* ** DOS-like path delimiters get delivered in pairs, something like ** \"..\\\\file.h\", so we have to make it normal again. We do NOT ** remove the pre dirs yet as we usually specify tmp paths relative ** to the current directory, so tmp files would not get found in ** the hash table. If this method fails we try it again later. */ { char *stmp = fname; /* ** Skip past the drive marker. */ if (strchr (stmp, ':') != NULL) { stmp = strchr (stmp, ':') + 1; } while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL ) { if (*(stmp+1) == CONNECTCHAR) { memmove (stmp, stmp+1, strlen (stmp)); } stmp++; } fid = fileTable_lookupBase (context_fileTable (), fname); if (!(fileId_isValid (fid))) { fname = removePreDirs (fname); fid = fileTable_lookupBase (context_fileTable (), fname); } } # else /* !defined(OS2) && !defined(MSDOS) */ fname = removePreDirs (fname); fid = fileTable_lookupBase (context_fileTable (), fname); # endif /* !defined(OS2) && !defined(MSDOS) */ if (!(fileId_isValid (fid))) { if (context_inXHFile ()) { fid = fileTable_addXHFile (context_fileTable (), fname); } else if (isHeaderFile (fname)) { fid = fileTable_addHeaderFile (context_fileTable (), fname); } else { fid = fileTable_addFile (context_fileTable (), fname); } } setFileLine (fid, lineno); /*@noaccess cstring@*/ } else if ((sscanf (ol, "line %d", &lineno) == 1) || (sscanf (ol, " %d", &lineno) == 1)) { setLine (lineno); /* next line is */ } else { if (mstring_equal (ol, "")) { DPRINTF (("Empty pp command!")); /* ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor. ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file. */ mstring_free (ol); return FALSE; } else { voptgenerror (FLG_UNRECOGDIRECTIVE, message ("Unrecognized pre-processor directive: #%s", cstring_fromChars (ol)), g_currentloc); } sfree (ol); return FALSE; /* evans 2001-12-30: was: TRUE; */ } sfree (ol); return FALSE; } static int handleLlSpecial () { bool hasnl = FALSE; int ic; char c; char *s = mstring_createEmpty (); char *os; int tok; int charsread = 0; fileloc loc; loc = fileloc_copy (g_currentloc); DPRINTF (("Handle special: %s", fileloc_unparse (loc))); while (((ic = ninput ()) != 0) && isalpha (ic)) { c = (char) ic; s = mstring_append (s, c); charsread++; } DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc))); os = s; if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0]) { ic = ninput (); llassert (ic == AFTER_COMMENT_MARKER[1]); if (*s == '\0') { sfree (os); fileloc_free (loc); return QNOMODS; /* special token no modifications token */ } } DPRINTF (("Coment marker: %s", os)); tok = commentMarkerToken (cstring_fromChars (os)); if (tok != BADTOK) { tokLength = charsread; sfree (os); inSpecPart = TRUE; fileloc_free (loc); return tok; } DPRINTF (("Not a comment marker...")); /* Add rest of the comment */ if (ic != 0 && ic != EOF) { c = (char) ic; s = mstring_append (s, c); charsread++; while (((ic = ninput ()) != 0) && (ic != EOF) && (ic != AFTER_COMMENT_MARKER[0])) { c = (char) ic; /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */ if (c == '\n') { hasnl = TRUE; /* This prevents tokLength from being set later. */ tokLength = 0; voptgenerror (FLG_SYNTAX, message ("Likely parse error: syntactic comment token spans multiple lines: %s", cstring_fromChars (s)), loc); } s = mstring_append (s, c); charsread++; } } DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc))); if (ic == AFTER_COMMENT_MARKER[0]) { int nc = ninput (); llassert ((char) nc == AFTER_COMMENT_MARKER[1]); charsread++; } os = s; while (*s == ' ' || *s == '\t' || *s == '\n') { s++; } if (*s == '-' || *s == '+' || *s == '=') /* setting flags */ { c = *s; while (c == '-' || c == '+' || c == '=') { ynm set = ynm_fromCodeChar (c); cstring thisflag; s++; thisflag = cstring_fromChars (s); while ((c = *s) != '\0' && (c != '-') && (c != '=') && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n')) { s++; } *s = '\0'; if (!context_getFlag (FLG_NOCOMMENTS)) { cstring flagname = thisflag; flagcode fflag = flags_identifyFlag (flagname); if (flagcode_isSkip (fflag)) { ; } else if (flagcode_isModeName (fflag)) { if (ynm_isMaybe (set)) { llerror (FLG_BADFLAG, message ("Semantic comment attempts to restore flag %s. " "A mode flag cannot be restored.", flagname)); } else { context_setMode (flagname); } } else if (flagcode_isInvalid (fflag)) { voptgenerror (FLG_UNRECOGFLAGCOMMENTS, message ("Unrecognized option in semantic comment: %s", flagname), loc); } else if (flagcode_isGlobalFlag (fflag)) { voptgenerror (FLG_BADFLAG, message ("Semantic comment attempts to set global flag %s. " "A global flag cannot be set locally.", flagname), loc); } else { context_fileSetFlag (fflag, set, loc); if (flagcode_hasArgument (fflag)) { if (ynm_isMaybe (set)) { voptgenerror (FLG_BADFLAG, message ("Semantic comment attempts to restore flag %s. " "A flag for setting a value cannot be restored.", flagname), loc); } else { /* cut-and-pastied from llmain...blecch */ cstring extra = cstring_undefined; char *rest; char *orest; char rchar; *s = c; rest = mstring_copy (s); orest = rest; *s = '\0'; while ((rchar = *rest) != '\0' && (isspace (rchar))) { rest++; s++; } while ((rchar = *rest) != '\0' && !isspace (rchar)) { extra = cstring_appendChar (extra, rchar); rest++; s++; } sfree (orest); if (cstring_isUndefined (extra)) { llerror (FLG_BADFLAG, message ("Flag %s (in semantic comment) must be followed by an argument", flagcode_unparse (fflag))); } else { s--; if (flagcode_hasNumber (fflag)) { setValueFlag (fflag, extra); } else if (flagcode_hasChar (fflag)) { setValueFlag (fflag, extra); } else if (flagcode_hasString (fflag)) { setStringFlag (fflag, extra); } else { BADEXIT; } } } } } } else { ; } *s = c; while ((c == ' ') || (c == '\t') || (c == '\n')) { c = *(++s); } } if (context_inHeader () && !isArtificial (cstring_fromChars (os))) { DPRINTF (("Here adding comment: %s", os)); context_addComment (cstring_fromCharsNew (os), loc); } else { ; } } else { char *t = s; int macrocode; char tchar = '\0'; annotationInfo ainfo; while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n') { s++; } if (*s != '\0') { tchar = *s; *s = '\0'; s++; } t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t))); macrocode = tokenMacroCode (cstring_fromChars (t)); if (macrocode != BADTOK) { tokLength = hasnl ? 0 : mstring_length (t); sfree (t); sfree (os); fileloc_free (loc); if (macrocode == SKIPTOK) { return BADTOK; } return macrocode; } ainfo = context_lookupAnnotation (cstring_fromChars (os)); if (annotationInfo_isDefined (ainfo)) { DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo))); /*@i324@*/ yylval.annotation = ainfo; tokLength = 0; sfree (os); sfree (t); fileloc_free (loc); return CANNOTATION; } if (context_inHeader ()) { if (tchar != '\0') { *(s-1) = tchar; } if ((context_inMacro () || context_inGlobalContext ()) && macrocode != SKIPTOK && !isArtificial (cstring_fromChars (os))) { if (context_processingMacros ()) { /* evans 2002-02-24: don't add comments when procssing macros */ } else { context_addComment (cstring_fromCharsNew (os), loc); } } else { ; } if (tchar != '\0') { *(s-1) = '\0'; } } if (mstring_equal (t, "ignore")) { if (!context_getFlag (FLG_NOCOMMENTS)) { context_enterSuppressRegion (loc); } } else if ((*t == 'i' || *t == 't') && (*(t + 1) == '\0')) { if (!context_getFlag (FLG_NOCOMMENTS) && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS))) { context_enterSuppressLine (-1, loc); /* infinite suppression */ } } else if (((*t == 'i') || (*t == 't')) && ((*(t + 1) >= '0' && *(t + 1) <= '9'))) { bool tmpcomment = (*t == 't'); int val = -1; char *tt = t; /* don't mangle t, since it is free'd */ char lc = *(++tt); if (lc >= '0' && lc <= '9') { val = (int)(lc - '0'); lc = *(++tt); while (lc >= '0' && lc <= '9') { val *= 10; val += lc - '0'; lc = *(++tt); } } if (!context_getFlag (FLG_NOCOMMENTS) && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS))) { DPRINTF (("Here: enter suppress: %s", fileloc_unparse (loc))); context_enterSuppressLine (val, loc); } } else if (mstring_equal (t, "end")) { if (!context_getFlag (FLG_NOCOMMENTS)) { context_exitSuppressRegion (loc); } } else if (mstring_equal (t, "notfunction")) { ; /* handled by pcpp */ } else if (mstring_equal (t, "access")) { cstring tname; while (TRUE) { while ((c = *s) && (c == ' ' || c == '\t' || c == '\n')) { s++; } if (c == '\0') { break; } tname = cstring_fromChars (s); while ((c = *s) != '\0' && c != ' ' && c != '\t' && c != '\n' && c != ',') { s++; } *s = '\0'; DPRINTF (("Access %s", tname)); if (!context_getFlag (FLG_NOCOMMENTS) && !context_getFlag (FLG_NOACCESS)) { if (usymtab_existsType (tname)) { typeId uid = usymtab_getTypeId (tname); uentry ue = usymtab_getTypeEntry (uid); if (uentry_isAbstractDatatype (ue)) { context_addFileAccessType (uid); DPRINTF (("Adding access to: %s / %d", tname, uid)); } else { voptgenerror (FLG_COMMENTERROR, message ("Non-abstract type %s used in access comment", tname), loc); } } else { if (!(context_inSuppressRegion () || context_inSuppressZone (loc))) { voptgenerror (FLG_COMMENTERROR, message ("Unrecognized type %s used in access comment", tname), loc); } } } if (c != '\0') { s++; } if (c != ',' && c != ' ') { break; } } } else if (mstring_equal (t, "noaccess")) { cstring tname; char lc; while (TRUE) { while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n')) { s++; } if (lc == '\0') { break; } tname = cstring_fromChars (s); while ((lc = *s) != '\0' && lc != ' ' && lc != '\t' && lc != '\n' && lc != ',') { s++; } *s = '\0'; if (!context_getFlag (FLG_NOCOMMENTS) && !context_getFlag (FLG_NOACCESS)) { if (usymtab_existsType (tname)) { typeId tuid = usymtab_getTypeId (tname); if (context_couldHaveAccess (tuid)) { DPRINTF (("Removing access: %s", tname)); context_removeFileAccessType (tuid); } else { if (!(context_inSuppressRegion () || context_inSuppressZone (loc))) { uentry ue = usymtab_getTypeEntry (tuid); if (uentry_isAbstractDatatype (ue)) { voptgenerror (FLG_COMMENTERROR, message ("Non-accessible abstract type %s used in noaccess comment", tname), loc); } else { voptgenerror (FLG_COMMENTERROR, message ("Non-abstract type %s used in noaccess comment", tname), loc); } } } } else { if (!(context_inSuppressRegion () || context_inSuppressZone (loc))) { voptgenerror (FLG_COMMENTERROR, message ("Unrecognized type %s used in noaccess comment", tname), loc); } } } if (lc != '\0') { s++; } if (lc != ',' && lc != ' ') { break; } } } else { voptgenerror (FLG_UNRECOGCOMMENTS, message ("Semantic comment unrecognized: %s", cstring_fromChars (os)), loc); } sfree (t); } sfree (os); fileloc_free (loc); return BADTOK; } static /*@only@*/ cstring makeIdentifier (char *s) { char *c = mstring_create (size_toInt (strlen (s)) + 1); cstring id = cstring_fromChars (c); while (isalnum (*s) || (*s == '_') || (*s == '$')) { *c++ = *s++; } *c = '\0'; return (id); } /*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn) { if (!(usymtab_exists (cn))) { fileloc loc = fileloc_createExternal (); /* ** We need to put this in a global scope, otherwise the sRef will be deallocated. */ uentry ce = uentry_makeUnrecognized (cn, loc); if (!context_inIterEnd ()) { voptgenerror (FLG_SYSTEMUNRECOG, message ("Unrecognized (possibly system) identifier: %q", uentry_getName (ce)), g_currentloc); } return ce; } return (usymtab_lookup (cn)); } /* ** like, coerceId, but doesn't supercede for iters */ /*@observer@*/ uentry coerceIterId (cstring cn) { if (!(usymtab_exists (cn))) { return uentry_undefined; } return (usymtab_lookup (cn)); } /*@observer@*/ cstring LastIdentifier () { return (lastidprocessed); } static int processIdentifier (cstring id) { uentry le; if (context_getFlag (FLG_GRAMMAR)) { lldiagmsg (message ("Process identifier: %s", id)); } context_clearJustPopped (); lastidprocessed = id; if (context_inFunctionHeader ()) { int tok = commentMarkerToken (id); DPRINTF (("in function decl...")); if (tok != BADTOK) { return tok; } else { tok = tokenMacroCode (id); if (tok != BADTOK) { return tok; } else { annotationInfo ainfo; if (expectingMetaStateName) { metaStateInfo msinfo = context_lookupMetaStateInfo (id); if (metaStateInfo_isDefined (msinfo)) { yylval.msinfo = msinfo; return METASTATE_NAME; } else { DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id))); } } ainfo = context_lookupAnnotation (id); if (annotationInfo_isDefined (ainfo)) { DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo))); /*@i324@*/ yylval.annotation = ainfo; return CANNOTATION; } else { DPRINTF (("Not annotation: %s", id)); } } } } /* Consider handling: Defined by C99 as static const char __func__[] */ if (context_getFlag (FLG_GNUEXTENSIONS)) { int tok = BADTOK; if (cstring_equalLit (id, "__stdcall") || cstring_equalLit (id, "__cdecl") || cstring_equalLit (id, "__extension__")) { return BADTOK; } else if (cstring_equalLit (id, "__volatile__")) { tok = QVOLATILE; } else if (cstring_equalLit (id, "__signed")) { tok = QSIGNED; } else if (cstring_equalLit (id, "__unsigned")) { tok = QUNSIGNED; } else if (cstring_equalLit (id, "__const__")) { tok = QCONST; } else if (cstring_equalLit (id, "__alignof__")) { tok = CALIGNOF; /* alignof is parsed like sizeof */ } else if (cstring_equalLit (id, "__typeof__")) { tok = CTYPEOF; } else if (cstring_equalLit (id, "typeof")) { tok = CTYPEOF; } else if (cstring_equalLit (id, "__FUNCTION__") || cstring_equalLit (id, "__PRETTY_FUNCTION__")) { /* These tokens hold the name of the current function as strings */ /* evans 2001-12-30: changed from exprNode_stringLiteral; bug reported by Jim Zelenka. */ yylval.expr = exprNode_makeConstantString (id, fileloc_copy (g_currentloc)); tokLength = 0; lastWasString = TRUE; tok = CCONSTANT; return tok; } else if (cstring_equalLit (id, "__attribute__") || cstring_equalLit (id, "__asm__") || cstring_equalLit (id, "_asm") || cstring_equalLit (id, "__asm") || cstring_equalLit (id, "__declspec")) { int depth = 0; bool useparens = FALSE; bool usebraces = FALSE; bool inquote = FALSE; bool inescape = FALSE; int ic; while ((ic = input ()) != EOF) { if (inescape) { inescape = FALSE; } else if (ic == '\\') { inescape = TRUE; } else if (ic == '\"') { inquote = !inquote; } else if (!inquote) { if (ic == '(') { if (!useparens) { if (!usebraces) { useparens = TRUE; } } if (useparens) { depth++; } } else if (ic == '{') { if (!usebraces) { if (!useparens) { usebraces = TRUE; } } if (usebraces) { depth++; } } else if (ic == ')' && useparens) { depth--; if (depth == 0) break; } else if (ic == '}' && usebraces) { depth--; if (depth == 0) break; } else if (ic == '}' && !usebraces && !useparens && cstring_equalLit (id, "__asm")) { /* ** We need this because some MS VC++ include files ** have __asm mov ... } ** Its a kludge, but otherwise would need to parse ** the asm code! */ return TRBRACE; } } if (ic == '\n') { context_incLineno (); if (cstring_equalLit (id, "__asm") && !useparens && !usebraces) { break; } } } llassert ((useparens && ic == ')') || (usebraces && ic == '}') || (!useparens && !usebraces)); return BADTOK; } else if (cstring_equalLit (id, "inline") || cstring_equalLit (id, "__inline") || cstring_equalLit (id, "_inline") || cstring_equalLit (id, "__inline__")) { tok = QINLINE; } if (tok != BADTOK) { RETURN_TOK (tok); } } le = usymtab_lookupSafe (id); /*@-dependenttrans@*/ if (uentry_isIter (le)) { /*@i32@*/ yylval.entry = le; return (ITER_NAME); } else if (uentry_isEndIter (le)) { /*@i32@*/ yylval.entry = le; return (ITER_ENDNAME); } else if (uentry_isUndefined (le)) { yylval.cname = id; /* avoid parse errors for certain system built ins */ if (g_expectingTypeName && (cstring_firstChar (id) == '_') && (cstring_secondChar (id) == '_')) { return (TYPE_NAME_OR_ID); } return (NEW_IDENTIFIER); } else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le)) { if (uentry_isDatatype (le)) { yylval.cname = id; return (NEW_IDENTIFIER); } else { /*@i32@*/ yylval.entry = le; return (IDENTIFIER); } } else if (uentry_isDatatype (le)) { if (!g_expectingTypeName) { yylval.cname = id; return (NEW_IDENTIFIER); } else { yylval.ctyp = uentry_getAbstractType (le); uentry_setUsed (le, g_currentloc); return (TYPE_NAME); } } else { /*@i32@*/ yylval.entry = le; return (IDENTIFIER); } /*@=dependenttrans@*/ } static bool processHashIdentifier (/*@only@*/ cstring id) { if (context_inMacro () || context_inIterDef () || context_inIterEnd ()) { uentry le; context_clearJustPopped (); lastidprocessed = id; le = usymtab_lookupSafe (id); if (uentry_isParam (le) || uentry_isRefParam (le)) { return TRUE; } else { return FALSE; } } else { /* ** Will be handled by handleLlSpecial */ cstring_free (id); return FALSE; } } static /*@only@*/ exprNode processString () { exprNode res; fileloc loc; char *nl = strchr (yytext, '\n'); cstring ns = cstring_fromCharsNew (yytext); if (nl == NULL) { loc = fileloc_copy (g_currentloc); addColumn (cstring_length (ns)); } else { char *lastnl = nl; loc = fileloc_copy (g_currentloc); context_incLineno (); while ((nl = strchr ((nl + 1), '\n')) != NULL) { context_incLineno (); lastnl = nl; } } res = exprNode_stringLiteral (ns, loc); return (res); } /* ** process a wide character string L"...." */ static /*@only@*/ exprNode processWideString () { exprNode res; fileloc loc; char *nl = strchr (yytext, '\n'); cstring ns; llassert (*yytext == 'L'); yytext++; ns = cstring_fromCharsNew (yytext); if (nl == NULL) { loc = fileloc_copy (g_currentloc); addColumn (cstring_length (ns)); } else { char *lastnl = nl; loc = fileloc_copy (g_currentloc); context_incLineno (); while ((nl = strchr ((nl + 1), '\n')) != NULL) { context_incLineno (); lastnl = nl; } } res = exprNode_wideStringLiteral (ns, loc); return (res); } static char processChar () { char fchar; char next; llassert (*yytext != '\0'); fchar = *(yytext + 1); if (fchar != '\\') return fchar; next = *(yytext + 2); switch (next) { case 'n': return '\n'; case 't': return '\t'; case '\"': return '\"'; case '\'': return '\''; case '\\': return '\\'; default: return '\0'; } } static double processFloat () { double ret = atof (yytext); return (ret); } static long processHex () { int index = 2; long val = 0; llassert (yytext[0] == '0' && (yytext[1] == 'X' || yytext[1] == 'x')); while (yytext[index] != '\0') { int tval; char c = yytext[index]; if (c >= '0' && c <= '9') { tval = (int) c - (int) '0'; } else if (c >= 'A' && c <= 'F') { tval = (int) c - (int) 'A' + 10; } else if (c >= 'a' && c <= 'f') { tval = (int) c - (int) 'a' + 10; } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') { index++; while (yytext[index] != '\0') { if (c == 'U' || c == 'L' || c == 'u' || c == 'l') { ; } else { voptgenerror (FLG_SYNTAX, message ("Invalid character (%c) following specifier in hex constant: %s", c, cstring_fromChars (yytext)), g_currentloc); } index++; } break; } else { voptgenerror (FLG_SYNTAX, message ("Invalid character (%c) in hex constant: %s", c, cstring_fromChars (yytext)), g_currentloc); break; } val = (val * 16) + tval; index++; } DPRINTF (("Hex constant: %s = %ld", yytext, val)); return val; } static long processOctal () { int index = 1; long val = 0; llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x'); while (yytext[index] != '\0') { int tval; char c = yytext[index]; if (c >= '0' && c <= '7') { tval = (int) c - (int) '0'; } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') { index++; while (yytext[index] != '\0') { if (c == 'U' || c == 'L' || c == 'u' || c == 'l') { ; } else { voptgenerror (FLG_SYNTAX, message ("Invalid character (%c) following specifier in octal constant: %s", c, cstring_fromChars (yytext)), g_currentloc); } index++; } break; } else { voptgenerror (FLG_SYNTAX, message ("Invalid character (%c) in octal constant: %s", c, cstring_fromChars (yytext)), g_currentloc); break; } val = (val * 8) + tval; index++; } DPRINTF (("Octal constant: %s = %ld", yytext, val)); return val; } static long processDec () { return (atol (yytext)); } static int processSpec (int tok) { size_t length = strlen (yytext); if (inSpecPart) { setTokLengthT (length); RETURN_TOK (tok); } else { context_saveLocation (); setTokLengthT (length); return (processIdentifier (makeIdentifier (yytext))); } } void cscanner_expectingMetaStateName () { llassert (!expectingMetaStateName); llassert (context_inFunctionHeader ()); expectingMetaStateName = TRUE; } void cscanner_clearExpectingMetaStateName () { llassert (expectingMetaStateName); expectingMetaStateName = FALSE; }