From cadf8012f6b861d67b5e68a54f7b65b9fe71c633 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 10 Dec 2023 15:43:24 +0800 Subject: [PATCH] Improved error recovery with type cast and sizeof. --- src/cc65/declare.c | 31 +++++++++++++++++++++++----- src/cc65/declare.h | 2 +- src/cc65/expr.c | 20 +----------------- src/cc65/scanner.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ src/cc65/scanner.h | 5 +++++ src/cc65/typeconv.c | 8 +------- 6 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 62c2bdfa3..fdc481ce1 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -2166,20 +2166,41 @@ static void DirectDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode) Type* ParseType (Type* T) -/* Parse a complete type specification */ +/* Parse a complete type specification in parentheses */ { DeclSpec Spec; Declarator Decl; + int NeedClean = -1; + + /* Skip the left paren */ + NextToken (); /* Get a type without a default */ InitDeclSpec (&Spec); ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE); - /* Parse additional declarators */ - ParseDecl (&Spec, &Decl, DM_NO_IDENT); + /* Only parse further if there is a type specifier */ + 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 */ - TypeCopy (T, Decl.Type); + /* Copy the type to the target buffer */ + 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 T; diff --git a/src/cc65/declare.h b/src/cc65/declare.h index 6185a111e..4cfc48c68 100644 --- a/src/cc65/declare.h +++ b/src/cc65/declare.h @@ -135,7 +135,7 @@ typedef enum { Type* ParseType (Type* Type); -/* Parse a complete type specification */ +/* Parse a complete type specification in parentheses */ int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode); /* Parse a variable, type or function declarator. Return -1 if this stops at diff --git a/src/cc65/expr.c b/src/cc65/expr.c index a0902ed82..963ea8bd6 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -1415,24 +1415,8 @@ static void Primary (ExprDesc* E) ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO); if ((Spec.Flags & DS_TYPE_MASK) != DS_NONE) { - /* Recognized but not supported */ Error ("Mixed declarations and code are not supported in cc65"); - - while (CurTok.Tok != TOK_SEMI) { - Declarator Decl; - - /* Parse one declaration */ - ParseDecl (&Spec, &Decl, DM_IDENT_OR_EMPTY); - if (CurTok.Tok == TOK_ASSIGN) { - NextToken (); - ParseInit (Decl.Type); - } - if (CurTok.Tok == TOK_COMMA) { - NextToken (); - } else { - break; - } - } + SmartErrorSkip (0); } else { Error ("Expression expected"); E->Flags |= E_EVAL_MAYBE_UNUSED; @@ -2089,9 +2073,7 @@ void hie10 (ExprDesc* Expr) NextToken (); if (TypeSpecAhead ()) { Type T[MAXTYPELEN]; - NextToken (); Size = ExprCheckedSizeOf (ParseType (T)); - ConsumeRParen (); } else { /* Remember the output queue pointer */ CodeMark Mark; diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index 6af9bc4be..6b5235679 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -1392,6 +1392,55 @@ ExitPoint: +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) /* 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. diff --git a/src/cc65/scanner.h b/src/cc65/scanner.h index 808b96c5e..ccf3a8805 100644 --- a/src/cc65/scanner.h +++ b/src/cc65/scanner.h @@ -339,6 +339,11 @@ int SmartErrorSkip (int TillEnd); ** 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); /* 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. diff --git a/src/cc65/typeconv.c b/src/cc65/typeconv.c index e5b6749d6..76658502d 100644 --- a/src/cc65/typeconv.c +++ b/src/cc65/typeconv.c @@ -321,15 +321,9 @@ void TypeCast (ExprDesc* Expr) { Type NewType[MAXTYPELEN]; - /* Skip the left paren */ - NextToken (); - - /* Read the type */ + /* Read the type enclosed in parentheses */ ParseType (NewType); - /* Closing paren */ - ConsumeRParen (); - /* Read the expression we have to cast */ hie10 (Expr);