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.
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.

View File

@ -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)

View File

@ -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();

View File

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