mirror of
https://github.com/cc65/cc65.git
synced 2024-06-30 01:29:37 +00:00
Merge branch 'master' into fptest
This commit is contained in:
commit
55b504652e
|
@ -79,7 +79,6 @@
|
||||||
static void Parse (void)
|
static void Parse (void)
|
||||||
/* Top level parser routine. */
|
/* Top level parser routine. */
|
||||||
{
|
{
|
||||||
int comma;
|
|
||||||
SymEntry* Sym;
|
SymEntry* Sym;
|
||||||
FuncDesc* FuncDef = 0;
|
FuncDesc* FuncDef = 0;
|
||||||
|
|
||||||
|
@ -89,16 +88,18 @@ static void Parse (void)
|
||||||
/* Fill up the next token with a bogus semicolon and start the tokenizer */
|
/* Fill up the next token with a bogus semicolon and start the tokenizer */
|
||||||
NextTok.Tok = TOK_SEMI;
|
NextTok.Tok = TOK_SEMI;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
/* Parse until end of input */
|
/* Parse until end of input */
|
||||||
while (CurTok.Tok != TOK_CEOF) {
|
while (CurTok.Tok != TOK_CEOF) {
|
||||||
|
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
|
int Comma;
|
||||||
int NeedClean = 0;
|
int NeedClean = 0;
|
||||||
unsigned PrevErrorCount = ErrorCount;
|
|
||||||
|
|
||||||
/* Check for empty statements */
|
/* Check for empty statements */
|
||||||
if (CurTok.Tok == TOK_SEMI) {
|
if (CurTok.Tok == TOK_SEMI) {
|
||||||
|
/* TODO: warn on this if we have a pedantic mode */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +120,7 @@ static void Parse (void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read variable defs and functions */
|
/* Read the declaration specifier */
|
||||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_EXTERN | SC_STATIC);
|
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_EXTERN | SC_STATIC);
|
||||||
|
|
||||||
/* Don't accept illegal storage classes */
|
/* Don't accept illegal storage classes */
|
||||||
|
@ -138,18 +139,30 @@ static void Parse (void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we haven't got a type specifier yet, something must be wrong */
|
||||||
|
if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||||
|
/* Avoid extra errors if it was a failed type specifier */
|
||||||
|
if ((Spec.Flags & DS_EXTRA_TYPE) == 0) {
|
||||||
|
Error ("Declaration specifier expected");
|
||||||
|
}
|
||||||
|
NeedClean = -1;
|
||||||
|
goto EndOfDecl;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read declarations for this type */
|
/* Read declarations for this type */
|
||||||
Sym = 0;
|
Comma = 0;
|
||||||
comma = 0;
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
Declarator Decl;
|
Declarator Decl;
|
||||||
|
|
||||||
|
Sym = 0;
|
||||||
|
|
||||||
/* Read the next declaration */
|
/* Read the next declaration */
|
||||||
NeedClean = ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
|
NeedClean = ParseDecl (&Spec, &Decl, DM_IDENT_OR_EMPTY);
|
||||||
if (Decl.Ident[0] == '\0') {
|
|
||||||
Sym = 0;
|
/* Bail out if there are errors */
|
||||||
goto NextDecl;
|
if (NeedClean <= 0) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we must reserve storage for the variable. We do this,
|
/* Check if we must reserve storage for the variable. We do this,
|
||||||
|
@ -191,10 +204,6 @@ static void Parse (void)
|
||||||
FuncDef->Flags = (FuncDef->Flags & ~FD_EMPTY) | FD_VOID_PARAM;
|
FuncDef->Flags = (FuncDef->Flags & ~FD_EMPTY) | FD_VOID_PARAM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (CurTok.Tok != TOK_COMMA && CurTok.Tok != TOK_SEMI) {
|
|
||||||
Error ("Expected ',' or ';' after top level declarator");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Just a declaration */
|
/* Just a declaration */
|
||||||
Decl.StorageClass |= SC_DECL;
|
Decl.StorageClass |= SC_DECL;
|
||||||
}
|
}
|
||||||
|
@ -317,50 +326,50 @@ 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 ();
|
|
||||||
comma = 1;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Comma = 1;
|
||||||
|
Spec.Flags |= DS_NO_EMPTY_DECL;
|
||||||
|
NextToken ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finish the declaration */
|
/* Finish the declaration */
|
||||||
if (Sym) {
|
if (Sym && IsTypeFunc (Sym->Type) && CurTok.Tok == TOK_LCURLY) {
|
||||||
/* Function definition? */
|
/* A function definition is not terminated with a semicolon */
|
||||||
if (IsTypeFunc (Sym->Type) && CurTok.Tok == TOK_LCURLY) {
|
if (IsTypeFunc (Spec.Type) && TypeCmp (Sym->Type, Spec.Type).C >= TC_EQUAL) {
|
||||||
if (IsTypeFunc (Spec.Type) && TypeCmp (Sym->Type, Spec.Type).C >= TC_EQUAL) {
|
/* ISO C: The type category in a function definition cannot be
|
||||||
/* ISO C: The type category in a function definition cannot be
|
** inherited from a typedef.
|
||||||
** inherited from a typedef.
|
*/
|
||||||
*/
|
Error ("Function cannot be defined with a typedef");
|
||||||
Error ("Function cannot be defined with a typedef");
|
} else if (Comma) {
|
||||||
} else if (comma) {
|
/* ISO C: A function definition cannot shall its return type
|
||||||
/* ISO C: A function definition cannot shall its return type
|
** specifier with other declarators.
|
||||||
** specifier with other declarators.
|
*/
|
||||||
*/
|
Error ("';' expected after top level declarator");
|
||||||
Error ("';' expected after top level declarator");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse the function body anyways */
|
/* Parse the function body anyways */
|
||||||
NeedClean = 0;
|
NeedClean = 0;
|
||||||
NewFunc (Sym, FuncDef);
|
NewFunc (Sym, FuncDef);
|
||||||
|
|
||||||
/* Make sure we aren't omitting any work */
|
/* Make sure we aren't omitting any work */
|
||||||
CheckDeferredOpAllDone ();
|
CheckDeferredOpAllDone ();
|
||||||
|
} else if (NeedClean > 0) {
|
||||||
|
/* Must be followed by a semicolon */
|
||||||
|
if (CurTok.Tok != TOK_SEMI) {
|
||||||
|
Error ("',' or ';' expected after top level declarator");
|
||||||
|
NeedClean = -1;
|
||||||
} else {
|
} else {
|
||||||
/* Must be followed by a semicolon */
|
NextToken ();
|
||||||
if (ConsumeSemi ()) {
|
NeedClean = 0;
|
||||||
NeedClean = 0;
|
|
||||||
} else {
|
|
||||||
NeedClean = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EndOfDecl:
|
||||||
/* Try some smart error recovery */
|
/* Try some smart error recovery */
|
||||||
if (PrevErrorCount != ErrorCount && NeedClean < 0) {
|
if (NeedClean < 0) {
|
||||||
SmartErrorSkip (1);
|
SmartErrorSkip (1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSpecified);
|
static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags);
|
||||||
/* Parse a type specifier */
|
/* Parse a type specifier */
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,125 +83,6 @@ 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 (int WholeDecl)
|
|
||||||
/* Try some smart error recovery.
|
|
||||||
**
|
|
||||||
** - If WholeDecl is 0:
|
|
||||||
** Skip tokens until a comma or closing curly brace that is not enclosed in
|
|
||||||
** an open parenthesis/bracket/curly brace, or until a semicolon, EOF or
|
|
||||||
** unpaired right parenthesis/bracket/curly brace is reached.
|
|
||||||
**
|
|
||||||
** - If WholeDecl is non-0:
|
|
||||||
** Skip tokens until a closing curly brace that is not enclosed in an open
|
|
||||||
** parenthesis/bracket/curly brace, or until a semicolon or EOF is reached.
|
|
||||||
**
|
|
||||||
** Return 0 if this exits as soon as it reaches an EOF. Return 0 as well if
|
|
||||||
** this exits with no open parentheses/brackets/curly braces. Otherwise, return
|
|
||||||
** -1.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
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) < 0) {
|
|
||||||
if (!WholeDecl) {
|
|
||||||
Res = -1;
|
|
||||||
goto ExitPoint;
|
|
||||||
}
|
|
||||||
NextToken ();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_RCURLY:
|
|
||||||
if (CloseBrace (&C, CurTok.Tok) < 0) {
|
|
||||||
if (!WholeDecl) {
|
|
||||||
Res = -1;
|
|
||||||
goto ExitPoint;
|
|
||||||
}
|
|
||||||
NextToken ();
|
|
||||||
} else if (CollCount (&C) == 0) {
|
|
||||||
goto ExitPoint;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_COMMA:
|
|
||||||
if (CollCount (&C) == 0 && !WholeDecl) {
|
|
||||||
goto ExitPoint;
|
|
||||||
}
|
|
||||||
NextToken ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_SEMI:
|
|
||||||
if (CollCount (&C) != 0) {
|
|
||||||
Res = -1;
|
|
||||||
}
|
|
||||||
goto ExitPoint;
|
|
||||||
|
|
||||||
case TOK_CEOF:
|
|
||||||
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 */
|
||||||
{
|
{
|
||||||
|
@ -451,20 +332,36 @@ static void OptionalInt (void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void OptionalSigned (int* SignednessSpecified)
|
static void OptionalSigned (DeclSpec* Spec)
|
||||||
/* Eat an optional "signed" token */
|
/* Eat an optional "signed" token */
|
||||||
{
|
{
|
||||||
if (CurTok.Tok == TOK_SIGNED) {
|
if (CurTok.Tok == TOK_SIGNED) {
|
||||||
/* Skip it */
|
/* Skip it */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (SignednessSpecified != NULL) {
|
if (Spec != NULL) {
|
||||||
*SignednessSpecified = 1;
|
Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void UseDefaultType (DeclSpec* Spec, typespec_t TSFlags)
|
||||||
|
/* Use the default type for the type specifier */
|
||||||
|
{
|
||||||
|
if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) {
|
||||||
|
Spec->Flags = (Spec->Flags & ~DS_TYPE_MASK) | DS_NONE;
|
||||||
|
Spec->Type[0].C = T_INT;
|
||||||
|
Spec->Type[1].C = T_END;
|
||||||
|
} else {
|
||||||
|
Spec->Flags = (Spec->Flags & ~DS_TYPE_MASK) | DS_DEF_TYPE;
|
||||||
|
Spec->Type[0].C = T_INT;
|
||||||
|
Spec->Type[1].C = T_END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void InitDeclSpec (DeclSpec* Spec)
|
static void InitDeclSpec (DeclSpec* Spec)
|
||||||
/* Initialize the DeclSpec struct for use */
|
/* Initialize the DeclSpec struct for use */
|
||||||
{
|
{
|
||||||
|
@ -1080,9 +977,15 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
|
|
||||||
/* Get the type of the entry */
|
/* Get the type of the entry */
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
int SignednessSpecified = 0;
|
|
||||||
int NeedClean = 0;
|
int NeedClean = 0;
|
||||||
|
|
||||||
|
/* Check for extra semicolons */
|
||||||
|
if (CurTok.Tok == TOK_SEMI) {
|
||||||
|
/* TODO: warn on this if we have a pedantic mode */
|
||||||
|
NextToken ();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for a _Static_assert */
|
/* Check for a _Static_assert */
|
||||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||||
ParseStaticAssert ();
|
ParseStaticAssert ();
|
||||||
|
@ -1090,7 +993,27 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
InitDeclSpec (&Spec);
|
InitDeclSpec (&Spec);
|
||||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, &SignednessSpecified);
|
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE);
|
||||||
|
|
||||||
|
/* Check if this is only a type declaration */
|
||||||
|
if (CurTok.Tok == TOK_SEMI && (Spec.Flags & DS_EXTRA_TYPE) == 0) {
|
||||||
|
CheckEmptyDecl (&Spec);
|
||||||
|
NextToken ();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we haven't got a type specifier yet, something must be wrong */
|
||||||
|
if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||||
|
/* Avoid extra errors if it was a failed type specifier */
|
||||||
|
if ((Spec.Flags & DS_EXTRA_TYPE) == 0) {
|
||||||
|
Error ("Declaration specifier expected");
|
||||||
|
}
|
||||||
|
NeedClean = -1;
|
||||||
|
goto EndOfDecl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow anonymous bit-fields */
|
||||||
|
Spec.Flags |= DS_ALLOW_BITFIELD;
|
||||||
|
|
||||||
/* Read fields with this type */
|
/* Read fields with this type */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -1098,7 +1021,12 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
Declarator Decl;
|
Declarator Decl;
|
||||||
|
|
||||||
/* Get type and name of the struct field */
|
/* Get type and name of the struct field */
|
||||||
NeedClean = ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
|
NeedClean = ParseDecl (&Spec, &Decl, DM_IDENT_OR_EMPTY);
|
||||||
|
|
||||||
|
/* Bail out if there are errors */
|
||||||
|
if (NeedClean <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for a bit-field declaration */
|
/* Check for a bit-field declaration */
|
||||||
FieldWidth = ParseFieldWidth (&Decl);
|
FieldWidth = ParseFieldWidth (&Decl);
|
||||||
|
@ -1123,9 +1051,7 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
Decl.Type[0].C &= ~T_QUAL_CVR;
|
Decl.Type[0].C &= ~T_QUAL_CVR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* A non bit-field without a name is legal but useless */
|
/* Invalid member */
|
||||||
Warning ("Declaration does not declare anything");
|
|
||||||
|
|
||||||
goto NextMember;
|
goto NextMember;
|
||||||
}
|
}
|
||||||
} else if (FieldWidth > 0) {
|
} else if (FieldWidth > 0) {
|
||||||
|
@ -1160,7 +1086,7 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
** bit-field.
|
** bit-field.
|
||||||
*/
|
*/
|
||||||
AddBitField (Decl.Ident, Decl.Type, 0, 0, FieldWidth,
|
AddBitField (Decl.Ident, Decl.Type, 0, 0, FieldWidth,
|
||||||
SignednessSpecified);
|
(Spec.Flags & DS_EXPLICIT_SIGNEDNESS) != 0);
|
||||||
} else if (Decl.Ident[0] != '\0') {
|
} else if (Decl.Ident[0] != '\0') {
|
||||||
/* Add the new field to the table */
|
/* Add the new field to the table */
|
||||||
Field = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
Field = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
||||||
|
@ -1189,17 +1115,23 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NextMember: if (CurTok.Tok != TOK_COMMA) {
|
NextMember:
|
||||||
|
/* Check for end of declaration list */
|
||||||
|
if (CurTok.Tok != TOK_COMMA) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Spec.Flags |= DS_NO_EMPTY_DECL;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be followed by a semicolon */
|
EndOfDecl:
|
||||||
if (NeedClean >= 0 && ConsumeSemi ()) {
|
if (NeedClean > 0) {
|
||||||
NeedClean = 0;
|
/* Must be followed by a semicolon */
|
||||||
} else {
|
if (ConsumeSemi ()) {
|
||||||
NeedClean = -1;
|
NeedClean = 0;
|
||||||
|
} else {
|
||||||
|
NeedClean = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try some smart error recovery */
|
/* Try some smart error recovery */
|
||||||
|
@ -1265,9 +1197,15 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||||
|
|
||||||
/* Get the type of the entry */
|
/* Get the type of the entry */
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
int SignednessSpecified = 0;
|
|
||||||
int NeedClean = 0;
|
int NeedClean = 0;
|
||||||
|
|
||||||
|
/* Check for extra semicolons */
|
||||||
|
if (CurTok.Tok == TOK_SEMI) {
|
||||||
|
/* TODO: warn on this if we have a pedantic mode */
|
||||||
|
NextToken ();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for a _Static_assert */
|
/* Check for a _Static_assert */
|
||||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||||
ParseStaticAssert ();
|
ParseStaticAssert ();
|
||||||
|
@ -1275,7 +1213,27 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
InitDeclSpec (&Spec);
|
InitDeclSpec (&Spec);
|
||||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, &SignednessSpecified);
|
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE);
|
||||||
|
|
||||||
|
/* Check if this is only a type declaration */
|
||||||
|
if (CurTok.Tok == TOK_SEMI && (Spec.Flags & DS_EXTRA_TYPE) == 0) {
|
||||||
|
CheckEmptyDecl (&Spec);
|
||||||
|
NextToken ();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we haven't got a type specifier yet, something must be wrong */
|
||||||
|
if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||||
|
/* Avoid extra errors if it was a failed type specifier */
|
||||||
|
if ((Spec.Flags & DS_EXTRA_TYPE) == 0) {
|
||||||
|
Error ("Declaration specifier expected");
|
||||||
|
}
|
||||||
|
NeedClean = -1;
|
||||||
|
goto EndOfDecl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow anonymous bit-fields */
|
||||||
|
Spec.Flags |= DS_ALLOW_BITFIELD;
|
||||||
|
|
||||||
/* Read fields with this type */
|
/* Read fields with this type */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -1291,7 +1249,12 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get type and name of the struct field */
|
/* Get type and name of the struct field */
|
||||||
NeedClean = ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
|
NeedClean = ParseDecl (&Spec, &Decl, DM_IDENT_OR_EMPTY);
|
||||||
|
|
||||||
|
/* Bail out if there are errors */
|
||||||
|
if (NeedClean <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for a bit-field declaration */
|
/* Check for a bit-field declaration */
|
||||||
FieldWidth = ParseFieldWidth (&Decl);
|
FieldWidth = ParseFieldWidth (&Decl);
|
||||||
|
@ -1335,9 +1298,7 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||||
Decl.Type[0].C &= ~T_QUAL_CVR;
|
Decl.Type[0].C &= ~T_QUAL_CVR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* A non bit-field without a name is legal but useless */
|
/* Invalid member */
|
||||||
Warning ("Declaration does not declare anything");
|
|
||||||
|
|
||||||
goto NextMember;
|
goto NextMember;
|
||||||
}
|
}
|
||||||
} else if (FieldWidth > 0) {
|
} else if (FieldWidth > 0) {
|
||||||
|
@ -1387,8 +1348,8 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||||
** bit-field as a char type in expressions.
|
** bit-field as a char type in expressions.
|
||||||
*/
|
*/
|
||||||
CHECK (BitOffs < CHAR_BITS);
|
CHECK (BitOffs < CHAR_BITS);
|
||||||
AddBitField (Decl.Ident, Decl.Type, StructSize, BitOffs,
|
AddBitField (Decl.Ident, Decl.Type, StructSize, BitOffs, FieldWidth,
|
||||||
FieldWidth, SignednessSpecified);
|
(Spec.Flags & DS_EXPLICIT_SIGNEDNESS) != 0);
|
||||||
BitOffs += FieldWidth;
|
BitOffs += FieldWidth;
|
||||||
CHECK (BitOffs <= CHAR_BITS * SizeOf (Decl.Type));
|
CHECK (BitOffs <= CHAR_BITS * SizeOf (Decl.Type));
|
||||||
/* Add any full bytes to the struct size */
|
/* Add any full bytes to the struct size */
|
||||||
|
@ -1427,17 +1388,23 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NextMember: if (CurTok.Tok != TOK_COMMA) {
|
NextMember:
|
||||||
|
/* Check for end of declaration list */
|
||||||
|
if (CurTok.Tok != TOK_COMMA) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Spec.Flags |= DS_NO_EMPTY_DECL;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be followed by a semicolon */
|
EndOfDecl:
|
||||||
if (NeedClean >= 0 && ConsumeSemi ()) {
|
if (NeedClean > 0) {
|
||||||
NeedClean = 0;
|
/* Must be followed by a semicolon */
|
||||||
} else {
|
if (ConsumeSemi ()) {
|
||||||
NeedClean = -1;
|
NeedClean = 0;
|
||||||
|
} else {
|
||||||
|
NeedClean = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try some smart error recovery */
|
/* Try some smart error recovery */
|
||||||
|
@ -1472,7 +1439,7 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSpecified)
|
static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags)
|
||||||
/* Parse a type specifier. Store whether one of "signed" or "unsigned" was
|
/* Parse a type specifier. Store whether one of "signed" or "unsigned" was
|
||||||
** specified, so bit-fields of unspecified signedness can be treated as
|
** specified, so bit-fields of unspecified signedness can be treated as
|
||||||
** unsigned; without special handling, it would be treated as signed.
|
** unsigned; without special handling, it would be treated as signed.
|
||||||
|
@ -1482,12 +1449,8 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
SymEntry* TagEntry;
|
SymEntry* TagEntry;
|
||||||
TypeCode Qualifiers = T_QUAL_NONE;
|
TypeCode Qualifiers = T_QUAL_NONE;
|
||||||
|
|
||||||
if (SignednessSpecified != NULL) {
|
/* Assume we have an explicitly specified type */
|
||||||
*SignednessSpecified = 0;
|
Spec->Flags = (Spec->Flags & ~DS_TYPE_MASK) | DS_EXPLICIT_TYPE;
|
||||||
}
|
|
||||||
|
|
||||||
/* Assume we have an explicit type */
|
|
||||||
Spec->Flags &= ~DS_DEF_TYPE;
|
|
||||||
|
|
||||||
/* Read storage specifiers and/or type qualifiers if we have any */
|
/* Read storage specifiers and/or type qualifiers if we have any */
|
||||||
OptionalSpecifiers (Spec, &Qualifiers, TSFlags);
|
OptionalSpecifiers (Spec, &Qualifiers, TSFlags);
|
||||||
|
@ -1511,15 +1474,13 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
case TOK_LONG:
|
case TOK_LONG:
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (CurTok.Tok == TOK_UNSIGNED) {
|
if (CurTok.Tok == TOK_UNSIGNED) {
|
||||||
if (SignednessSpecified != NULL) {
|
Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
|
||||||
*SignednessSpecified = 1;
|
|
||||||
}
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
OptionalInt ();
|
OptionalInt ();
|
||||||
Spec->Type[0].C = T_ULONG;
|
Spec->Type[0].C = T_ULONG;
|
||||||
Spec->Type[1].C = T_END;
|
Spec->Type[1].C = T_END;
|
||||||
} else {
|
} else {
|
||||||
OptionalSigned (SignednessSpecified);
|
OptionalSigned (Spec);
|
||||||
OptionalInt ();
|
OptionalInt ();
|
||||||
Spec->Type[0].C = T_LONG;
|
Spec->Type[0].C = T_LONG;
|
||||||
Spec->Type[1].C = T_END;
|
Spec->Type[1].C = T_END;
|
||||||
|
@ -1529,15 +1490,13 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
case TOK_SHORT:
|
case TOK_SHORT:
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (CurTok.Tok == TOK_UNSIGNED) {
|
if (CurTok.Tok == TOK_UNSIGNED) {
|
||||||
if (SignednessSpecified != NULL) {
|
Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
|
||||||
*SignednessSpecified = 1;
|
|
||||||
}
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
OptionalInt ();
|
OptionalInt ();
|
||||||
Spec->Type[0].C = T_USHORT;
|
Spec->Type[0].C = T_USHORT;
|
||||||
Spec->Type[1].C = T_END;
|
Spec->Type[1].C = T_END;
|
||||||
} else {
|
} else {
|
||||||
OptionalSigned (SignednessSpecified);
|
OptionalSigned (Spec);
|
||||||
OptionalInt ();
|
OptionalInt ();
|
||||||
Spec->Type[0].C = T_SHORT;
|
Spec->Type[0].C = T_SHORT;
|
||||||
Spec->Type[1].C = T_END;
|
Spec->Type[1].C = T_END;
|
||||||
|
@ -1550,10 +1509,8 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
Spec->Type[1].C = T_END;
|
Spec->Type[1].C = T_END;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_SIGNED:
|
case TOK_SIGNED:
|
||||||
if (SignednessSpecified != NULL) {
|
Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
|
||||||
*SignednessSpecified = 1;
|
|
||||||
}
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
switch (CurTok.Tok) {
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
|
@ -1589,9 +1546,7 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_UNSIGNED:
|
case TOK_UNSIGNED:
|
||||||
if (SignednessSpecified != NULL) {
|
Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
|
||||||
*SignednessSpecified = 1;
|
|
||||||
}
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
switch (CurTok.Tok) {
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
|
@ -1640,15 +1595,19 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
|
|
||||||
case TOK_UNION:
|
case TOK_UNION:
|
||||||
NextToken ();
|
NextToken ();
|
||||||
/* */
|
/* Remember we have an extra type decl */
|
||||||
|
Spec->Flags |= DS_EXTRA_TYPE;
|
||||||
|
/* Check for tag name */
|
||||||
if (CurTok.Tok == TOK_IDENT) {
|
if (CurTok.Tok == TOK_IDENT) {
|
||||||
strcpy (Ident, CurTok.Ident);
|
strcpy (Ident, CurTok.Ident);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else {
|
} else if (CurTok.Tok == TOK_LCURLY) {
|
||||||
AnonName (Ident, "union");
|
AnonName (Ident, "union");
|
||||||
|
} else {
|
||||||
|
Error ("Tag name identifier or '{' expected");
|
||||||
|
UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* Remember we have an extra type decl */
|
|
||||||
Spec->Flags |= DS_EXTRA_TYPE;
|
|
||||||
/* Declare the union in the current scope */
|
/* Declare the union in the current scope */
|
||||||
TagEntry = ParseUnionSpec (Ident, &Spec->Flags);
|
TagEntry = ParseUnionSpec (Ident, &Spec->Flags);
|
||||||
/* Encode the union entry into the type */
|
/* Encode the union entry into the type */
|
||||||
|
@ -1659,15 +1618,19 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
|
|
||||||
case TOK_STRUCT:
|
case TOK_STRUCT:
|
||||||
NextToken ();
|
NextToken ();
|
||||||
/* */
|
/* Remember we have an extra type decl */
|
||||||
|
Spec->Flags |= DS_EXTRA_TYPE;
|
||||||
|
/* Check for tag name */
|
||||||
if (CurTok.Tok == TOK_IDENT) {
|
if (CurTok.Tok == TOK_IDENT) {
|
||||||
strcpy (Ident, CurTok.Ident);
|
strcpy (Ident, CurTok.Ident);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else {
|
} else if (CurTok.Tok == TOK_LCURLY) {
|
||||||
AnonName (Ident, "struct");
|
AnonName (Ident, "struct");
|
||||||
|
} else {
|
||||||
|
Error ("Tag name identifier or '{' expected");
|
||||||
|
UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* Remember we have an extra type decl */
|
|
||||||
Spec->Flags |= DS_EXTRA_TYPE;
|
|
||||||
/* Declare the struct in the current scope */
|
/* Declare the struct in the current scope */
|
||||||
TagEntry = ParseStructSpec (Ident, &Spec->Flags);
|
TagEntry = ParseStructSpec (Ident, &Spec->Flags);
|
||||||
/* Encode the struct entry into the type */
|
/* Encode the struct entry into the type */
|
||||||
|
@ -1678,18 +1641,19 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
|
|
||||||
case TOK_ENUM:
|
case TOK_ENUM:
|
||||||
NextToken ();
|
NextToken ();
|
||||||
/* Named enum */
|
/* Remember we have an extra type decl */
|
||||||
|
Spec->Flags |= DS_EXTRA_TYPE;
|
||||||
|
/* Check for tag name */
|
||||||
if (CurTok.Tok == TOK_IDENT) {
|
if (CurTok.Tok == TOK_IDENT) {
|
||||||
strcpy (Ident, CurTok.Ident);
|
strcpy (Ident, CurTok.Ident);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else {
|
} else if (CurTok.Tok == TOK_LCURLY) {
|
||||||
if (CurTok.Tok != TOK_LCURLY) {
|
|
||||||
Error ("Identifier expected for enum tag name");
|
|
||||||
}
|
|
||||||
AnonName (Ident, "enum");
|
AnonName (Ident, "enum");
|
||||||
|
} else {
|
||||||
|
Error ("Tag name identifier or '{' expected");
|
||||||
|
UseDefaultType (Spec, TS_DEFAULT_TYPE_NONE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* Remember we have an extra type decl */
|
|
||||||
Spec->Flags |= DS_EXTRA_TYPE;
|
|
||||||
/* Parse the enum decl */
|
/* Parse the enum decl */
|
||||||
TagEntry = ParseEnumSpec (Ident, &Spec->Flags);
|
TagEntry = ParseEnumSpec (Ident, &Spec->Flags);
|
||||||
/* Encode the enum entry into the type */
|
/* Encode the enum entry into the type */
|
||||||
|
@ -1699,9 +1663,7 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
/* The signedness of enums is determined by the type, so say this is specified to avoid
|
/* The signedness of enums is determined by the type, so say this is specified to avoid
|
||||||
** the int -> unsigned int handling for plain int bit-fields in AddBitField.
|
** the int -> unsigned int handling for plain int bit-fields in AddBitField.
|
||||||
*/
|
*/
|
||||||
if (SignednessSpecified) {
|
Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
|
||||||
*SignednessSpecified = 1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_IDENT:
|
case TOK_IDENT:
|
||||||
|
@ -1718,9 +1680,7 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
** Unforunately, this will cause plain int bit-fields defined via typedefs
|
** Unforunately, this will cause plain int bit-fields defined via typedefs
|
||||||
** to be treated as signed rather than unsigned.
|
** to be treated as signed rather than unsigned.
|
||||||
*/
|
*/
|
||||||
if (SignednessSpecified) {
|
Spec->Flags |= DS_EXPLICIT_SIGNEDNESS;
|
||||||
*SignednessSpecified = 1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
} else if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) {
|
} else if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) {
|
||||||
/* Treat this identifier as an unknown type */
|
/* Treat this identifier as an unknown type */
|
||||||
|
@ -1734,23 +1694,13 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp
|
||||||
** in DeclareLocals. The type code used here doesn't matter as
|
** in DeclareLocals. The type code used here doesn't matter as
|
||||||
** long as it has no qualifiers.
|
** long as it has no qualifiers.
|
||||||
*/
|
*/
|
||||||
Spec->Flags |= DS_DEF_TYPE;
|
UseDefaultType (Spec, TS_DEFAULT_TYPE_INT);
|
||||||
Spec->Type[0].C = T_INT;
|
|
||||||
Spec->Type[1].C = T_END;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* FALL THROUGH */
|
/* FALL THROUGH */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) {
|
UseDefaultType (Spec, TSFlags);
|
||||||
Spec->Flags |= DS_NO_TYPE;
|
|
||||||
Spec->Type[0].C = T_INT;
|
|
||||||
Spec->Type[1].C = T_END;
|
|
||||||
} else {
|
|
||||||
Spec->Flags |= DS_DEF_TYPE;
|
|
||||||
Spec->Type[0].C = T_INT;
|
|
||||||
Spec->Type[1].C = T_END;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1839,6 +1789,9 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
||||||
/* Read the declaration specifier */
|
/* Read the declaration specifier */
|
||||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
||||||
|
|
||||||
|
/* Paremeters must have identifiers as names */
|
||||||
|
Spec.Flags |= DS_NO_EMPTY_DECL;
|
||||||
|
|
||||||
/* We accept only auto and register as storage class specifiers, but
|
/* We accept only auto and register as storage class specifiers, but
|
||||||
** we ignore all this, since we use auto anyway.
|
** we ignore all this, since we use auto anyway.
|
||||||
*/
|
*/
|
||||||
|
@ -1848,7 +1801,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Type must be specified */
|
/* Type must be specified */
|
||||||
if ((Spec.Flags & DS_NO_TYPE) != 0) {
|
if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||||
Error ("Expected declaration specifiers");
|
Error ("Expected declaration specifiers");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1859,7 +1812,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
||||||
Declarator Decl;
|
Declarator Decl;
|
||||||
|
|
||||||
/* Read the parameter */
|
/* Read the parameter */
|
||||||
ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
|
ParseDecl (&Spec, &Decl, DM_IDENT_OR_EMPTY);
|
||||||
|
|
||||||
/* Warn about new local type declaration */
|
/* Warn about new local type declaration */
|
||||||
if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0) {
|
if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0) {
|
||||||
|
@ -1941,7 +1894,7 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Type must be specified */
|
/* Type must be specified */
|
||||||
if ((Spec.Flags & DS_NO_TYPE) != 0) {
|
if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||||
Error ("Type specifier missing");
|
Error ("Type specifier missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2083,7 +2036,7 @@ static FuncDesc* ParseFuncDecl (void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static declmode_t DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
static void DirectDecl (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
|
||||||
|
@ -2101,19 +2054,19 @@ static declmode_t DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mo
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* A pointer type cannot be used as an empty declaration */
|
/* A pointer type cannot be used as an empty declaration */
|
||||||
if (Mode == DM_ACCEPT_IDENT) {
|
if (Mode == DM_IDENT_OR_EMPTY) {
|
||||||
Mode = DM_NEED_IDENT;
|
Spec->Flags |= DS_NO_EMPTY_DECL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 */
|
||||||
Mode = DirectDecl (Spec, D, Mode);
|
DirectDecl (Spec, D, Mode);
|
||||||
|
|
||||||
/* Add the type */
|
/* Add the type */
|
||||||
AddTypeCodeToDeclarator (D, T_PTR | Qualifiers);
|
AddTypeCodeToDeclarator (D, T_PTR | Qualifiers);
|
||||||
return Mode;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurTok.Tok == TOK_LPAREN) {
|
if (CurTok.Tok == TOK_LPAREN) {
|
||||||
|
@ -2121,28 +2074,27 @@ static declmode_t DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mo
|
||||||
/* An empty declaration cannot contain parentheses where an identifier
|
/* An empty declaration cannot contain parentheses where an identifier
|
||||||
** would show up if it were a non-empty declaration.
|
** would show up if it were a non-empty declaration.
|
||||||
*/
|
*/
|
||||||
if (Mode == DM_ACCEPT_IDENT) {
|
if (Mode == DM_IDENT_OR_EMPTY) {
|
||||||
Mode = DM_NEED_IDENT;
|
Spec->Flags |= DS_NO_EMPTY_DECL;
|
||||||
}
|
}
|
||||||
Mode = DirectDecl (Spec, D, Mode);
|
DirectDecl (Spec, D, Mode);
|
||||||
ConsumeRParen ();
|
ConsumeRParen ();
|
||||||
} else if (CurTok.Tok == TOK_IDENT) {
|
} else if (CurTok.Tok == TOK_IDENT) {
|
||||||
|
if (Mode == DM_NO_IDENT) {
|
||||||
|
Error ("Unexpected identifier in type name");
|
||||||
|
}
|
||||||
strcpy (D->Ident, CurTok.Ident);
|
strcpy (D->Ident, CurTok.Ident);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else {
|
} else {
|
||||||
D->Ident[0] = '\0';
|
D->Ident[0] = '\0';
|
||||||
if (Mode == DM_NEED_IDENT) {
|
if ((Spec->Flags & DS_NO_EMPTY_DECL) != 0 &&
|
||||||
|
CurTok.Tok != TOK_LBRACK &&
|
||||||
|
((Spec->Flags & DS_ALLOW_BITFIELD) == 0 || CurTok.Tok != TOK_COLON)) {
|
||||||
Error ("Identifier expected");
|
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 */
|
||||||
|
@ -2181,6 +2133,18 @@ static declmode_t DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mo
|
||||||
/* Array declarator */
|
/* Array declarator */
|
||||||
long Size = UNSPECIFIED;
|
long Size = UNSPECIFIED;
|
||||||
|
|
||||||
|
/* An array type cannot be used as an empty declaration */
|
||||||
|
if (Mode == DM_IDENT_OR_EMPTY) {
|
||||||
|
Spec->Flags |= DS_NO_EMPTY_DECL;
|
||||||
|
if (D->Ident[0] == '\0') {
|
||||||
|
if ((Spec->Flags & DS_TYPE_MASK) != DS_NONE) {
|
||||||
|
Error ("Identifier or ';' expected after declaration specifiers");
|
||||||
|
} else {
|
||||||
|
Error ("Identifier expected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* We cannot have any qualifiers for an array */
|
/* We cannot have any qualifiers for an array */
|
||||||
if (Qualifiers != T_QUAL_NONE) {
|
if (Qualifiers != T_QUAL_NONE) {
|
||||||
Error ("Invalid qualifiers for array");
|
Error ("Invalid qualifiers for array");
|
||||||
|
@ -2228,8 +2192,6 @@ static declmode_t DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mo
|
||||||
if (Qualifiers & T_QUAL_CDECL) {
|
if (Qualifiers & T_QUAL_CDECL) {
|
||||||
Error ("Invalid '__cdecl__' qualifier");
|
Error ("Invalid '__cdecl__' qualifier");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2241,20 +2203,41 @@ static declmode_t DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mo
|
||||||
|
|
||||||
|
|
||||||
Type* ParseType (Type* T)
|
Type* ParseType (Type* T)
|
||||||
/* Parse a complete type specification */
|
/* Parse a complete type specification in parentheses */
|
||||||
{
|
{
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
Declarator Decl;
|
Declarator Decl;
|
||||||
|
int NeedClean = -1;
|
||||||
|
|
||||||
|
/* Skip the left paren */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
/* Get a type without a default */
|
/* Get a type without a default */
|
||||||
InitDeclSpec (&Spec);
|
InitDeclSpec (&Spec);
|
||||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, NULL);
|
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE);
|
||||||
|
|
||||||
/* Parse additional declarators */
|
/* Only parse further if there is a type specifier */
|
||||||
ParseDecl (&Spec, &Decl, DM_NO_IDENT);
|
if ((Spec.Flags & DS_TYPE_MASK) != DS_NONE) {
|
||||||
|
/* Parse additional declarators */
|
||||||
|
NeedClean = ParseDecl (&Spec, &Decl, DM_NO_IDENT);
|
||||||
|
|
||||||
/* Copy the type to the target buffer */
|
/* Copy the type to the target buffer */
|
||||||
TypeCopy (T, Decl.Type);
|
TypeCopy (T, Decl.Type);
|
||||||
|
} else {
|
||||||
|
/* Fail-safe */
|
||||||
|
TypeCopy (T, type_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try some smart error recovery */
|
||||||
|
if (NeedClean < 0) {
|
||||||
|
SimpleErrorSkip ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Closing paren */
|
||||||
|
if (!ConsumeRParen ()) {
|
||||||
|
SimpleErrorSkip ();
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Return a pointer to the target buffer */
|
/* Return a pointer to the target buffer */
|
||||||
return T;
|
return T;
|
||||||
|
@ -2262,14 +2245,24 @@ Type* ParseType (Type* T)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
/* Parse a variable, type or function declarator. Return -1 if this stops at
|
/* Parse a variable, type or function declarator. Return -1 if this stops at
|
||||||
** an unpaired right parenthesis/bracket/curly brace.
|
** an unpaired right parenthesis/bracket/curly brace. Return 0 if this stops
|
||||||
|
** after consuming a semicolon or closing curly brace, or reaching an EOF.
|
||||||
|
** Return 1 otherwise.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/* 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;
|
||||||
|
|
||||||
|
/* If there is no explicit type specifier, an optional identifier becomes
|
||||||
|
** required.
|
||||||
|
*/
|
||||||
|
if (Mode == DM_IDENT_OR_EMPTY &&
|
||||||
|
(Spec->Flags & DS_TYPE_MASK) == DS_DEF_TYPE) {
|
||||||
|
Spec->Flags |= DS_NO_EMPTY_DECL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize the Declarator struct */
|
/* Initialize the Declarator struct */
|
||||||
InitDeclarator (D);
|
InitDeclarator (D);
|
||||||
|
|
||||||
|
@ -2283,6 +2276,11 @@ int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
/* Use the storage class from the declspec */
|
/* Use the storage class from the declspec */
|
||||||
D->StorageClass = Spec->StorageClass;
|
D->StorageClass = Spec->StorageClass;
|
||||||
|
|
||||||
|
/* If we have a function, add a special symbol type */
|
||||||
|
if (IsTypeFunc (D->Type)) {
|
||||||
|
D->StorageClass |= SC_FUNC;
|
||||||
|
}
|
||||||
|
|
||||||
/* Do several fixes on qualifiers */
|
/* Do several fixes on qualifiers */
|
||||||
FixQualifiers (D->Type);
|
FixQualifiers (D->Type);
|
||||||
|
|
||||||
|
@ -2297,26 +2295,8 @@ int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
/* Parse attributes for this declarator */
|
/* Parse attributes for this declarator */
|
||||||
ParseAttribute (D);
|
ParseAttribute (D);
|
||||||
|
|
||||||
/* If we have a function, add a special storage class */
|
|
||||||
if (IsTypeFunc (D->Type)) {
|
|
||||||
|
|
||||||
D->StorageClass |= SC_FUNC;
|
|
||||||
|
|
||||||
} else if (!IsTypeVoid (D->Type)) {
|
|
||||||
/* Check the size of the generated type */
|
|
||||||
unsigned Size = SizeOf (D->Type);
|
|
||||||
|
|
||||||
if (Size >= 0x10000) {
|
|
||||||
if (D->Ident[0] != '\0') {
|
|
||||||
Error ("Size of '%s' is invalid (0x%06X)", D->Ident, Size);
|
|
||||||
} else {
|
|
||||||
Error ("Invalid size in declaration (0x%06X)", Size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check a few pre-C99 things */
|
/* Check a few pre-C99 things */
|
||||||
if (D->Ident[0] != '\0' && (Spec->Flags & DS_DEF_TYPE) != 0) {
|
if (D->Ident[0] != '\0' && (Spec->Flags & DS_TYPE_MASK) == DS_DEF_TYPE) {
|
||||||
/* 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
|
||||||
|
@ -2331,7 +2311,7 @@ int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
/* For anything 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 (!IsTypeFunc (D->Type) &&
|
||||||
(D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
|
(D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
|
||||||
/* If the standard was not set explicitly to C89, print a warning
|
/* If the standard was not set explicitly to C89, print a warning
|
||||||
** for variables with implicit int type.
|
** for variables with implicit int type.
|
||||||
|
@ -2342,11 +2322,32 @@ int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PrevErrorCount != ErrorCount) {
|
/* Check the size of the declared type */
|
||||||
if ((Spec->Flags & DS_DEF_TYPE) == 0 && Mode == DM_NEED_IDENT && D->Ident[0] == '\0') {
|
if (IsObjectType (D->Type)) {
|
||||||
/* Make the declaration fictitious if is is not parsed correctly */
|
unsigned Size = SizeOf (D->Type);
|
||||||
D->StorageClass |= SC_FICTITIOUS;
|
|
||||||
|
|
||||||
|
if (Size >= 0x10000) {
|
||||||
|
if (D->Ident[0] != '\0') {
|
||||||
|
Error ("Size of '%s' is too large (0x%06X)", D->Ident, Size);
|
||||||
|
} else {
|
||||||
|
Error ("Size in declaration is too large (0x%06X)", Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* An empty declaration must be terminated with a semicolon */
|
||||||
|
if (PrevErrorCount == ErrorCount &&
|
||||||
|
Mode == DM_IDENT_OR_EMPTY &&
|
||||||
|
D->Ident[0] == '\0' &&
|
||||||
|
CurTok.Tok != TOK_SEMI &&
|
||||||
|
((Spec->Flags & DS_ALLOW_BITFIELD) == 0 || CurTok.Tok != TOK_COLON)) {
|
||||||
|
Error ("Identifier or ';' expected after declaration specifiers");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PrevErrorCount != ErrorCount) {
|
||||||
|
if ((Spec->Flags & DS_TYPE_MASK) != DS_DEF_TYPE &&
|
||||||
|
(Spec->Flags & DS_NO_EMPTY_DECL) != 0 &&
|
||||||
|
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 */
|
||||||
const char* Level = "";
|
const char* Level = "";
|
||||||
|
|
||||||
|
@ -2366,15 +2367,21 @@ int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
AnonName (D->Ident, Level);
|
AnonName (D->Ident, Level);
|
||||||
|
|
||||||
|
/* Make the declarator fictitious */
|
||||||
|
D->StorageClass |= SC_FICTITIOUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try some smart error recovery */
|
/* Try some smart error recovery */
|
||||||
if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) {
|
if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) {
|
||||||
return SmartErrorSkip (0);
|
/* Skip to the end of the whole declaration if it is not part of a
|
||||||
|
** parameter list or a type cast.
|
||||||
|
*/
|
||||||
|
return SmartErrorSkip (Mode == DM_IDENT_OR_EMPTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2389,7 +2396,7 @@ void ParseDeclSpec (DeclSpec* Spec, typespec_t TSFlags, unsigned DefStorage)
|
||||||
Spec->Flags &= ~DS_DEF_STORAGE;
|
Spec->Flags &= ~DS_DEF_STORAGE;
|
||||||
|
|
||||||
/* Parse the type specifiers */
|
/* Parse the type specifiers */
|
||||||
ParseTypeSpec (Spec, TSFlags | TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC, NULL);
|
ParseTypeSpec (Spec, TSFlags | TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC);
|
||||||
|
|
||||||
/* If no explicit storage class is given, use the default */
|
/* If no explicit storage class is given, use the default */
|
||||||
if (Spec->StorageClass == 0) {
|
if (Spec->StorageClass == 0) {
|
||||||
|
@ -2406,7 +2413,13 @@ void CheckEmptyDecl (const DeclSpec* Spec)
|
||||||
** warning if not.
|
** warning if not.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
if ((Spec->Flags & DS_EXTRA_TYPE) == 0) {
|
if ((Spec->Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||||
Warning ("Useless declaration");
|
/* No declaration at all */
|
||||||
|
} else if ((Spec->Flags & DS_EXTRA_TYPE) == 0) {
|
||||||
|
Warning ("Declaration does not declare anything");
|
||||||
|
} else if (IsClassStruct (Spec->Type) &&
|
||||||
|
!IsIncompleteESUType (Spec->Type) &&
|
||||||
|
SymHasAnonName (GetESUTagSym (Spec->Type))) {
|
||||||
|
Warning ("Unnamed %s that defines no instances", GetBasicTypeName (Spec->Type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,18 +65,26 @@ enum typespec_t {
|
||||||
TS_DEFAULT_TYPE_AUTO = 0x02, /* C23 type inference with auto */
|
TS_DEFAULT_TYPE_AUTO = 0x02, /* C23 type inference with auto */
|
||||||
|
|
||||||
/* Whether to allow certain kinds of specifiers */
|
/* Whether to allow certain kinds of specifiers */
|
||||||
TS_STORAGE_CLASS_SPEC = 0x04, /* Allow storage storage class specifiers */
|
TS_STORAGE_CLASS_SPEC = 0x04, /* Allow storage class specifiers */
|
||||||
TS_FUNCTION_SPEC = 0x08, /* Allow function specifiers */
|
TS_FUNCTION_SPEC = 0x08, /* Allow function specifiers */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Masks for the Flags field in DeclSpec */
|
/* Masks for the Flags field in DeclSpec */
|
||||||
|
#define DS_NONE 0x0000U /* Nothing specified or used */
|
||||||
#define DS_DEF_STORAGE 0x0001U /* Default storage class used */
|
#define DS_DEF_STORAGE 0x0001U /* Default storage class used */
|
||||||
#define DS_NO_TYPE 0x0002U /* No type explicitly specified */
|
#define DS_EXPLICIT_TYPE 0x0002U /* Type specified */
|
||||||
#define DS_DEF_TYPE 0x0006U /* Default type used */
|
#define DS_DEF_TYPE 0x0004U /* Implicit type used */
|
||||||
#define DS_EXTRA_TYPE 0x0008U /* Extra type declared */
|
#define DS_AUTO_TYPE 0x0006U /* C23 auto type used */
|
||||||
|
#define DS_TYPE_MASK 0x0006U /* Mask for type of spec decl */
|
||||||
|
#define DS_EXTRA_TYPE 0x0008U /* ESU type in declaration */
|
||||||
#define DS_NEW_TYPE_DECL 0x0010U /* New type declared */
|
#define DS_NEW_TYPE_DECL 0x0010U /* New type declared */
|
||||||
#define DS_NEW_TYPE_DEF 0x0020U /* New type defined */
|
#define DS_NEW_TYPE_DEF 0x0020U /* New type defined */
|
||||||
#define DS_NEW_TYPE (DS_NEW_TYPE_DECL | DS_NEW_TYPE_DEF)
|
#define DS_NEW_TYPE (DS_NEW_TYPE_DECL | DS_NEW_TYPE_DEF)
|
||||||
|
#define DS_EXPLICIT_SIGNEDNESS 0x0040U /* Signedness specified */
|
||||||
|
#define DS_NO_EMPTY_DECL 0x0100U /* Disallow empty declaration */
|
||||||
|
#define DS_ALLOW_BITFIELD 0x0200U /* Allow anonymous bit-fields */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Result of ParseDeclSpec */
|
/* Result of ParseDeclSpec */
|
||||||
typedef struct DeclSpec DeclSpec;
|
typedef struct DeclSpec DeclSpec;
|
||||||
|
@ -99,24 +107,22 @@ struct Declarator {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Modes for ParseDecl:
|
/* Modes for ParseDecl:
|
||||||
** - DM_NEED_IDENT means:
|
** - DM_IDENT_OR_EMPTY means:
|
||||||
** we *must* have a type and a variable identifer.
|
** we *may* have an identifier, or none. If it is the latter case,
|
||||||
|
** the type specifier must be used for an empty declaration,
|
||||||
|
** or it is an error.
|
||||||
** - DM_NO_IDENT means:
|
** - DM_NO_IDENT means:
|
||||||
** we must have a type but no variable identifer
|
** we must have a type but no variable identifer
|
||||||
** (if there is one, it's not read).
|
** (if there is one, it's not read).
|
||||||
** - DM_ACCEPT_IDENT means:
|
** Note: this is used for type names.
|
||||||
** we *may* have an identifier, or none. If it is the latter case,
|
** - DM_ACCEPT_PARAM_IDENT means:
|
||||||
** 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,
|
** we *may* have an identifier. If there is an identifier,
|
||||||
** it is read, but it is no error, if there is none.
|
** it is read, but it is no error, if there is none.
|
||||||
** Note: this is used for function parameter type lists.
|
** Note: this is used for function parameter type lists.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DM_NEED_IDENT,
|
DM_IDENT_OR_EMPTY,
|
||||||
DM_NO_IDENT,
|
DM_NO_IDENT,
|
||||||
DM_ACCEPT_IDENT,
|
|
||||||
DM_ACCEPT_PARAM_IDENT,
|
DM_ACCEPT_PARAM_IDENT,
|
||||||
} declmode_t;
|
} declmode_t;
|
||||||
|
|
||||||
|
@ -128,29 +134,14 @@ typedef enum {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int SmartErrorSkip (int WholeDecl);
|
|
||||||
/* Try some smart error recovery.
|
|
||||||
**
|
|
||||||
** - If WholeDecl is 0:
|
|
||||||
** Skip tokens until a comma or closing curly brace that is not enclosed in
|
|
||||||
** an open parenthesis/bracket/curly brace, or until a semicolon, EOF or
|
|
||||||
** unpaired right parenthesis/bracket/curly brace is reached.
|
|
||||||
**
|
|
||||||
** - If WholeDecl is non-0:
|
|
||||||
** Skip tokens until a closing curly brace that is not enclosed in an open
|
|
||||||
** parenthesis/bracket/curly brace, or until a semicolon or EOF is reached.
|
|
||||||
**
|
|
||||||
** Return 0 if this exits as soon as it reaches an EOF. Return 0 as well if
|
|
||||||
** this exits with no open parentheses/brackets/curly braces. Otherwise, return
|
|
||||||
** -1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Type* ParseType (Type* Type);
|
Type* ParseType (Type* Type);
|
||||||
/* Parse a complete type specification */
|
/* Parse a complete type specification in parentheses */
|
||||||
|
|
||||||
int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode);
|
int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode);
|
||||||
/* Parse a variable, type or function declarator. Return -1 if this stops at
|
/* Parse a variable, type or function declarator. Return -1 if this stops at
|
||||||
** an unpaired right parenthesis/bracket/curly brace.
|
** an unpaired right parenthesis/bracket/curly brace. Return 0 if this stops
|
||||||
|
** after consuming a semicolon or closing curly brace, or reaching an EOF.
|
||||||
|
** Return 1 otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ParseDeclSpec (DeclSpec* Spec, typespec_t TSFlags, unsigned DefStorage);
|
void ParseDeclSpec (DeclSpec* Spec, typespec_t TSFlags, unsigned DefStorage);
|
||||||
|
|
|
@ -1428,25 +1428,9 @@ static void Primary (ExprDesc* E)
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
||||||
|
|
||||||
if ((Spec.Flags & DS_DEF_TYPE) == 0) {
|
if ((Spec.Flags & DS_TYPE_MASK) != DS_NONE) {
|
||||||
/* Recognized but not supported */
|
|
||||||
Error ("Mixed declarations and code are not supported in cc65");
|
Error ("Mixed declarations and code are not supported in cc65");
|
||||||
|
SmartErrorSkip (0);
|
||||||
while (CurTok.Tok != TOK_SEMI) {
|
|
||||||
Declarator Decl;
|
|
||||||
|
|
||||||
/* Parse one declaration */
|
|
||||||
ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
|
|
||||||
if (CurTok.Tok == TOK_ASSIGN) {
|
|
||||||
NextToken ();
|
|
||||||
ParseInit (Decl.Type);
|
|
||||||
}
|
|
||||||
if (CurTok.Tok == TOK_COMMA) {
|
|
||||||
NextToken ();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Error ("Expression expected");
|
Error ("Expression expected");
|
||||||
E->Flags |= E_EVAL_MAYBE_UNUSED;
|
E->Flags |= E_EVAL_MAYBE_UNUSED;
|
||||||
|
@ -2147,9 +2131,7 @@ void hie10 (ExprDesc* Expr)
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (TypeSpecAhead ()) {
|
if (TypeSpecAhead ()) {
|
||||||
Type T[MAXTYPELEN];
|
Type T[MAXTYPELEN];
|
||||||
NextToken ();
|
|
||||||
Size = ExprCheckedSizeOf (ParseType (T));
|
Size = ExprCheckedSizeOf (ParseType (T));
|
||||||
ConsumeRParen ();
|
|
||||||
} else {
|
} else {
|
||||||
/* Remember the output queue pointer */
|
/* Remember the output queue pointer */
|
||||||
CodeMark Mark;
|
CodeMark Mark;
|
||||||
|
|
|
@ -462,14 +462,15 @@ static void ParseStaticDecl (Declarator* Decl)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParseOneDecl (const DeclSpec* Spec)
|
static int ParseOneDecl (DeclSpec* Spec)
|
||||||
/* Parse one variable declarator. */
|
/* Parse one variable declarator. */
|
||||||
{
|
{
|
||||||
Declarator Decl; /* Declarator data structure */
|
Declarator Decl; /* Declarator data structure */
|
||||||
|
int NeedClean;
|
||||||
|
|
||||||
|
|
||||||
/* Read the declarator */
|
/* Read the declarator */
|
||||||
ParseDecl (Spec, &Decl, DM_NEED_IDENT);
|
NeedClean = ParseDecl (Spec, &Decl, DM_IDENT_OR_EMPTY);
|
||||||
|
|
||||||
/* Check if there are any non-extern storage classes set for function
|
/* Check if there are any non-extern storage classes set for function
|
||||||
** declarations. Function can only be declared inside functions with the
|
** declarations. Function can only be declared inside functions with the
|
||||||
|
@ -559,6 +560,8 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
||||||
|
|
||||||
/* Make sure we aren't missing some work */
|
/* Make sure we aren't missing some work */
|
||||||
CheckDeferredOpAllDone ();
|
CheckDeferredOpAllDone ();
|
||||||
|
|
||||||
|
return NeedClean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -574,15 +577,8 @@ void DeclareLocals (void)
|
||||||
|
|
||||||
/* Loop until we don't find any more variables */
|
/* Loop until we don't find any more variables */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
/* Check variable declarations. We need to distinguish between a
|
|
||||||
** default int type and the end of variable declarations. So we
|
|
||||||
** will do the following: If there is no explicit storage class
|
|
||||||
** specifier *and* no explicit type given, *and* no type qualifiers
|
|
||||||
** have been read, it is assumed that we have reached the end of
|
|
||||||
** declarations.
|
|
||||||
*/
|
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
|
int NeedClean;
|
||||||
|
|
||||||
/* Check for a _Static_assert */
|
/* Check for a _Static_assert */
|
||||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||||
|
@ -590,10 +586,18 @@ void DeclareLocals (void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read the declaration specifier */
|
||||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO);
|
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO);
|
||||||
if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
|
|
||||||
(Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
|
/* Check variable declarations. We need distinguish between a default
|
||||||
GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */
|
** int type and the end of variable declarations. So we will do the
|
||||||
|
** following: If there is no explicit storage class specifier *and* no
|
||||||
|
** explicit type given, *and* no type qualifiers have been read, it is
|
||||||
|
** assumed that we have reached the end of declarations.
|
||||||
|
*/
|
||||||
|
if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
|
||||||
|
(Spec.Flags & DS_TYPE_MASK) == DS_DEF_TYPE && /* No type given */
|
||||||
|
GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,11 +609,24 @@ void DeclareLocals (void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we haven't got a type specifier yet, something must be wrong */
|
||||||
|
if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||||
|
/* Avoid extra errors if it was a failed type specifier */
|
||||||
|
if ((Spec.Flags & DS_EXTRA_TYPE) == 0) {
|
||||||
|
Error ("Declaration specifier expected");
|
||||||
|
}
|
||||||
|
NeedClean = -1;
|
||||||
|
goto EndOfDecl;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse a comma separated variable list */
|
/* Parse a comma separated variable list */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
/* Parse one declaration */
|
/* Parse one declarator */
|
||||||
ParseOneDecl (&Spec);
|
NeedClean = ParseOneDecl (&Spec);
|
||||||
|
if (NeedClean <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if there is more */
|
/* Check if there is more */
|
||||||
if (CurTok.Tok == TOK_COMMA) {
|
if (CurTok.Tok == TOK_COMMA) {
|
||||||
|
@ -621,8 +638,20 @@ void DeclareLocals (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A semicolon must follow */
|
if (NeedClean > 0) {
|
||||||
ConsumeSemi ();
|
/* Must be followed by a semicolon */
|
||||||
|
if (ConsumeSemi ()) {
|
||||||
|
NeedClean = 0;
|
||||||
|
} else {
|
||||||
|
NeedClean = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EndOfDecl:
|
||||||
|
/* Try some smart error recovery */
|
||||||
|
if (NeedClean < 0) {
|
||||||
|
SmartErrorSkip (1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Be sure to allocate any reserved space for locals */
|
/* Be sure to allocate any reserved space for locals */
|
||||||
|
|
|
@ -1245,6 +1245,212 @@ void SkipTokens (const token_t* TokenList, unsigned TokenCount)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 void PopBrace (Collection* C)
|
||||||
|
/* Close the latest open parenthesis/bracket/curly brace */
|
||||||
|
{
|
||||||
|
if (CollCount (C) > 0) {
|
||||||
|
CollPop (C);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int CloseBrace (Collection* C, token_t Tok)
|
||||||
|
/* Consume a closing parenthesis/bracket/curly brace if it is matched with an
|
||||||
|
** opening one to close 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 (int TillEnd)
|
||||||
|
/* Try some smart error recovery.
|
||||||
|
**
|
||||||
|
** - If TillEnd == 0:
|
||||||
|
** Skip tokens until a comma or closing curly brace that is not enclosed in
|
||||||
|
** an open parenthesis/bracket/curly brace, or until a semicolon, EOF or
|
||||||
|
** unpaired right parenthesis/bracket/curly brace is reached. The closing
|
||||||
|
** curly brace is consumed in the former case.
|
||||||
|
**
|
||||||
|
** - If TillEnd != 0:
|
||||||
|
** Skip tokens until a right curly brace or semicolon is reached and consumed
|
||||||
|
** while there are no open parentheses/brackets/curly braces, or until an EOF
|
||||||
|
** is reached anytime. Any open parenthesis/bracket/curly brace is considered
|
||||||
|
** to be closed by consuming a right parenthesis/bracket/curly brace even if
|
||||||
|
** they didn't match.
|
||||||
|
**
|
||||||
|
** - Return -1:
|
||||||
|
** If this exits at a semicolon or unpaired right parenthesis/bracket/curly
|
||||||
|
** brace while there are still open parentheses/brackets/curly braces.
|
||||||
|
**
|
||||||
|
** - Return 0:
|
||||||
|
** If this exits as soon as it reaches an EOF;
|
||||||
|
** Or if this exits right after consuming a semicolon or right curly brace
|
||||||
|
** while there are no open parentheses/brackets/curly braces.
|
||||||
|
**
|
||||||
|
** - Return 1:
|
||||||
|
** If this exits at a non-EOF without consuming it.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
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) < 0) {
|
||||||
|
if (!TillEnd) {
|
||||||
|
Res = -1;
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
PopBrace (&C);
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_RCURLY:
|
||||||
|
if (CloseBrace (&C, CurTok.Tok) < 0) {
|
||||||
|
if (!TillEnd) {
|
||||||
|
Res = -1;
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
PopBrace (&C);
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
if (CollCount (&C) == 0) {
|
||||||
|
/* We consider this as a terminator as well */
|
||||||
|
Res = 0;
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_COMMA:
|
||||||
|
if (CollCount (&C) == 0 && !TillEnd) {
|
||||||
|
Res = 1;
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
NextToken ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_SEMI:
|
||||||
|
if (CollCount (&C) == 0) {
|
||||||
|
if (TillEnd) {
|
||||||
|
NextToken ();
|
||||||
|
Res = 0;
|
||||||
|
} else {
|
||||||
|
Res = 1;
|
||||||
|
}
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
NextToken ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_CEOF:
|
||||||
|
/* We cannot consume this */
|
||||||
|
Res = 0;
|
||||||
|
goto ExitPoint;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Internal ("Unexpected token: %02X", (unsigned)CurTok.Tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitPoint:
|
||||||
|
DoneCollection (&C);
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int SimpleErrorSkip (void)
|
||||||
|
/* Skip tokens until an EOF or unpaired right parenthesis/bracket/curly brace
|
||||||
|
** is reached. Return 0 If this exits at an EOF. Otherwise return -1.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Collection C = AUTO_COLLECTION_INITIALIZER;
|
||||||
|
int Res = 0;
|
||||||
|
|
||||||
|
/* Some fix point tokens that are used for error recovery */
|
||||||
|
static const token_t TokenList[] = {
|
||||||
|
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:
|
||||||
|
case TOK_RCURLY:
|
||||||
|
if (CloseBrace (&C, CurTok.Tok) < 0) {
|
||||||
|
/* Found a terminator */
|
||||||
|
Res = -1;
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_CEOF:
|
||||||
|
/* We cannot go any farther */
|
||||||
|
Res = 0;
|
||||||
|
goto ExitPoint;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Internal ("Unexpected token: %02X", (unsigned)CurTok.Tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitPoint:
|
||||||
|
DoneCollection (&C);
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Consume (token_t Token, const char* ErrorMsg)
|
int Consume (token_t Token, const char* ErrorMsg)
|
||||||
/* Eat token if it is the next in the input stream, otherwise print an error
|
/* Eat token if it is the next in the input stream, otherwise print an error
|
||||||
** message. Returns true if the token was found and false otherwise.
|
** message. Returns true if the token was found and false otherwise.
|
||||||
|
|
|
@ -310,6 +310,40 @@ void SkipTokens (const token_t* TokenList, unsigned TokenCount);
|
||||||
** This routine is used for error recovery.
|
** This routine is used for error recovery.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
int SmartErrorSkip (int TillEnd);
|
||||||
|
/* Try some smart error recovery.
|
||||||
|
**
|
||||||
|
** - If TillEnd == 0:
|
||||||
|
** Skip tokens until a comma or closing curly brace that is not enclosed in
|
||||||
|
** an open parenthesis/bracket/curly brace, or until a semicolon, EOF or
|
||||||
|
** unpaired right parenthesis/bracket/curly brace is reached. The closing
|
||||||
|
** curly brace is consumed in the former case.
|
||||||
|
**
|
||||||
|
** - If TillEnd != 0:
|
||||||
|
** Skip tokens until a right curly brace or semicolon is reached and consumed
|
||||||
|
** while there are no open parentheses/brackets/curly braces, or until an EOF
|
||||||
|
** is reached anytime. Any open parenthesis/bracket/curly brace is considered
|
||||||
|
** to be closed by consuming a right parenthesis/bracket/curly brace even if
|
||||||
|
** they didn't match.
|
||||||
|
**
|
||||||
|
** - Return -1:
|
||||||
|
** If this exits at a semicolon or unpaired right parenthesis/bracket/curly
|
||||||
|
** brace while there are still open parentheses/brackets/curly braces.
|
||||||
|
**
|
||||||
|
** - Return 0:
|
||||||
|
** If this exits as soon as it reaches an EOF;
|
||||||
|
** Or if this exits right after consuming a semicolon or right curly brace
|
||||||
|
** while there are no open parentheses/brackets/curly braces.
|
||||||
|
**
|
||||||
|
** - Return 1:
|
||||||
|
** If this exits at a non-EOF without consuming it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int SimpleErrorSkip (void);
|
||||||
|
/* Skip tokens until an EOF or unpaired right parenthesis/bracket/curly brace
|
||||||
|
** is reached. Return 0 If this exits at an EOF. Otherwise return -1.
|
||||||
|
*/
|
||||||
|
|
||||||
int Consume (token_t Token, const char* ErrorMsg);
|
int Consume (token_t Token, const char* ErrorMsg);
|
||||||
/* Eat token if it is the next in the input stream, otherwise print an error
|
/* Eat token if it is the next in the input stream, otherwise print an error
|
||||||
** message. Returns true if the token was found and false otherwise.
|
** message. Returns true if the token was found and false otherwise.
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ParseStaticAssert ()
|
void ParseStaticAssert (void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
** static_assert-declaration ::=
|
** static_assert-declaration ::=
|
||||||
|
@ -53,20 +53,23 @@ void ParseStaticAssert ()
|
||||||
** _Static_assert ( constant-expression , string-literal ) ;
|
** _Static_assert ( constant-expression , string-literal ) ;
|
||||||
*/
|
*/
|
||||||
ExprDesc Expr;
|
ExprDesc Expr;
|
||||||
int failed;
|
unsigned PrevErrorCount = ErrorCount;
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
/* Skip the _Static_assert token itself */
|
/* Skip the _Static_assert token itself */
|
||||||
CHECK (CurTok.Tok == TOK_STATIC_ASSERT);
|
CHECK (CurTok.Tok == TOK_STATIC_ASSERT);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* We expect an opening paren */
|
/* We expect an opening paren */
|
||||||
if (!ConsumeLParen ()) {
|
if (ConsumeLParen ()) {
|
||||||
return;
|
/* Parse assertion condition */
|
||||||
|
Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
|
failed = !Expr.IVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse assertion condition */
|
if (PrevErrorCount != ErrorCount) {
|
||||||
Expr = NoCodeConstAbsIntExpr (hie1);
|
goto ExitPoint;
|
||||||
failed = !Expr.IVal;
|
}
|
||||||
|
|
||||||
/* If there is a comma, we also have an error message. The message is optional because we
|
/* If there is a comma, we also have an error message. The message is optional because we
|
||||||
** support the C2X syntax with only an expression.
|
** support the C2X syntax with only an expression.
|
||||||
|
@ -84,19 +87,16 @@ void ParseStaticAssert ()
|
||||||
/* String literal */
|
/* String literal */
|
||||||
if (CurTok.Tok != TOK_SCONST) {
|
if (CurTok.Tok != TOK_SCONST) {
|
||||||
Error ("String literal expected for static_assert message");
|
Error ("String literal expected for static_assert message");
|
||||||
return;
|
} else {
|
||||||
}
|
/* Issue an error including the message if the static_assert failed. */
|
||||||
|
if (failed) {
|
||||||
|
Error ("static_assert failed '%s'", GetLiteralStr (CurTok.SVal));
|
||||||
|
}
|
||||||
|
|
||||||
/* Issue an error including the message if the static_assert failed. */
|
/* Consume the string constant, now that we don't need it anymore.
|
||||||
if (failed) {
|
** This should never fail since we checked the token type above.
|
||||||
Error ("static_assert failed '%s'", GetLiteralStr (CurTok.SVal));
|
*/
|
||||||
}
|
Consume (TOK_SCONST, "String literal expected");
|
||||||
|
|
||||||
/* Consume the string constant, now that we don't need it anymore.
|
|
||||||
** This should never fail since we checked the token type above.
|
|
||||||
*/
|
|
||||||
if (!Consume (TOK_SCONST, "String literal expected")) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* No message. */
|
/* No message. */
|
||||||
|
@ -105,7 +105,24 @@ void ParseStaticAssert ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Closing paren and semi-colon needed */
|
/* The assertion failure error is not a syntax error */
|
||||||
ConsumeRParen ();
|
if (failed) {
|
||||||
ConsumeSemi ();
|
++PrevErrorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PrevErrorCount == ErrorCount) {
|
||||||
|
/* Closing paren needed */
|
||||||
|
ConsumeRParen ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PrevErrorCount == ErrorCount) {
|
||||||
|
/* Must be followed by a semicolon */
|
||||||
|
ConsumeSemi ();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitPoint:
|
||||||
|
/* Try some smart error recovery */
|
||||||
|
if (PrevErrorCount != ErrorCount) {
|
||||||
|
SmartErrorSkip (1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,15 +366,9 @@ void TypeCast (ExprDesc* Expr)
|
||||||
{
|
{
|
||||||
Type NewType[MAXTYPELEN];
|
Type NewType[MAXTYPELEN];
|
||||||
|
|
||||||
/* Skip the left paren */
|
/* Read the type enclosed in parentheses */
|
||||||
NextToken ();
|
|
||||||
|
|
||||||
/* Read the type */
|
|
||||||
ParseType (NewType);
|
ParseType (NewType);
|
||||||
|
|
||||||
/* Closing paren */
|
|
||||||
ConsumeRParen ();
|
|
||||||
|
|
||||||
/* Read the expression we have to cast */
|
/* Read the expression we have to cast */
|
||||||
hie10 (Expr);
|
hie10 (Expr);
|
||||||
|
|
||||||
|
|
25
test/err/type-name-extra-identifier.c
Normal file
25
test/err/type-name-extra-identifier.c
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The cc65 Authors
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Test of type name with extra identifier
|
||||||
|
*/
|
||||||
|
|
||||||
|
int a = sizeof (int b);
|
|
@ -1,3 +1,3 @@
|
||||||
bug1889-missing-identifier.c:3: Error: Identifier expected
|
bug1889-missing-identifier.c:3: Error: Identifier or ';' expected after declaration specifiers
|
||||||
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
|
||||||
|
|
53
test/val/optimizer-bug-pr2262.c
Normal file
53
test/val/optimizer-bug-pr2262.c
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
// optimizer bug that occured after PR #2262, fixed by PR #2295
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
unsigned char n;
|
||||||
|
unsigned long fp1;
|
||||||
|
|
||||||
|
int failures = 0;
|
||||||
|
|
||||||
|
void test1(void)
|
||||||
|
{
|
||||||
|
asm("lda _n");
|
||||||
|
asm("jeq %g", L0004);
|
||||||
|
|
||||||
|
asm("lda #$3F");
|
||||||
|
asm("sta sreg+1");
|
||||||
|
asm("lda #$C0");
|
||||||
|
asm("sta sreg");
|
||||||
|
asm("lda #$00");
|
||||||
|
asm("ldx #$00");
|
||||||
|
asm("jmp %g", L0005);
|
||||||
|
|
||||||
|
L0004:
|
||||||
|
asm("lda #$3F");
|
||||||
|
asm("sta sreg+1");
|
||||||
|
asm("lda #$00");
|
||||||
|
asm("sta sreg");
|
||||||
|
asm("lda #$00");
|
||||||
|
asm("ldx #$00");
|
||||||
|
|
||||||
|
L0005:
|
||||||
|
asm("sta _fp1");
|
||||||
|
asm("stx _fp1+1");
|
||||||
|
asm("ldy sreg");
|
||||||
|
asm("sty _fp1+2");
|
||||||
|
asm("ldy sreg+1");
|
||||||
|
asm("sty _fp1+3");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
n = 0;
|
||||||
|
test1();
|
||||||
|
printf("fp1:%08lx\n", fp1);
|
||||||
|
if (fp1 != 0x3f000000) failures++;
|
||||||
|
n = 0xff;
|
||||||
|
test1();
|
||||||
|
printf("fp1:%08lx\n", fp1);
|
||||||
|
if (fp1 != 0x3fc00000) failures++;
|
||||||
|
printf("failures:%d\n", failures);
|
||||||
|
return failures;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user