X-Git-Url: http://andersk.mit.edu/gitweb/splint.git/blobdiff_plain/7272a1c162ecf75235b8a4c44c9b86d023e7ef16..53306cab3dabf761f459f8f5fdc4b30eca6ec707:/src/cscanner.l diff --git a/src/cscanner.l b/src/cscanner.l index 66701f5..4bb02db 100644 --- a/src/cscanner.l +++ b/src/cscanner.l @@ -1,46 +1,57 @@ /*;-*-C-*-; -** Copyright (c) Massachusetts Institute of Technology 1994-1998. -** All Rights Reserved. -** Unpublished rights reserved under the copyright laws of -** the United States. +** Splint - annotation-assisted static program checker +** Copyright (C) 1994-2002 University of Virginia, +** Massachusetts Institute of Technology ** -** THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED -** OR IMPLIED. ANY USE IS AT YOUR OWN RISK. +** 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. ** -** This code is distributed freely and may be used freely under the -** following conditions: -** -** 1. This notice may not be removed or altered. +** 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 ** -** 2. Works derived from this code are not distributed for -** commercial gain without explicit permission from MIT -** (for permission contact lclint-request@sds.lcs.mit.edu). +** 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 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 LCLint 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 - */ +** 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_$] @@ -53,56 +64,53 @@ IS (u|U|l|L)* ULSuffix ({U}{L}|{L}{U}) %{ +# include "splintMacros.nf" +# if defined(OS2) && defined(__IBMC__) + /* needed for isatty()... */ +# include +# else + /* -** based on original C lexer by Nate Osgood -** from hacrat@catfish.lcs.mit.edu Mon Jun 14 13:06:32 1993 -** +** Win32 doesn't have unistd.h */ -# include "lclintMacros.nf" +# ifndef WIN32 +# include +# endif + +# endif + # include "basic.h" # include "cgrammar.h" # include "cgrammar_tokens.h" - -# include "fileIdList.h" # include "portab.h" -# if defined(OS2) && defined(__IBMC__) - /* needed for isatty()... */ -# include -# endif - static bool lastWasString = FALSE; static char savechar = '\0'; /*@notfunction@*/ # define yyinput() (incColumn (), getc (yyin)) -/*@-noparams@*/ -/*@-incondefs@*/ -extern /*@external@*/ int read (); -/*@=incondefs@*/ -/*@=noparams@*/ - -static /*@owned@*/ cstring lastidprocessed = cstring_undefined; - +static /*@owned@*/ cstring s_lastidprocessed = cstring_undefined; static int lminput (void); static int tokLength = 0; -static bool inSpecPart = FALSE; +static bool s_inSpecPart = FALSE; +static int s_whichSpecPart; static bool continueLine = FALSE; static int ninput (void); static char processChar (void); static double processFloat (void); -static /*@only@*/ exprNode processString (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@*/ ; + /*@globals s_lastidprocessed@*/ ; static bool processHashIdentifier (/*@only@*/ cstring) - /*@globals undef lastidprocessed@*/ ; + /*@globals s_lastidprocessed@*/ ; static int processSpec (int); static bool handleSpecial (char *); @@ -174,6 +182,7 @@ static void setTokLength (int len) { addColumn (len); tokLength = len; + DPRINTF (("Set tok length: %d", len)); } static void setTokLengthT (size_t len) @@ -189,7 +198,7 @@ static void setTokLengthT (size_t len) %% -"/*" { llfatalbug (cstring_makeLiteral ("Comment in pre-processor output")); } +"/*" { llfatalerror (cstring_makeLiteral ("Comment in pre-processor output")); } "#"{Letter}({Letter}|{Digit})* { context_saveLocation (); @@ -261,6 +270,7 @@ static void setTokLengthT (size_t len) "volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); } "const" { setTokLength (5); RETURN_TOK (QCONST); } +"restrict" { setTokLength (8); RETURN_TOK (QRESTRICT); } /* some systems expect this! [gack!] */ "__const" { setTokLength (7); RETURN_TOK (QCONST); } @@ -271,7 +281,7 @@ static void setTokLengthT (size_t len) "static" { setTokLength (6); RETURN_TOK (QSTATIC); } \"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); } -L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); } +L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processWideString ()); } "out" { return (processSpec (QOUT)); } "in" { return (processSpec (QIN)); } "partial" { return (processSpec (QPARTIAL)); } @@ -286,6 +296,8 @@ L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); "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)); } @@ -368,6 +380,8 @@ L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); 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)); @@ -443,6 +457,16 @@ L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); [ \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; @@ -452,7 +476,7 @@ L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); if (context_inMacro ()) { /* Don't use RETURN_TOK */ - yylval.tok = lltok_create (TENDMACRO, g_currentloc); + yylval.tok = lltok_create (TENDMACRO, fileloc_copy (g_currentloc)); /* !!! evans 2002-03-13 */ lastWasString = FALSE; return (TENDMACRO); } @@ -496,6 +520,8 @@ L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); if (processMacro ()) { + DPRINTF (("Here we are: %s", context_unparse ())); + if (context_inIterDef ()) { RETURN_TOK (LLMACROITER); @@ -547,7 +573,8 @@ L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); } "%}" { /* AFTER_COMMENT_MARKER */ setTokLength (2); - inSpecPart = FALSE; + s_inSpecPart = FALSE; + s_whichSpecPart = BADTOK; RETURN_TOK (QENDMACRO); } "\\" { incColumn (); continueLine = TRUE; } . { incColumn (); @@ -563,6 +590,58 @@ L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); } %% +/* +** Resets flags set by flex.head. +*/ + +/*@=allmacros@*/ +/*@=pred@*/ +/*@=globstate@*/ +/*@=null@*/ +/*@=boolint@*/ +/*@=charint@*/ +/*@=macrospec@*/ +/*@=macroredef@*/ +/*@=exitarg@*/ +/*@=compdef@*/ +/*@=uniondef@*/ +/*@=ignorequals@*/ +/*@=noreturn@*/ +/*@=mustfree@*/ +/*@=compdestroy@*/ +/*@=branchstate@*/ +/*@=unreachable@*/ +/*@=varuse@*/ +/*@=fcnuse@*/ +/*@=exportlocal@*/ +/*@=evalorderuncon@*/ +/*@=exportheader@*/ +/*@=redecl@*/ +/*@=loopswitchbreak@*/ +/*@=switchswitchbreak@*/ +/*@=sizeoftype@*/ +/*@=czechfcns@*/ +/*@=noparams@*/ +/*@=ansireserved@*/ +/*@=ifblock@*/ +/*@=whileblock@*/ +/*@=forblock@*/ +/*@=elseifcomplete@*/ +/*@=ptrnegate@*/ +/*@=onlytrans@*/ +/*@=temptrans@*/ +/*@=immediatetrans@*/ +/*@=namechecks@*/ +/*@=matchanyintegral@*/ +/*@=statictrans@*/ +/*@=compmempass@*/ +/*@=forempty@*/ +/*@=evalorder@*/ +/*@=retalias@*/ +/*@=redecl@*/ +/*@=retvalother@*/ +/*@=exportheader@*/ + struct skeyword { /*@null@*/ /*@observer@*/ char *name; @@ -574,7 +653,7 @@ struct skeyword ** grammar proper. */ -struct skeyword s_parsetable[] = { +static struct skeyword s_parsetable[] = { { "modifies", QMODIFIES } , { "globals", QGLOBALS } , { "alt", QALT } , @@ -594,6 +673,7 @@ struct skeyword s_parsetable[] = { { "testinRange", QTESTINRANGE}, { "requires", QPRECLAUSE } , { "ensures", QPOSTCLAUSE } , + { "invariant", QINVARIANT} , { NULL, BADTOK } } ; @@ -602,7 +682,7 @@ struct skeyword s_parsetable[] = { ** token-specific text. */ -struct skeyword s_keytable[] = { +static struct skeyword s_keytable[] = { { "anytype", QANYTYPE } , { "integraltype", QINTEGRALTYPE } , { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } , @@ -616,6 +696,8 @@ struct skeyword s_keytable[] = { { "special", QSPECIAL } , { "truenull", QTRUENULL } , { "falsenull", QFALSENULL } , + { "nullwhentrue", QTRUENULL } , + { "falsewhennull", QFALSENULL } , { "keep", QKEEP } , { "kept", QKEPT } , { "notnull", QNOTNULL } , @@ -639,15 +721,23 @@ struct skeyword s_keytable[] = { { "nullterminated", QNULLTERMINATED }, { "setBufferSize", QSETBUFFERSIZE }, { "testInRange", QTESTINRANGE}, + { "isnull", QISNULL }, { "MaxSet", QMAXSET}, { "MaxRead", QMAXREAD}, + { "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 } , @@ -685,7 +775,7 @@ static bool isArtificial (cstring s) || cstring_equalLit (s, "alt")); } -void swallowMacro (void) +void cscanner_swallowMacro (void) { int i; bool skipnext = FALSE; @@ -694,7 +784,6 @@ void swallowMacro (void) { char c = (char) i; - if (c == '\\') { skipnext = TRUE; @@ -711,6 +800,10 @@ void swallowMacro (void) return; } } + else + { + ; + } } if (i != EOF) @@ -751,9 +844,8 @@ static int tokenMacroCode (cstring s) voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral - ("Traditional lint comment /*FALLTHROUGH*/ used. " - "This is interpreted by " - "LCLint in the same way as most Unix lints, but it is " + ("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); @@ -764,9 +856,8 @@ static int tokenMacroCode (cstring s) voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral - ("Traditional lint comment /*FALLTHRU*/ used. " - "This is interpreted by " - "LCLint in the same way as most Unix lints, but it is " + ("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); @@ -777,9 +868,8 @@ static int tokenMacroCode (cstring s) voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral - ("Traditional lint comment /*NOTREACHED*/ used. " - "This is interpreted by " - "LCLint in the same way as most Unix lints, but it is " + ("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); @@ -796,9 +886,8 @@ static int tokenMacroCode (cstring s) voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral - ("Traditional lint comment /*PRINTFLIKE*/ used. " - "This is interpreted by " - "LCLint in the same way as most Unix lints, but it is " + ("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); @@ -821,9 +910,8 @@ static int tokenMacroCode (cstring s) voptgenerror (FLG_WARNLINTCOMMENTS, cstring_makeLiteral - ("Traditional lint comment /*ARGSUSED*/ used. " - "This is interpreted by " - "LCLint in the same way as most Unix lints, but it is " + ("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); @@ -831,10 +919,12 @@ static int tokenMacroCode (cstring s) setArgsUsed (); return SKIPTOK; } - - return s_keytable[i].token; + else + { + return s_keytable[i].token; + } } - + i++; } @@ -887,6 +977,10 @@ static int returnInt (ctype ct, long i) { c = context_typeofOne (); } + else + { + ; + } } yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext), @@ -915,7 +1009,7 @@ static int ninput () return c; } -static char macro_nextChar () +static char macro_nextChar (void) { static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE; int ic; @@ -1012,6 +1106,11 @@ static char macro_nextChar () lmsavechar (c2); } } + else + { + ; + } + return c; } @@ -1019,7 +1118,7 @@ static char macro_nextChar () ** keeps semantic comments */ -static char macro_nextCharC () +static char macro_nextCharC (void) { static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE; char c; @@ -1100,6 +1199,11 @@ static char macro_nextCharC () lmsavechar (c2); } } + else /* normal character */ + { + ; + } + return c; } @@ -1108,7 +1212,7 @@ static char macro_nextCharC () ** returns first non-whitespace character */ -static char skip_whitespace () +static char skip_whitespace (void) { char c; @@ -1138,7 +1242,7 @@ static void handleMacro () { int i; - for (i = 0; i < ((c - '0') + 1); i++) + for (i = 0; i < (((int) (c - '0')) + 1); i++) { mac = cstring_appendChar (mac, ' '); } @@ -1219,27 +1323,25 @@ static bool processMacro (void) { c = macro_nextChar (); } - unput (c); + unput ((int) c); } if (c == '\n') { emptyMacro = TRUE; - unput (c); + unput ((int) 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))) { @@ -1312,7 +1414,7 @@ static bool processMacro (void) uentry_showWhereSpecified (e2); uentry_setType (e2, ctype_unknown); - uentry_makeVarFunction (e2); + uentry_makeConstantFunction (e2); uentry_setDefined (e2, g_currentloc); uentry_setFunctionDefined (e2, g_currentloc); context_enterUnknownMacro (e2); @@ -1351,6 +1453,10 @@ static bool processMacro (void) fileloc_unparse (oloc)), loc); } + else + { + /* No warning */ + } } context_enterConstantMacro (e2); @@ -1428,7 +1534,7 @@ static bool processMacro (void) "typedef should be used instead."), g_currentloc); - swallowMacro (); + cscanner_swallowMacro (); /* Must exit scope (not sure why a new scope was entered?) */ usymtab_quietExitScope (g_currentloc); uentry_setDefined (e2, g_currentloc); @@ -1457,24 +1563,47 @@ static bool processMacro (void) { uentry ce; - 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; + /* 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 */ @@ -1523,14 +1652,14 @@ static bool processMacro (void) && !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)); + sr = sRef_makeParam (paramno, uentry_getType (param), stateInfo_makeLoc (sloc)); if (sRef_getNullState (sr) == NS_ABSNULL) { @@ -1547,12 +1676,12 @@ static bool processMacro (void) } else { - sRef_setNullState (sr, NS_UNKNOWN, g_currentloc); + sRef_setNullState (sr, NS_UNKNOWN, sloc); } } uentry_setSref (param, sr); - uentry_setDeclaredForceOnly (param, context_getSaveLocation ()); + uentry_setDeclaredForceOnly (param, sloc); skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno)); } @@ -1561,11 +1690,12 @@ static bool processMacro (void) fileloc sloc = context_getSaveLocation (); param = uentry_makeVariableSrefParam - (paramname, ctype_unknown, sRef_makeParam (paramno, ctype_unknown)); + (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; @@ -1657,31 +1787,32 @@ static bool processMacro (void) static bool handleSpecial (char *yyt) { - char *l = mstring_create (MAX_NAME_LENGTH); - static bool reportcpp = FALSE; + char *l; /* !! = mstring_create (MAX_NAME_LENGTH); */ int lineno = 0; char c; char *ol; cstring olc; - - strcpy (l, yyt + 1); + size_t len_yyt; - /* Need to safe original l for deallocating. */ - ol = l; + len_yyt = strlen (yyt +1) ; - l += strlen (yyt) - 1; + l = mstring_copy (yyt + 1); while ((c = char_fromInt (lminput ())) != '\n' && c != '\0') { - *l++ = c; + l = mstring_append(l, c); } - *l = '\0'; + /* Need to safe original l for deallocating. */ + ol = l; + + l += strlen (l); + olc = cstring_fromChars (ol); - if (cstring_equalPrefix (olc, "pragma")) + if (cstring_equalPrefixLit (olc, "pragma")) { - char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN)); + char *pname = mstring_create (size_fromInt (MAX_PRAGMA_LEN)); char *opname = pname; char *ptr = ol + 6; /* pragma is six characters, plus space */ int len = 0; @@ -1737,7 +1868,7 @@ static bool handleSpecial (char *yyt) cstring_free (exname); } } - else if (cstring_equalPrefix (olc, "ident")) + else if (cstring_equalPrefixLit (olc, "ident")) { /* Some pre-processors will leave these in the code. Ignore rest of line */ } @@ -1819,7 +1950,11 @@ static bool handleSpecial (char *yyt) if (!(fileId_isValid (fid))) { - if (isHeaderFile (fname)) + if (context_inXHFile ()) + { + fid = fileTable_addXHFile (context_fileTable (), fname); + } + else if (isHeaderFile (fname)) { fid = fileTable_addHeaderFile (context_fileTable (), fname); } @@ -1848,26 +1983,24 @@ static bool handleSpecial (char *yyt) mstring_free (ol); return FALSE; } else { - if (!reportcpp) - { - - } else { - llbug (message ("File contains preprocessor command: #%s", - cstring_fromChars (ol))); - reportcpp = TRUE; - } + voptgenerror + (FLG_UNRECOGDIRECTIVE, + message ("Unrecognized pre-processor directive: #%s", + cstring_fromChars (ol)), + g_currentloc); } sfree (ol); - return TRUE; + return FALSE; /* evans 2001-12-30: was: TRUE; */ } sfree (ol); return FALSE; } -static int handleLlSpecial () +static int handleLlSpecial (void) { + bool hasnl = FALSE; int ic; char c; char *s = mstring_createEmpty (); @@ -1893,7 +2026,7 @@ static int handleLlSpecial () { ic = ninput (); - llassert (ic == AFTER_COMMENT_MARKER[1]); + llassert (ic == (int) AFTER_COMMENT_MARKER[1]); if (*s == '\0') { @@ -1910,7 +2043,8 @@ static int handleLlSpecial () { tokLength = charsread; sfree (os); - inSpecPart = TRUE; + s_inSpecPart = TRUE; + s_whichSpecPart = tok; fileloc_free (loc); return tok; } @@ -1926,9 +2060,23 @@ static int handleLlSpecial () charsread++; while (((ic = ninput ()) != 0) && (ic != EOF) - && (ic != AFTER_COMMENT_MARKER[0])) + && (ic != (int) 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++; } @@ -1936,7 +2084,7 @@ static int handleLlSpecial () DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc))); - if (ic == AFTER_COMMENT_MARKER[0]) + if (ic == (int) AFTER_COMMENT_MARKER[0]) { int nc = ninput (); llassert ((char) nc == AFTER_COMMENT_MARKER[1]); @@ -1974,39 +2122,36 @@ static int handleLlSpecial () if (!context_getFlag (FLG_NOCOMMENTS)) { cstring flagname = thisflag; - flagcode fflag = identifyFlag (flagname); - + flagcode fflag = flags_identifyFlag (flagname); + if (flagcode_isSkip (fflag)) { ; } - else if (flagcode_isInvalid (fflag)) + else if (flagcode_isModeName (fflag)) { - if (isMode (flagname)) + if (ynm_isMaybe (set)) { - 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); - } + llerror + (FLG_BADFLAG, + message + ("Semantic comment attempts to restore flag %s. " + "A mode flag cannot be restored.", + flagname)); } else { - voptgenerror - (FLG_UNRECOGFLAGCOMMENTS, - message ("Unrecognized option in semantic comment: %s", - flagname), - g_currentloc); + 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 @@ -2015,11 +2160,11 @@ static int handleLlSpecial () ("Semantic comment attempts to set global flag %s. " "A global flag cannot be set locally.", flagname), - g_currentloc); + loc); } else { - context_fileSetFlag (fflag, set); + context_fileSetFlag (fflag, set, loc); if (flagcode_hasArgument (fflag)) { @@ -2031,7 +2176,7 @@ static int handleLlSpecial () ("Semantic comment attempts to restore flag %s. " "A flag for setting a value cannot be restored.", flagname), - g_currentloc); + loc); } else { /* cut-and-pastied from llmain...blecch */ @@ -2059,7 +2204,10 @@ static int handleLlSpecial () rest++; s++; } - + s--; /* evans 2002-07-12: this was previously only in the else branch. + Leads to an invalid read on the true branch. + */ + sfree (orest); if (cstring_isUndefined (extra)) @@ -2069,12 +2217,15 @@ static int handleLlSpecial () message ("Flag %s (in semantic comment) must be followed by an argument", flagcode_unparse (fflag))); + } else { - s--; - - if (flagcode_hasValue (fflag)) + if (flagcode_hasNumber (fflag)) + { + setValueFlag (fflag, extra); + } + else if (flagcode_hasChar (fflag)) { setValueFlag (fflag, extra); } @@ -2084,6 +2235,7 @@ static int handleLlSpecial () } else { + cstring_free (extra); BADEXIT; } } @@ -2106,7 +2258,7 @@ static int handleLlSpecial () if (context_inHeader () && !isArtificial (cstring_fromChars (os))) { DPRINTF (("Here adding comment: %s", os)); - context_addComment (cstring_fromCharsNew (os)); + context_addComment (cstring_fromCharsNew (os), loc); } else { @@ -2137,7 +2289,7 @@ static int handleLlSpecial () if (macrocode != BADTOK) { - tokLength = mstring_length (t); + tokLength = hasnl ? 0 : size_toInt (mstring_length (t)); sfree (t); sfree (os); @@ -2174,8 +2326,14 @@ static int handleLlSpecial () && macrocode != SKIPTOK && !isArtificial (cstring_fromChars (os))) { - DPRINTF (("Add comment: %s", os)); - context_addComment (cstring_fromCharsNew (os)); + if (context_processingMacros ()) + { + /* evans 2002-02-24: don't add comments when procssing macros */ + } + else + { + context_addComment (cstring_fromCharsNew (os), loc); + } } else { @@ -2192,7 +2350,7 @@ static int handleLlSpecial () { if (!context_getFlag (FLG_NOCOMMENTS)) { - context_enterSuppressRegion (); + context_enterSuppressRegion (loc); } } else if ((*t == 'i' || *t == 't') @@ -2201,7 +2359,7 @@ static int handleLlSpecial () if (!context_getFlag (FLG_NOCOMMENTS) && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS))) { - context_enterSuppressLine (-1); /* infinite suppression */ + context_enterSuppressLine (-1, loc); /* infinite suppression */ } } else if (((*t == 'i') || (*t == 't')) @@ -2220,23 +2378,23 @@ static int handleLlSpecial () while (lc >= '0' && lc <= '9') { val *= 10; - val += lc - '0'; + val += (int) (lc - '0'); lc = *(++tt); } } - if (!context_getFlag (FLG_NOCOMMENTS) && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS))) { - context_enterSuppressLine (val); + 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 (); + context_exitSuppressRegion (loc); } } else if (mstring_equal (t, "notfunction")) @@ -2249,7 +2407,7 @@ static int handleLlSpecial () while (TRUE) { - while ((c = *s) && (c == ' ' || c == '\t' || c == '\n')) + while (((c = *s) != '\0') && (c == ' ' || c == '\t' || c == '\n')) { s++; } @@ -2291,20 +2449,20 @@ static int handleLlSpecial () message ("Non-abstract type %s used in access comment", tname), - g_currentloc); + loc); } } else { if (!(context_inSuppressRegion () - || context_inSuppressZone (g_currentloc))) + || context_inSuppressZone (loc))) { voptgenerror (FLG_COMMENTERROR, message ("Unrecognized type %s used in access comment", tname), - g_currentloc); + loc); } } } @@ -2327,7 +2485,7 @@ static int handleLlSpecial () while (TRUE) { - while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n')) + while (((lc = *s) != '\0') && (lc == ' ' || lc == '\t' || lc == '\n')) { s++; } @@ -2362,7 +2520,7 @@ static int handleLlSpecial () else { if (!(context_inSuppressRegion () - || context_inSuppressZone (g_currentloc))) + || context_inSuppressZone (loc))) { uentry ue = usymtab_getTypeEntry (tuid); @@ -2373,7 +2531,7 @@ static int handleLlSpecial () message ("Non-accessible abstract type %s used in noaccess comment", tname), - g_currentloc); + loc); } else { @@ -2382,7 +2540,7 @@ static int handleLlSpecial () message ("Non-abstract type %s used in noaccess comment", tname), - g_currentloc); + loc); } } } @@ -2390,14 +2548,14 @@ static int handleLlSpecial () else { if (!(context_inSuppressRegion () - || context_inSuppressZone (g_currentloc))) + || context_inSuppressZone (loc))) { voptgenerror (FLG_COMMENTERROR, message ("Unrecognized type %s used in noaccess comment", tname), - g_currentloc); + loc); } } } @@ -2417,9 +2575,10 @@ static int handleLlSpecial () { voptgenerror (FLG_UNRECOGCOMMENTS, message ("Semantic comment unrecognized: %s", - cstring_fromChars (os)), loc); + cstring_fromChars (os)), + loc); } - + sfree (t); } @@ -2430,7 +2589,7 @@ static int handleLlSpecial () static /*@only@*/ cstring makeIdentifier (char *s) { - char *c = mstring_create (size_toInt (strlen (s)) + 1); + char *c = mstring_create (strlen (s) + 1); cstring id = cstring_fromChars (c); while (isalnum (*s) || (*s == '_') || (*s == '$')) @@ -2483,25 +2642,46 @@ static /*@only@*/ cstring makeIdentifier (char *s) return (usymtab_lookup (cn)); } -/*@observer@*/ cstring LastIdentifier () +/* +** Need to keep this in case there is a declaration that isn't processed until +** the scope exits. Would be good to rearrange the symbol table so this doesn't +** happen, and save all the cstring copying. +*/ + +/*@observer@*/ cstring cscanner_observeLastIdentifier () +{ + cstring res = s_lastidprocessed; + return res; +} + +static void cscanner_setLastIdentifier (/*@keep@*/ cstring id) /*@modifies s_lastidprocessed@*/ { - return (lastidprocessed); + if (cstring_isDefined (s_lastidprocessed)) + { + cstring_free (s_lastidprocessed); + } + + s_lastidprocessed = id; } static int processIdentifier (cstring id) { uentry le; - DPRINTF (("Process identifier: %s / %s / %s", id, fileloc_unparse (g_currentloc), - bool_unparse (context_inFunctionHeader ()))); + if (context_getFlag (FLG_GRAMMAR)) + { + lldiagmsg (message ("Process identifier: %s", id)); + } context_clearJustPopped (); - lastidprocessed = id; + cscanner_setLastIdentifier (id); + + DPRINTF (("Context: %s", context_unparse ())); if (context_inFunctionHeader ()) { int tok = commentMarkerToken (id); - DPRINTF (("in function decl...")); + DPRINTF (("in function decl: %s", id)); if (tok != BADTOK) { @@ -2510,7 +2690,7 @@ static int processIdentifier (cstring id) else { tok = tokenMacroCode (id); - + if (tok != BADTOK) { return tok; @@ -2550,6 +2730,8 @@ static int processIdentifier (cstring id) } } + DPRINTF (("Here!")); + /* Consider handling: Defined by C99 as static const char __func__[] */ if (context_getFlag (FLG_GNUEXTENSIONS)) @@ -2582,11 +2764,20 @@ static int processIdentifier (cstring id) { 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 */ - yylval.expr = exprNode_stringLiteral (id, fileloc_copy (g_currentloc)); + /* 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; @@ -2607,22 +2798,23 @@ static int processIdentifier (cstring id) while ((ic = input ()) != EOF) { - + char cc = (char) ic; + if (inescape) { inescape = FALSE; } - else if (ic == '\\') + else if (cc == '\\') { inescape = TRUE; } - else if (ic == '\"') + else if (cc == '\"') { inquote = !inquote; } else if (!inquote) { - if (ic == '(') + if (cc == '(') { if (!useparens) { @@ -2637,7 +2829,7 @@ static int processIdentifier (cstring id) depth++; } } - else if (ic == '{') + else if (cc == '{') { if (!usebraces) { @@ -2652,17 +2844,17 @@ static int processIdentifier (cstring id) depth++; } } - else if (ic == ')' && useparens) + else if (cc == ')' && useparens) { depth--; if (depth == 0) break; } - else if (ic == '}' && usebraces) + else if (cc == '}' && usebraces) { depth--; if (depth == 0) break; } - else if (ic == '}' + else if (cc == '}' && !usebraces && !useparens && cstring_equalLit (id, "__asm")) { @@ -2674,9 +2866,17 @@ static int processIdentifier (cstring id) */ return TRBRACE; } + else + { + ; + } + } + else + { + ; } - if (ic == '\n') + if (cc == '\n') { context_incLineno (); @@ -2688,8 +2888,8 @@ static int processIdentifier (cstring id) } } - llassert ((useparens && ic == ')') - || (usebraces && ic == '}') + llassert ((useparens && ic == (int) ')') + || (usebraces && ic == (int) '}') || (!useparens && !usebraces)); return BADTOK; @@ -2701,6 +2901,10 @@ static int processIdentifier (cstring id) { tok = QINLINE; } + else + { + ; + } if (tok != BADTOK) { @@ -2724,7 +2928,7 @@ static int processIdentifier (cstring id) } else if (uentry_isUndefined (le)) { - yylval.cname = id; + yylval.cname = cstring_copy (id); /* avoid parse errors for certain system built ins */ @@ -2740,7 +2944,7 @@ static int processIdentifier (cstring id) { if (uentry_isDatatype (le)) { - yylval.cname = id; + yylval.cname = cstring_copy (id); return (NEW_IDENTIFIER); } else @@ -2753,7 +2957,7 @@ static int processIdentifier (cstring id) { if (!g_expectingTypeName) { - yylval.cname = id; + yylval.cname = cstring_copy (id); return (NEW_IDENTIFIER); } @@ -2783,8 +2987,8 @@ static bool processHashIdentifier (/*@only@*/ cstring id) context_clearJustPopped (); - lastidprocessed = id; le = usymtab_lookupSafe (id); + cscanner_setLastIdentifier (id); if (uentry_isParam (le) || uentry_isRefParam (le)) { @@ -2797,13 +3001,17 @@ static bool processHashIdentifier (/*@only@*/ cstring id) } else { + /* + ** Will be handled by handleLlSpecial + */ + cstring_free (id); return FALSE; } } -static /*@only@*/ exprNode processString () +static /*@only@*/ exprNode processString (void) { exprNode res; fileloc loc; @@ -2813,7 +3021,7 @@ static /*@only@*/ exprNode processString () if (nl == NULL) { loc = fileloc_copy (g_currentloc); - addColumn (cstring_length (ns)); + addColumn (size_toInt (cstring_length (ns))); } else { @@ -2835,6 +3043,46 @@ static /*@only@*/ exprNode processString () 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 (size_toInt (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 () { @@ -2932,6 +3180,22 @@ long processOctal () 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, @@ -2959,20 +3223,55 @@ static int processSpec (int tok) { size_t length = strlen (yytext); - - if (inSpecPart) - { - setTokLengthT (length); - RETURN_TOK (tok); - } - else + if (s_inSpecPart) { - - context_saveLocation (); - setTokLengthT (length); - return (processIdentifier (makeIdentifier (yytext))); + + /*drl 12/11/2002 + patched to fix assert failures in constraint code. + Added the else if test so that splint does not treat MaxSet and MaxRead + as identifies*/ + + if (s_whichSpecPart == QMODIFIES + || s_whichSpecPart == QDEFINES + || s_whichSpecPart == QUSES + || s_whichSpecPart == QALLOCATES + || s_whichSpecPart == QSETS + || s_whichSpecPart == QRELEASES) + + { + DPRINTF((message("Treating specifaction keyword %s as an identifiers. (This corresponds to" + " token %d and we're in the specification denoted by %d see cgrammar_tokens.h" + " for an explanation of these numbers", + yytext, tok, s_whichSpecPart) + )); + + ; /* Allow specificiation keywords to be used as identifiers in these contexts. */ + } + else if ( (s_whichSpecPart == QPRECLAUSE + || s_whichSpecPart == QPOSTCLAUSE + || s_whichSpecPart == QINVARIANT ) + && (!isConstraintToken(tok) ) + ) + { + DPRINTF((message("Treating specifaction keyword %s as an identifiers. (This corresponds to" + " token %d and we're in the specification denoted by %d see cgrammar_tokens.h" + " for an explanation of these numbers", + yytext, tok, s_whichSpecPart) + )); + + /* Allow specificiation keywords to be used as identifiers in these contexts. */ + } + else + { + setTokLengthT (length); + RETURN_TOK (tok); + } } + + context_saveLocation (); + setTokLengthT (length); + return (processIdentifier (makeIdentifier (yytext))); } void cscanner_expectingMetaStateName () @@ -2987,3 +3286,29 @@ void cscanner_clearExpectingMetaStateName () llassert (expectingMetaStateName); expectingMetaStateName = FALSE; } + +/*drl added 12/11/2002 + Tell whether a token has special meaning + within a function constraint +*/ + +/*uncomment the additional if statement tests + when minSet and minRead are supported +*/ +int isConstraintToken(int tok) +{ + if ( tok == QMAXSET + || tok == QMAXREAD + + /* || tok == QMINREAD + || tok == QMINSET */ + + ) + { + return TRUE; + } + else + { + return FALSE; + } +}