mirror of
https://github.com/cc65/cc65.git
synced 2024-12-27 15:29:46 +00:00
Improved error recovery with function declarations.
Fixed some rare cases when a single file-scope error could get reapeated endlessly until the maximum total count of errors allowed is reached.
This commit is contained in:
parent
ac04394254
commit
7574e36e95
@ -94,6 +94,8 @@ static void Parse (void)
|
||||
while (CurTok.Tok != TOK_CEOF) {
|
||||
|
||||
DeclSpec Spec;
|
||||
int NeedClean = 0;
|
||||
unsigned PrevErrorCount = ErrorCount;
|
||||
|
||||
/* Check for empty statements */
|
||||
if (CurTok.Tok == TOK_SEMI) {
|
||||
@ -144,7 +146,11 @@ static void Parse (void)
|
||||
Declarator Decl;
|
||||
|
||||
/* 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,
|
||||
**
|
||||
@ -310,6 +316,7 @@ static void Parse (void)
|
||||
|
||||
}
|
||||
|
||||
NextDecl:
|
||||
/* Check for end of declaration list */
|
||||
if (CurTok.Tok == TOK_COMMA) {
|
||||
NextToken ();
|
||||
@ -325,6 +332,7 @@ static void Parse (void)
|
||||
/* Function */
|
||||
if (CurTok.Tok == TOK_SEMI) {
|
||||
/* Prototype only */
|
||||
NeedClean = 0;
|
||||
NextToken ();
|
||||
} else if (CurTok.Tok == TOK_LCURLY) {
|
||||
/* ISO C: The type category in a function definition cannot be
|
||||
@ -337,6 +345,7 @@ static void Parse (void)
|
||||
}
|
||||
|
||||
/* Parse the function body anyways */
|
||||
NeedClean = 0;
|
||||
NewFunc (Sym, FuncDef);
|
||||
|
||||
/* Make sure we aren't omitting any work */
|
||||
@ -345,10 +354,27 @@ static void Parse (void)
|
||||
|
||||
} else {
|
||||
|
||||
/* Must be followed by a semicolon */
|
||||
ConsumeSemi ();
|
||||
if (Sym) {
|
||||
/* 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 */
|
||||
|
@ -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)
|
||||
/* Parse and return a storage class specifier */
|
||||
{
|
||||
@ -1537,6 +1635,12 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||
*SignednessSpecified = 1;
|
||||
}
|
||||
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 {
|
||||
/* This is a label. Use the default type flag to end the loop
|
||||
@ -1618,14 +1722,13 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
||||
NextToken ();
|
||||
|
||||
} 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 */
|
||||
Error ("Identifier expected for parameter name");
|
||||
|
||||
/* Try some smart error recovery */
|
||||
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
|
||||
if (SmartErrorSkip () < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for more parameters */
|
||||
@ -1711,12 +1814,9 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
||||
ConsumeSemi ();
|
||||
}
|
||||
|
||||
if (PrevErrorCount != ErrorCount) {
|
||||
/* Some fix point tokens that are used for error recovery */
|
||||
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI };
|
||||
|
||||
if (PrevErrorCount != ErrorCount && CurTok.Tok != TOK_LCURLY) {
|
||||
/* Try some smart error recovery */
|
||||
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
|
||||
SmartErrorSkip ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1731,6 +1831,7 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||
DeclSpec Spec;
|
||||
Declarator Decl;
|
||||
SymEntry* Param;
|
||||
unsigned PrevErrorCount = ErrorCount;
|
||||
|
||||
/* Allow an ellipsis as last parameter */
|
||||
if (CurTok.Tok == TOK_ELLIPSIS) {
|
||||
@ -1798,6 +1899,13 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||
/* Count arguments */
|
||||
++F->ParamCount;
|
||||
|
||||
if (PrevErrorCount != ErrorCount) {
|
||||
/* Try some smart error recovery */
|
||||
if (SmartErrorSkip () < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for more parameters */
|
||||
if (CurTok.Tok == TOK_COMMA) {
|
||||
NextToken ();
|
||||
@ -2065,8 +2173,10 @@ Type* ParseType (Type* T)
|
||||
|
||||
|
||||
|
||||
void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||
/* Parse a variable, type or function declarator */
|
||||
int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||
/* 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 */
|
||||
unsigned PrevErrorCount = ErrorCount;
|
||||
@ -2117,7 +2227,7 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (IsTypeFunc (D->Type) && IsRankInt (GetFuncReturnType (D->Type))) {
|
||||
/* Function has an implicit int return. Output a warning if we don't
|
||||
@ -2129,7 +2239,7 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||
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.
|
||||
*/
|
||||
if ((D->StorageClass & SC_FUNC) != SC_FUNC &&
|
||||
@ -2144,22 +2254,7 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||
}
|
||||
|
||||
if (PrevErrorCount != ErrorCount) {
|
||||
/* Some fix point tokens that are used for error recovery */
|
||||
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI, TOK_LCURLY, TOK_RCURLY };
|
||||
|
||||
/* 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 ();
|
||||
}
|
||||
|
||||
if (Mode == DM_NEED_IDENT && D->Ident[0] == '\0') {
|
||||
if ((Spec->Flags & DS_DEF_TYPE) == 0 && Mode == DM_NEED_IDENT && D->Ident[0] == '\0') {
|
||||
/* Make the declaration fictitious if is is not parsed correctly */
|
||||
D->StorageClass |= SC_FICTITIOUS;
|
||||
|
||||
@ -2183,7 +2278,14 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||
}
|
||||
AnonName (D->Ident, Level);
|
||||
}
|
||||
|
||||
/* Try some smart error recovery */
|
||||
if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) {
|
||||
return SmartErrorSkip ();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -128,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);
|
||||
/* Parse a complete type specification */
|
||||
|
||||
void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode);
|
||||
/* Parse a variable, type or function declarator */
|
||||
int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode);
|
||||
/* 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);
|
||||
/* Parse a declaration specification */
|
||||
|
@ -1,5 +1,3 @@
|
||||
bug1889-missing-identifier.c:3: Error: Identifier 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: Warning: Implicit 'int' is an obsolete feature
|
||||
|
Loading…
Reference in New Issue
Block a user