/*;-*-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-2001 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 lclint: lclint-request@cs.virginia.edu
+** To report a bug: lclint-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 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
+*/
Digit [0-9]
Letter [a-zA-Z_$]
ULSuffix ({U}{L}|{L}{U})
%{
-/*
-** based on original C lexer by Nate Osgood
-** from hacrat@catfish.lcs.mit.edu Mon Jun 14 13:06:32 1993
-**
-*/
-
# include "lclintMacros.nf"
+# if defined(OS2) && defined(__IBMC__)
+ /* needed for isatty()... */
+# include <io.h>
+# else
+# include <unistd.h>
+# endif
+
# include "basic.h"
# include "cgrammar.h"
# include "fileIdList.h"
# include "portab.h"
-# if defined(OS2) && defined(__IBMC__)
- /* needed for isatty()... */
-# include <io.h>
-# 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 int lminput (void);
static int tokLength = 0;
static bool inSpecPart = FALSE;
/* 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);
{
addColumn (len);
tokLength = len;
+ DPRINTF (("Set tok length: %d", len));
}
static void setTokLengthT (size_t len)
"static" { setTokLength (6); RETURN_TOK (QSTATIC); }
\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
+L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
"out" { return (processSpec (QOUT)); }
"in" { return (processSpec (QIN)); }
"partial" { return (processSpec (QPARTIAL)); }
"killed" { return (processSpec (QKILLED)); }
"nullterminated" { return (processSpec (QNULLTERMINATED));}
"MaxSet" { return (processSpec (QMAXSET));}
-"MaxRead" { return (processSpec (QMAXREAD));}
+"MaxRead" { return (processSpec (QMAXREAD));}
+"maxSet" { return (processSpec (QMAXSET));}
+"maxRead" { return (processSpec (QMAXREAD));}
{Letter}({Letter}|{Digit})* { int tok;
context_saveLocation ();
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));
[ \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;
if (processMacro ())
{
+ DPRINTF (("Here we are: %s", context_unparse ()));
+
if (context_inIterDef ())
{
RETURN_TOK (LLMACROITER);
{ "releases", QRELEASES } ,
{ "pre", QPRECLAUSE } ,
{ "post", QPOSTCLAUSE } ,
- {"setBufferSize", QSETBUFFERSIZE},
- {"LRequires", QBUFFERCONSTRAINT},
- {"LEnsures", QENSURESCONSTRAINT},
- {"setStringLength", QSETSTRINGLENGTH},
- {"testinRange", QTESTINRANGE},
+ { "setBufferSize", QSETBUFFERSIZE},
+ { "setStringLength", QSETSTRINGLENGTH},
+ { "testinRange", QTESTINRANGE},
{ "requires", QPRECLAUSE } ,
{ "ensures", QPOSTCLAUSE } ,
{ NULL, BADTOK }
{ "relnull", QRELNULL } ,
{ "nullterminated", QNULLTERMINATED },
{ "setBufferSize", QSETBUFFERSIZE },
- { "LRequires", QBUFFERCONSTRAINT },
- { "LEnsures", QENSURESCONSTRAINT },
{ "testInRange", QTESTINRANGE},
{ "MaxSet", QMAXSET},
{ "MaxRead", QMAXREAD},
}
hasParams = (c == '(');
-
if (usymtab_exists (fname))
{
e2 = usymtab_lookupExpose (fname);
ct = uentry_getType (e2);
-
if (uentry_isCodeDefined (e2)
&& fileloc_isUser (uentry_whereDefined (e2)))
{
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);
{
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 */
&& !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)
{
}
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));
}
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;
static bool handleSpecial (char *yyt)
{
char *l = mstring_create (MAX_NAME_LENGTH);
- static bool reportcpp = FALSE;
int lineno = 0;
char c;
char *ol;
*l = '\0';
olc = cstring_fromChars (ol);
- if (cstring_equalPrefix (olc, "pragma"))
+ if (cstring_equalPrefixLit (olc, "pragma"))
{
char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN));
char *opname = pname;
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 */
}
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);
}
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);
static int handleLlSpecial ()
{
+ bool hasnl = FALSE;
int ic;
char c;
char *s = mstring_createEmpty ();
&& (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)),
+ g_currentloc);
+ }
+
s = mstring_append (s, c);
charsread++;
}
}
else
{
- llerror
- (FLG_BADFLAG,
+ voptgenerror
+ (FLG_UNRECOGFLAGCOMMENTS,
message ("Unrecognized option in semantic comment: %s",
- flagname));
+ flagname),
+ g_currentloc);
}
}
else if (flagcode_isGlobalFlag (fflag))
{
- llerror
+ voptgenerror
(FLG_BADFLAG,
message
("Semantic comment attempts to set global flag %s. "
"A global flag cannot be set locally.",
- flagname));
+ flagname),
+ g_currentloc);
}
else
{
{
if (ynm_isMaybe (set))
{
- llerror
+ voptgenerror
(FLG_BADFLAG,
message
("Semantic comment attempts to restore flag %s. "
"A flag for setting a value cannot be restored.",
- flagname));
+ flagname),
+ g_currentloc);
}
else
{ /* cut-and-pastied from llmain...blecch */
if (macrocode != BADTOK)
{
- tokLength = mstring_length (t);
+ tokLength = hasnl ? 0 : mstring_length (t);
sfree (t);
sfree (os);
{
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;
}
else
{
- annotationInfo ainfo = context_lookupAnnotation (id);
+ 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))
{
|| 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;
}
else
{
+ /*
+ ** Will be handled by handleLlSpecial
+ */
+
cstring_free (id);
return FALSE;
}
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,
processSpec (int tok)
{
size_t length = strlen (yytext);
-
if (inSpecPart)
{
return (processIdentifier (makeIdentifier (yytext)));
}
}
+
+void cscanner_expectingMetaStateName ()
+{
+ llassert (!expectingMetaStateName);
+ llassert (context_inFunctionHeader ());
+ expectingMetaStateName = TRUE;
+}
+
+void cscanner_clearExpectingMetaStateName ()
+{
+ llassert (expectingMetaStateName);
+ expectingMetaStateName = FALSE;
+}