Allow omission of braces on multiple-statement switch cases.

This commit is contained in:
Curle 2023-04-24 03:57:58 +01:00
parent 4e47cdcaf6
commit 96f6773904
4 changed files with 32 additions and 17 deletions

View File

@ -287,6 +287,9 @@ struct FileData {
// The column that was last marked as "valid", the start of the error block if something goes wrong. // The column that was last marked as "valid", the start of the error block if something goes wrong.
long CurrentSafeColumn; 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. // The symbol currently being lexed - TokenTypes index and integer value.
struct Token CurrentSymbol; struct Token CurrentSymbol;
// The function currently being parsed - null if in global scope or if finished. // The function currently being parsed - null if in global scope or if finished.

View File

@ -39,10 +39,13 @@ static int OperatorPrecedence(int Token) {
int Prec = Precedence[Token]; int Prec = Precedence[Token];
if (Prec == 0 || Token >= PPMM_PLUS) { if (Prec == 0 || Token >= PPMM_PLUS) {
if (Token == TY_IDENTIFIER) if (Token == TY_IDENTIFIER) {
DieMessage("Attempting to determine operator precedence of identifier", CurrentIdentifier); 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; return Prec;
@ -259,9 +262,8 @@ struct ASTNode* ParsePrimary(void) {
return Node; return Node;
} }
Tokenise(); Tokenise();
Safe();
return Node; return Node;
} }
@ -286,7 +288,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
// int LeftType, RightType; // int LeftType, RightType;
int NodeType, OpType; int NodeType, OpType;
fflush(stdout); Safe();
LeftNode = PrefixStatement(); LeftNode = PrefixStatement();
NodeType = CurrentFile->CurrentSymbol.type; NodeType = CurrentFile->CurrentSymbol.type;
@ -296,14 +298,19 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
return LeftNode; return LeftNode;
} }
Safe();
while ((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) || while ((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) ||
(IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) { (IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) {
Tokenise(); Tokenise();
if (CurrentFile->CurrentSymbol.type == LI_RPARE) if (CurrentFile->CurrentSymbol.type == LI_RPARE)
break; break;
Safe();
RightNode = ParsePrecedenceASTNode(Precedence[NodeType]); RightNode = ParsePrecedenceASTNode(Precedence[NodeType]);
Safe();
/** /**
* While parsing this node, we may need to widen some types. * While parsing this node, we may need to widen some types.
* This requires a few functions and checks. * 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); printf("\t\tBranch leads to here, type %s/%d\r\n", TokenNames[CurrentFile->CurrentSymbol.type], CurrentFile->CurrentSymbol.type);
switch (CurrentFile->CurrentSymbol.type) { switch (CurrentFile->CurrentSymbol.type) {
case LI_LBRAC: case LI_LBRAC:
Tokenise();
Node = ParseCompound(); Node = ParseCompound();
VerifyToken(LI_RBRAC, "}");
return Node; return Node;
case TY_CHAR: case TY_CHAR:
case TY_LONG: case TY_LONG:
@ -541,10 +550,6 @@ struct ASTNode* ParseStatement(void) {
struct ASTNode* ParseCompound() { struct ASTNode* ParseCompound() {
struct ASTNode* Left = NULL, * Tree; struct ASTNode* Left = NULL, * Tree;
// Compound statements are defined by comprising
// multiple statements inside { a bracket block }
VerifyToken(LI_LBRAC, "{");
while (1) { while (1) {
printf("\tNew branch in compound\n"); printf("\tNew branch in compound\n");
@ -563,7 +568,11 @@ struct ASTNode* ParseCompound() {
} }
if (CurrentFile->CurrentSymbol.type == LI_RBRAC) { 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; return Left;
} }
} }
@ -592,7 +601,6 @@ void ParseGlobals() {
printf("Parsing global definitions\r\n"); printf("Parsing global definitions\r\n");
while (1) { while (1) {
// We loop early if there's a struct, and since a struct may be the last // 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 // thing in a file, we need to check for eof before anything else
if (CurrentFile->CurrentSymbol.type == LI_EOF) if (CurrentFile->CurrentSymbol.type == LI_EOF)

View File

@ -292,7 +292,9 @@ struct ASTNode* ParseFunction(int Type) {
CurrentFile->FunctionEntry = OldFunction; CurrentFile->FunctionEntry = OldFunction;
CurrentFile->CurrentLoopDepth = 0; CurrentFile->CurrentLoopDepth = 0;
VerifyToken(LI_LBRAC, "{");
Tree = ParseCompound(); Tree = ParseCompound();
VerifyToken(LI_RBRAC, "}");
if (Type != RET_VOID) { if (Type != RET_VOID) {
// Functions with one statement have no composite node, so we have to check // Functions with one statement have no composite node, so we have to check
@ -550,6 +552,7 @@ struct ASTNode* SwitchStatement() {
int ASTOp, casevalue; int ASTOp, casevalue;
printf("\tParsing switch statement\n"); printf("\tParsing switch statement\n");
CurrentFile->SwitchStatement = true;
// Skip switch( // Skip switch(
Tokenise(); Tokenise();
@ -615,7 +618,7 @@ struct ASTNode* SwitchStatement() {
VerifyToken(LI_COLON, ":"); VerifyToken(LI_COLON, ":");
Safe(); Safe();
left = ParseStatement(); left = ParseCompound();
OptionallyConsume(LI_SEMIC); OptionallyConsume(LI_SEMIC);
cases++; cases++;
Safe(); Safe();
@ -641,6 +644,7 @@ struct ASTNode* SwitchStatement() {
// Consume the right brace immediately // Consume the right brace immediately
VerifyToken(LI_RBRAC, "}"); VerifyToken(LI_RBRAC, "}");
CurrentFile->SwitchStatement = false;
return root; return root;
} }
@ -668,8 +672,8 @@ struct ASTNode* SwitchStatement() {
* @return the AST of this statement * @return the AST of this statement
*/ */
struct ASTNode* BreakStatement() { struct ASTNode* BreakStatement() {
if (CurrentFile->CurrentLoopDepth == 0) if (CurrentFile->CurrentLoopDepth == 0 && !CurrentFile->SwitchStatement)
Die("Unable to break without a loop"); Die("Unable to break without a loop or switch statement");
Tokenise(); Tokenise();

View File

@ -11,9 +11,9 @@ int :: main() {
case 1: { case 1: {
y = 5; y = 5;
break; } break; }
case 2: { case 2:
y = 7; y = 7;
break; } break;
case 3: case 3:
y = 9; y = 9;
default: default: