mirror of
https://github.com/cc65/cc65.git
synced 2024-06-07 23:29:39 +00:00
Merge pull request #2272 from acqn/Diagnostics
[cc65] Improved diagnostics
This commit is contained in:
commit
5537b61e6a
|
@ -102,7 +102,7 @@ static SymEntry* AsmGetSym (unsigned Arg, unsigned Type)
|
||||||
|
|
||||||
/* Did we find a symbol with this name? */
|
/* Did we find a symbol with this name? */
|
||||||
if (Sym == 0) {
|
if (Sym == 0) {
|
||||||
Error ("Undefined symbol '%s' for argument %u", CurTok.Ident, Arg);
|
Error ("Undeclared symbol '%s' for argument %u", CurTok.Ident, Arg);
|
||||||
AsmErrorSkip ();
|
AsmErrorSkip ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,8 @@ static void Parse (void)
|
||||||
while (CurTok.Tok != TOK_CEOF) {
|
while (CurTok.Tok != TOK_CEOF) {
|
||||||
|
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
|
int NeedClean = 0;
|
||||||
|
unsigned PrevErrorCount = ErrorCount;
|
||||||
|
|
||||||
/* Check for empty statements */
|
/* Check for empty statements */
|
||||||
if (CurTok.Tok == TOK_SEMI) {
|
if (CurTok.Tok == TOK_SEMI) {
|
||||||
|
@ -144,7 +146,11 @@ static void Parse (void)
|
||||||
Declarator Decl;
|
Declarator Decl;
|
||||||
|
|
||||||
/* Read the next declaration */
|
/* Read the next declaration */
|
||||||
ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
|
NeedClean = ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
|
||||||
|
if (Decl.Ident[0] == '\0') {
|
||||||
|
Sym = 0;
|
||||||
|
goto NextDecl;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we must reserve storage for the variable. We do this,
|
/* Check if we must reserve storage for the variable. We do this,
|
||||||
**
|
**
|
||||||
|
@ -310,6 +316,7 @@ static void Parse (void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NextDecl:
|
||||||
/* Check for end of declaration list */
|
/* Check for end of declaration list */
|
||||||
if (CurTok.Tok == TOK_COMMA) {
|
if (CurTok.Tok == TOK_COMMA) {
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
@ -325,6 +332,7 @@ static void Parse (void)
|
||||||
/* Function */
|
/* Function */
|
||||||
if (CurTok.Tok == TOK_SEMI) {
|
if (CurTok.Tok == TOK_SEMI) {
|
||||||
/* Prototype only */
|
/* Prototype only */
|
||||||
|
NeedClean = 0;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else if (CurTok.Tok == TOK_LCURLY) {
|
} else if (CurTok.Tok == TOK_LCURLY) {
|
||||||
/* ISO C: The type category in a function definition cannot be
|
/* ISO C: The type category in a function definition cannot be
|
||||||
|
@ -337,6 +345,7 @@ static void Parse (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the function body anyways */
|
/* Parse the function body anyways */
|
||||||
|
NeedClean = 0;
|
||||||
NewFunc (Sym, FuncDef);
|
NewFunc (Sym, FuncDef);
|
||||||
|
|
||||||
/* Make sure we aren't omitting any work */
|
/* Make sure we aren't omitting any work */
|
||||||
|
@ -345,10 +354,27 @@ static void Parse (void)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Must be followed by a semicolon */
|
if (Sym) {
|
||||||
ConsumeSemi ();
|
/* Must be followed by a semicolon */
|
||||||
|
if (CurTok.Tok != TOK_SEMI) {
|
||||||
|
NeedClean = -1;
|
||||||
|
}
|
||||||
|
ConsumeSemi ();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try some smart error recovery */
|
||||||
|
if (PrevErrorCount != ErrorCount && NeedClean < 0) {
|
||||||
|
/* Some fix point tokens that are used for error recovery */
|
||||||
|
static const token_t TokenList[] = { TOK_SEMI, TOK_RCURLY };
|
||||||
|
|
||||||
|
SmartErrorSkip ();
|
||||||
|
SkipTokens (TokenList, sizeof (TokenList) / sizeof (TokenList[0]));
|
||||||
|
if (CurTok.Tok == TOK_SEMI || CurTok.Tok == TOK_RCURLY) {
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Done with deferred operations */
|
/* Done with deferred operations */
|
||||||
|
|
|
@ -83,6 +83,104 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void OpenBrace (Collection* C, token_t Tok)
|
||||||
|
/* Consume an opening parenthesis/bracket/curly brace and remember that */
|
||||||
|
{
|
||||||
|
switch (Tok) {
|
||||||
|
case TOK_LPAREN: Tok = TOK_RPAREN; break;
|
||||||
|
case TOK_LBRACK: Tok = TOK_RBRACK; break;
|
||||||
|
case TOK_LCURLY: Tok = TOK_RCURLY; break;
|
||||||
|
default: Internal ("Unexpected opening token: %02X", (unsigned)Tok);
|
||||||
|
}
|
||||||
|
CollAppend (C, (void*)Tok);
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int CloseBrace (Collection* C, token_t Tok)
|
||||||
|
/* Consume a closing parenthesis/bracket/curly brace if it is matched with an
|
||||||
|
** opening one and return 0, or bail out and return -1 if it is not matched.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if (CollCount (C) > 0) {
|
||||||
|
token_t LastTok = (token_t)CollLast (C);
|
||||||
|
if (LastTok == Tok) {
|
||||||
|
CollPop (C);
|
||||||
|
NextToken ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int SmartErrorSkip (void)
|
||||||
|
/* Try some smart error recovery. Skip tokens until either a comma or semicolon
|
||||||
|
** that is not enclosed in an open parenthesis/bracket/curly brace, or until an
|
||||||
|
** unpaired right parenthesis/bracket/curly brace is reached. Return 0 if it is
|
||||||
|
** the former case, or -1 if it is the latter case. */
|
||||||
|
{
|
||||||
|
Collection C = AUTO_COLLECTION_INITIALIZER;
|
||||||
|
int Res = 0;
|
||||||
|
|
||||||
|
/* Some fix point tokens that are used for error recovery */
|
||||||
|
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI,
|
||||||
|
TOK_LPAREN, TOK_RPAREN, TOK_LBRACK, TOK_RBRACK, TOK_LCURLY, TOK_RCURLY };
|
||||||
|
|
||||||
|
while (CurTok.Tok != TOK_CEOF) {
|
||||||
|
SkipTokens (TokenList, sizeof (TokenList) / sizeof (TokenList[0]));
|
||||||
|
|
||||||
|
switch (CurTok.Tok) {
|
||||||
|
case TOK_LPAREN:
|
||||||
|
case TOK_LBRACK:
|
||||||
|
case TOK_LCURLY:
|
||||||
|
OpenBrace (&C, CurTok.Tok);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_RPAREN:
|
||||||
|
case TOK_RBRACK:
|
||||||
|
if (CloseBrace (&C, CurTok.Tok)) {
|
||||||
|
Res = -1;
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_RCURLY:
|
||||||
|
if (CloseBrace (&C, CurTok.Tok)) {
|
||||||
|
Res = -1;
|
||||||
|
goto ExitPoint;
|
||||||
|
} else if (CollCount (&C) == 0) {
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_COMMA:
|
||||||
|
if (CollCount (&C) == 0) {
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
NextToken ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_SEMI:
|
||||||
|
case TOK_CEOF:
|
||||||
|
Res = -1;
|
||||||
|
goto ExitPoint;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Internal ("Unexpected token: %02X", (unsigned)CurTok.Tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitPoint:
|
||||||
|
DoneCollection (&C);
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned ParseOneStorageClass (void)
|
static unsigned ParseOneStorageClass (void)
|
||||||
/* Parse and return a storage class specifier */
|
/* Parse and return a storage class specifier */
|
||||||
{
|
{
|
||||||
|
@ -1589,6 +1687,12 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
*SignednessSpecified = 1;
|
*SignednessSpecified = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
} else if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) {
|
||||||
|
/* Treat this identifier as an unknown type */
|
||||||
|
Error ("Unknown type name '%s'", CurTok.Ident);
|
||||||
|
TypeCopy (Spec->Type, type_int);
|
||||||
|
NextToken ();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* This is a label. Use the default type flag to end the loop
|
/* This is a label. Use the default type flag to end the loop
|
||||||
|
@ -1670,14 +1774,13 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Some fix point tokens that are used for error recovery */
|
|
||||||
static const token_t TokenList[] = { TOK_COMMA, TOK_RPAREN, TOK_SEMI };
|
|
||||||
|
|
||||||
/* Not a parameter name */
|
/* Not a parameter name */
|
||||||
Error ("Identifier expected for parameter name");
|
Error ("Identifier expected for parameter name");
|
||||||
|
|
||||||
/* Try some smart error recovery */
|
/* Try some smart error recovery */
|
||||||
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
|
if (SmartErrorSkip () < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for more parameters */
|
/* Check for more parameters */
|
||||||
|
@ -1763,12 +1866,9 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
||||||
ConsumeSemi ();
|
ConsumeSemi ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PrevErrorCount != ErrorCount) {
|
if (PrevErrorCount != ErrorCount && CurTok.Tok != TOK_LCURLY) {
|
||||||
/* Some fix point tokens that are used for error recovery */
|
|
||||||
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI };
|
|
||||||
|
|
||||||
/* Try some smart error recovery */
|
/* Try some smart error recovery */
|
||||||
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
|
SmartErrorSkip ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1783,6 +1883,7 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
Declarator Decl;
|
Declarator Decl;
|
||||||
SymEntry* Param;
|
SymEntry* Param;
|
||||||
|
unsigned PrevErrorCount = ErrorCount;
|
||||||
|
|
||||||
/* Allow an ellipsis as last parameter */
|
/* Allow an ellipsis as last parameter */
|
||||||
if (CurTok.Tok == TOK_ELLIPSIS) {
|
if (CurTok.Tok == TOK_ELLIPSIS) {
|
||||||
|
@ -1818,7 +1919,7 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||||
/* Allow parameters without a name, but remember if we had some to
|
/* Allow parameters without a name, but remember if we had some to
|
||||||
** eventually print an error message later.
|
** eventually print an error message later.
|
||||||
*/
|
*/
|
||||||
ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
|
ParseDecl (&Spec, &Decl, DM_ACCEPT_PARAM_IDENT);
|
||||||
if (Decl.Ident[0] == '\0') {
|
if (Decl.Ident[0] == '\0') {
|
||||||
|
|
||||||
/* Unnamed symbol. Generate a name that is not user accessible,
|
/* Unnamed symbol. Generate a name that is not user accessible,
|
||||||
|
@ -1850,6 +1951,13 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||||
/* Count arguments */
|
/* Count arguments */
|
||||||
++F->ParamCount;
|
++F->ParamCount;
|
||||||
|
|
||||||
|
if (PrevErrorCount != ErrorCount) {
|
||||||
|
/* Try some smart error recovery */
|
||||||
|
if (SmartErrorSkip () < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for more parameters */
|
/* Check for more parameters */
|
||||||
if (CurTok.Tok == TOK_COMMA) {
|
if (CurTok.Tok == TOK_COMMA) {
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
@ -1940,7 +2048,7 @@ static FuncDesc* ParseFuncDecl (void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
static declmode_t DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
/* Recursively process direct declarators. Build a type array in reverse order. */
|
/* Recursively process direct declarators. Build a type array in reverse order. */
|
||||||
{
|
{
|
||||||
/* Read optional function or pointer qualifiers that modify the identifier
|
/* Read optional function or pointer qualifiers that modify the identifier
|
||||||
|
@ -1957,61 +2065,49 @@ static void DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
/* Skip the star */
|
/* Skip the star */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
|
/* A pointer type cannot be used as an empty declaration */
|
||||||
|
if (Mode == DM_ACCEPT_IDENT) {
|
||||||
|
Mode = DM_NEED_IDENT;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allow const, restrict, and volatile qualifiers */
|
/* Allow const, restrict, and volatile qualifiers */
|
||||||
Qualifiers |= OptionalQualifiers (Qualifiers, T_QUAL_CVR);
|
Qualifiers |= OptionalQualifiers (Qualifiers, T_QUAL_CVR);
|
||||||
|
|
||||||
/* Parse the type that the pointer points to */
|
/* Parse the type that the pointer points to */
|
||||||
DirectDecl (Spec, D, Mode);
|
Mode = DirectDecl (Spec, D, Mode);
|
||||||
|
|
||||||
/* Add the type */
|
/* Add the type */
|
||||||
AddTypeCodeToDeclarator (D, T_PTR | Qualifiers);
|
AddTypeCodeToDeclarator (D, T_PTR | Qualifiers);
|
||||||
return;
|
return Mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurTok.Tok == TOK_LPAREN) {
|
if (CurTok.Tok == TOK_LPAREN) {
|
||||||
NextToken ();
|
NextToken ();
|
||||||
DirectDecl (Spec, D, Mode);
|
/* An empty declaration cannot contain parentheses where an identifier
|
||||||
ConsumeRParen ();
|
** would show up if it were a non-empty declaration.
|
||||||
} else {
|
|
||||||
/* Things depend on Mode now:
|
|
||||||
** - Mode == DM_NEED_IDENT means:
|
|
||||||
** we *must* have a type and a variable identifer.
|
|
||||||
** - Mode == DM_NO_IDENT means:
|
|
||||||
** we must have a type but no variable identifer
|
|
||||||
** (if there is one, it's not read).
|
|
||||||
** - Mode == DM_ACCEPT_IDENT means:
|
|
||||||
** we *may* have an identifier. If there is an identifier,
|
|
||||||
** it is read, but it is no error, if there is none.
|
|
||||||
*/
|
*/
|
||||||
if (Mode == DM_NO_IDENT) {
|
if (Mode == DM_ACCEPT_IDENT) {
|
||||||
D->Ident[0] = '\0';
|
Mode = DM_NEED_IDENT;
|
||||||
} else if (CurTok.Tok == TOK_IDENT) {
|
}
|
||||||
strcpy (D->Ident, CurTok.Ident);
|
Mode = DirectDecl (Spec, D, Mode);
|
||||||
NextToken ();
|
ConsumeRParen ();
|
||||||
} else {
|
} else if (CurTok.Tok == TOK_IDENT) {
|
||||||
if (Mode == DM_NEED_IDENT) {
|
strcpy (D->Ident, CurTok.Ident);
|
||||||
/* Some fix point tokens that are used for error recovery */
|
NextToken ();
|
||||||
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI, TOK_LCURLY, TOK_RCURLY };
|
} else {
|
||||||
|
D->Ident[0] = '\0';
|
||||||
Error ("Identifier expected");
|
if (Mode == DM_NEED_IDENT) {
|
||||||
|
Error ("Identifier expected");
|
||||||
/* Try some smart error recovery */
|
|
||||||
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
|
|
||||||
|
|
||||||
/* Skip curly braces */
|
|
||||||
if (CurTok.Tok == TOK_LCURLY) {
|
|
||||||
static const token_t CurlyToken[] = { TOK_RCURLY };
|
|
||||||
SkipTokens (CurlyToken, sizeof(CurlyToken) / sizeof(CurlyToken[0]));
|
|
||||||
NextToken ();
|
|
||||||
} else if (CurTok.Tok == TOK_RCURLY) {
|
|
||||||
NextToken ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
D->Ident[0] = '\0';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
|
while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
|
||||||
|
/* An array or function type cannot be used as an empty declaration */
|
||||||
|
if (Mode == DM_ACCEPT_IDENT && D->Ident[0] == '\0') {
|
||||||
|
Mode = DM_NEED_IDENT;
|
||||||
|
Error ("Identifier expected");
|
||||||
|
}
|
||||||
|
|
||||||
if (CurTok.Tok == TOK_LPAREN) {
|
if (CurTok.Tok == TOK_LPAREN) {
|
||||||
|
|
||||||
/* Function declarator */
|
/* Function declarator */
|
||||||
|
@ -2097,6 +2193,8 @@ static void DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
if (Qualifiers & T_QUAL_CDECL) {
|
if (Qualifiers & T_QUAL_CDECL) {
|
||||||
Error ("Invalid '__cdecl__' qualifier");
|
Error ("Invalid '__cdecl__' qualifier");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2129,8 +2227,10 @@ Type* ParseType (Type* T)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
/* Parse a variable, type or function declarator */
|
/* Parse a variable, type or function declarator. Return -1 if this stops at
|
||||||
|
** an unpaired right parenthesis/bracket/curly brace.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
/* Used to check if we have any errors during parsing this */
|
/* Used to check if we have any errors during parsing this */
|
||||||
unsigned PrevErrorCount = ErrorCount;
|
unsigned PrevErrorCount = ErrorCount;
|
||||||
|
@ -2181,7 +2281,7 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check a few pre-C99 things */
|
/* Check a few pre-C99 things */
|
||||||
if ((Spec->Flags & DS_DEF_TYPE) != 0) {
|
if (D->Ident[0] != '\0' && (Spec->Flags & DS_DEF_TYPE) != 0) {
|
||||||
/* Check and warn about an implicit int return in the function */
|
/* Check and warn about an implicit int return in the function */
|
||||||
if (IsTypeFunc (D->Type) && IsRankInt (GetFuncReturnType (D->Type))) {
|
if (IsTypeFunc (D->Type) && IsRankInt (GetFuncReturnType (D->Type))) {
|
||||||
/* Function has an implicit int return. Output a warning if we don't
|
/* Function has an implicit int return. Output a warning if we don't
|
||||||
|
@ -2193,7 +2293,7 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET;
|
GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For anthing that is not a function or typedef, check for an implicit
|
/* For anything that is not a function or typedef, check for an implicit
|
||||||
** int declaration.
|
** int declaration.
|
||||||
*/
|
*/
|
||||||
if ((D->StorageClass & SC_FUNC) != SC_FUNC &&
|
if ((D->StorageClass & SC_FUNC) != SC_FUNC &&
|
||||||
|
@ -2208,14 +2308,38 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PrevErrorCount != ErrorCount) {
|
if (PrevErrorCount != ErrorCount) {
|
||||||
/* Make the declaration fictitious if is is not parsed correctly */
|
if ((Spec->Flags & DS_DEF_TYPE) == 0 && Mode == DM_NEED_IDENT && D->Ident[0] == '\0') {
|
||||||
D->StorageClass |= SC_FICTITIOUS;
|
/* Make the declaration fictitious if is is not parsed correctly */
|
||||||
|
D->StorageClass |= SC_FICTITIOUS;
|
||||||
|
|
||||||
if (Mode == DM_NEED_IDENT && D->Ident[0] == '\0') {
|
|
||||||
/* Use a fictitious name for the identifier if it is missing */
|
/* Use a fictitious name for the identifier if it is missing */
|
||||||
AnonName (D->Ident, "global");
|
const char* Level = "";
|
||||||
|
|
||||||
|
switch (GetLexicalLevel ()) {
|
||||||
|
case LEX_LEVEL_GLOBAL:
|
||||||
|
Level = "global";
|
||||||
|
break;
|
||||||
|
case LEX_LEVEL_FUNCTION:
|
||||||
|
case LEX_LEVEL_BLOCK:
|
||||||
|
Level = "local";
|
||||||
|
break;
|
||||||
|
case LEX_LEVEL_STRUCT:
|
||||||
|
Level = "field";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Level = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
AnonName (D->Ident, Level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try some smart error recovery */
|
||||||
|
if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) {
|
||||||
|
return SmartErrorSkip ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,11 +98,26 @@ struct Declarator {
|
||||||
unsigned Index; /* Used to build Type */
|
unsigned Index; /* Used to build Type */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Modes for ParseDecl */
|
/* Modes for ParseDecl:
|
||||||
|
** - DM_NEED_IDENT means:
|
||||||
|
** we *must* have a type and a variable identifer.
|
||||||
|
** - DM_NO_IDENT means:
|
||||||
|
** we must have a type but no variable identifer
|
||||||
|
** (if there is one, it's not read).
|
||||||
|
** - DM_ACCEPT_IDENT means:
|
||||||
|
** we *may* have an identifier, or none. If it is the latter case,
|
||||||
|
** the type must be used as an empty declaration, or it is an error.
|
||||||
|
** Note: this is used for struct/union members.
|
||||||
|
** - DM_IGNORE_IDENT means:
|
||||||
|
** we *may* have an identifier. If there is an identifier,
|
||||||
|
** it is read, but it is no error, if there is none.
|
||||||
|
** Note: this is used for function parameter type lists.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DM_NEED_IDENT, /* We must have an identifier */
|
DM_NEED_IDENT,
|
||||||
DM_NO_IDENT, /* We won't read an identifier */
|
DM_NO_IDENT,
|
||||||
DM_ACCEPT_IDENT, /* We will accept an id if there is one */
|
DM_ACCEPT_IDENT,
|
||||||
|
DM_ACCEPT_PARAM_IDENT,
|
||||||
} declmode_t;
|
} declmode_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,11 +128,19 @@ typedef enum {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int SmartErrorSkip (void);
|
||||||
|
/* Try some smart error recovery. Skip tokens until either a comma or semicolon
|
||||||
|
** that is not enclosed in an open parenthesis/bracket/curly brace, or until an
|
||||||
|
** unpaired right parenthesis/bracket/curly brace is reached. Return 0 if it is
|
||||||
|
** the former case, or -1 if it is the latter case. */
|
||||||
|
|
||||||
Type* ParseType (Type* Type);
|
Type* ParseType (Type* Type);
|
||||||
/* Parse a complete type specification */
|
/* Parse a complete type specification */
|
||||||
|
|
||||||
void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode);
|
int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode);
|
||||||
/* Parse a variable, type or function declarator */
|
/* Parse a variable, type or function declarator. Return -1 if this stops at
|
||||||
|
** an unpaired right parenthesis/bracket/curly brace.
|
||||||
|
*/
|
||||||
|
|
||||||
void ParseDeclSpec (DeclSpec* Spec, typespec_t TSFlags, unsigned DefStorage);
|
void ParseDeclSpec (DeclSpec* Spec, typespec_t TSFlags, unsigned DefStorage);
|
||||||
/* Parse a declaration specification */
|
/* Parse a declaration specification */
|
||||||
|
|
|
@ -61,6 +61,8 @@
|
||||||
/* Count of errors/warnings */
|
/* Count of errors/warnings */
|
||||||
unsigned ErrorCount = 0;
|
unsigned ErrorCount = 0;
|
||||||
unsigned WarningCount = 0;
|
unsigned WarningCount = 0;
|
||||||
|
unsigned RecentLineNo = 0;
|
||||||
|
unsigned RecentErrorCount = 0;
|
||||||
|
|
||||||
/* Warning and error options */
|
/* Warning and error options */
|
||||||
IntStack WarnEnable = INTSTACK(1); /* Enable warnings */
|
IntStack WarnEnable = INTSTACK(1); /* Enable warnings */
|
||||||
|
@ -205,8 +207,16 @@ static void IntError (const char* Filename, unsigned LineNo, const char* Msg, va
|
||||||
if (Line) {
|
if (Line) {
|
||||||
Print (stderr, 1, "Input: %.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
|
Print (stderr, 1, "Input: %.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
|
||||||
}
|
}
|
||||||
|
|
||||||
++ErrorCount;
|
++ErrorCount;
|
||||||
if (ErrorCount > 20) {
|
if (RecentLineNo != LineNo) {
|
||||||
|
RecentLineNo = LineNo;
|
||||||
|
RecentErrorCount = 0;
|
||||||
|
} else {
|
||||||
|
++RecentErrorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RecentErrorCount > 20 || ErrorCount > 200) {
|
||||||
Fatal ("Too many errors");
|
Fatal ("Too many errors");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1322,10 +1322,10 @@ static void Primary (ExprDesc* E)
|
||||||
E->Name = (uintptr_t) Sym->Name;
|
E->Name = (uintptr_t) Sym->Name;
|
||||||
} else {
|
} else {
|
||||||
/* Undeclared Variable */
|
/* Undeclared Variable */
|
||||||
|
Error ("Undeclared identifier '%s'", Ident);
|
||||||
Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
|
Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
|
||||||
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
||||||
E->Type = type_int;
|
E->Type = type_int;
|
||||||
Error ("Undefined symbol: '%s'", Ident);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1493,7 +1493,7 @@ void MakeZPSym (const char* Name)
|
||||||
if (Entry) {
|
if (Entry) {
|
||||||
Entry->Flags |= SC_ZEROPAGE;
|
Entry->Flags |= SC_ZEROPAGE;
|
||||||
} else {
|
} else {
|
||||||
Error ("Undefined symbol: '%s'", Name);
|
Error ("Undeclared symbol: '%s'", Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
bug1889-missing-identifier.c:3: Error: Identifier expected
|
bug1889-missing-identifier.c:3: Error: Identifier expected
|
||||||
bug1889-missing-identifier.c:3: Error: ';' expected
|
bug1889-missing-identifier.c:3: Error: ';' expected
|
||||||
bug1889-missing-identifier.c:3: Warning: Implicit 'int' is an obsolete feature
|
|
||||||
bug1889-missing-identifier.c:4: Error: Identifier expected
|
bug1889-missing-identifier.c:4: Error: Identifier expected
|
||||||
bug1889-missing-identifier.c:4: Warning: Implicit 'int' is an obsolete feature
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
custom-reference-error.c:18: Error: Call to undeclared function 'printf'
|
custom-reference-error.c:18: Error: Call to undeclared function 'printf'
|
||||||
custom-reference-error.c:19: Error: Undefined symbol: 'n'
|
custom-reference-error.c:19: Error: Undeclared identifier 'n'
|
||||||
custom-reference-error.c:21: Warning: Control reaches end of non-void function [-Wreturn-type]
|
custom-reference-error.c:21: Warning: Control reaches end of non-void function [-Wreturn-type]
|
||||||
custom-reference-error.c:21: Warning: Parameter 'argc' is never used
|
custom-reference-error.c:21: Warning: Parameter 'argc' is never used
|
||||||
custom-reference-error.c:21: Warning: Parameter 'argv' is never used
|
custom-reference-error.c:21: Warning: Parameter 'argv' is never used
|
||||||
|
|
Loading…
Reference in New Issue
Block a user