mirror of
https://github.com/cc65/cc65.git
synced 2024-09-28 10:55:43 +00:00
Fixed and improved diagnostics about declaration errors.
This commit is contained in:
parent
79214530e0
commit
ac04394254
@ -1766,7 +1766,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,
|
||||||
@ -1886,7 +1886,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
|
||||||
@ -1903,61 +1903,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;
|
||||||
|
}
|
||||||
|
Mode = DirectDecl (Spec, D, Mode);
|
||||||
|
ConsumeRParen ();
|
||||||
} else if (CurTok.Tok == TOK_IDENT) {
|
} else if (CurTok.Tok == TOK_IDENT) {
|
||||||
strcpy (D->Ident, CurTok.Ident);
|
strcpy (D->Ident, CurTok.Ident);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else {
|
} else {
|
||||||
if (Mode == DM_NEED_IDENT) {
|
|
||||||
/* Some fix point tokens that are used for error recovery */
|
|
||||||
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI, TOK_LCURLY, TOK_RCURLY };
|
|
||||||
|
|
||||||
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';
|
D->Ident[0] = '\0';
|
||||||
|
if (Mode == DM_NEED_IDENT) {
|
||||||
|
Error ("Identifier expected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 */
|
||||||
@ -2043,6 +2031,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2154,12 +2144,44 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (PrevErrorCount != ErrorCount) {
|
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') {
|
||||||
/* Make the declaration fictitious if is is not parsed correctly */
|
/* Make the declaration fictitious if is is not parsed correctly */
|
||||||
D->StorageClass |= SC_FICTITIOUS;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user