diff --git a/include/Defs.h b/include/Defs.h index 168302a..f747950 100644 --- a/include/Defs.h +++ b/include/Defs.h @@ -287,6 +287,9 @@ struct FileData { // The column that was last marked as "valid", the start of the error block if something goes wrong. long CurrentSafeColumn; + // Whether or not we are currently parsing a switch statement - changes the behavior of compound statements! + bool SwitchStatement; + // The symbol currently being lexed - TokenTypes index and integer value. struct Token CurrentSymbol; // The function currently being parsed - null if in global scope or if finished. diff --git a/src/Parser.c b/src/Parser.c index 6743e64..b7d9c88 100644 --- a/src/Parser.c +++ b/src/Parser.c @@ -39,10 +39,13 @@ static int OperatorPrecedence(int Token) { int Prec = Precedence[Token]; if (Prec == 0 || Token >= PPMM_PLUS) { - if (Token == TY_IDENTIFIER) - DieMessage("Attempting to determine operator precedence of identifier", CurrentIdentifier); + if (Token == TY_IDENTIFIER) { + ErrorReport("Attempting to determine operator precedence of identifier %s\n", CurrentIdentifier); + exit(1); + } - DieMessage("Attempting to determine operator precedence of an EOF or INT literal", TokenNames[Token]); + ErrorReport("Attempting to determine operator precedence of an EOF or INT literal: %s\n", TokenNames[Token]); + exit(1); } return Prec; @@ -259,9 +262,8 @@ struct ASTNode* ParsePrimary(void) { return Node; } - Tokenise(); - + Safe(); return Node; } @@ -286,7 +288,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) { // int LeftType, RightType; int NodeType, OpType; - fflush(stdout); + Safe(); LeftNode = PrefixStatement(); NodeType = CurrentFile->CurrentSymbol.type; @@ -296,14 +298,19 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) { return LeftNode; } + Safe(); + while ((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) || (IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) { Tokenise(); if (CurrentFile->CurrentSymbol.type == LI_RPARE) break; + Safe(); + RightNode = ParsePrecedenceASTNode(Precedence[NodeType]); + Safe(); /** * While parsing this node, we may need to widen some types. * This requires a few functions and checks. @@ -483,7 +490,9 @@ struct ASTNode* ParseStatement(void) { printf("\t\tBranch leads to here, type %s/%d\r\n", TokenNames[CurrentFile->CurrentSymbol.type], CurrentFile->CurrentSymbol.type); switch (CurrentFile->CurrentSymbol.type) { case LI_LBRAC: + Tokenise(); Node = ParseCompound(); + VerifyToken(LI_RBRAC, "}"); return Node; case TY_CHAR: case TY_LONG: @@ -541,10 +550,6 @@ struct ASTNode* ParseStatement(void) { struct ASTNode* ParseCompound() { struct ASTNode* Left = NULL, * Tree; - // Compound statements are defined by comprising - // multiple statements inside { a bracket block } - VerifyToken(LI_LBRAC, "{"); - while (1) { printf("\tNew branch in compound\n"); @@ -563,7 +568,11 @@ struct ASTNode* ParseCompound() { } if (CurrentFile->CurrentSymbol.type == LI_RBRAC) { - VerifyToken(LI_RBRAC, "}"); + fflush(stdout); + return Left; + } + + if (CurrentFile->SwitchStatement && (CurrentFile->CurrentSymbol.type == KW_CASE || CurrentFile->CurrentSymbol.type == KW_DEFAULT)) { return Left; } } @@ -592,7 +601,6 @@ void ParseGlobals() { printf("Parsing global definitions\r\n"); while (1) { - // We loop early if there's a struct, and since a struct may be the last // thing in a file, we need to check for eof before anything else if (CurrentFile->CurrentSymbol.type == LI_EOF) diff --git a/src/Statements.c b/src/Statements.c index ad9a9aa..1751d5c 100644 --- a/src/Statements.c +++ b/src/Statements.c @@ -292,7 +292,9 @@ struct ASTNode* ParseFunction(int Type) { CurrentFile->FunctionEntry = OldFunction; CurrentFile->CurrentLoopDepth = 0; + VerifyToken(LI_LBRAC, "{"); Tree = ParseCompound(); + VerifyToken(LI_RBRAC, "}"); if (Type != RET_VOID) { // Functions with one statement have no composite node, so we have to check @@ -550,6 +552,7 @@ struct ASTNode* SwitchStatement() { int ASTOp, casevalue; printf("\tParsing switch statement\n"); + CurrentFile->SwitchStatement = true; // Skip switch( Tokenise(); @@ -615,7 +618,7 @@ struct ASTNode* SwitchStatement() { VerifyToken(LI_COLON, ":"); Safe(); - left = ParseStatement(); + left = ParseCompound(); OptionallyConsume(LI_SEMIC); cases++; Safe(); @@ -641,6 +644,7 @@ struct ASTNode* SwitchStatement() { // Consume the right brace immediately VerifyToken(LI_RBRAC, "}"); + CurrentFile->SwitchStatement = false; return root; } @@ -668,8 +672,8 @@ struct ASTNode* SwitchStatement() { * @return the AST of this statement */ struct ASTNode* BreakStatement() { - if (CurrentFile->CurrentLoopDepth == 0) - Die("Unable to break without a loop"); + if (CurrentFile->CurrentLoopDepth == 0 && !CurrentFile->SwitchStatement) + Die("Unable to break without a loop or switch statement"); Tokenise(); diff --git a/tests/switch.er b/tests/switch.er index 2afc4bf..b25ef74 100644 --- a/tests/switch.er +++ b/tests/switch.er @@ -11,9 +11,9 @@ int :: main() { case 1: { y = 5; break; } - case 2: { + case 2: y = 7; - break; } + break; case 3: y = 9; default: