Allow omission of braces on multiple-statement switch cases.
This commit is contained in:
parent
4e47cdcaf6
commit
96f6773904
|
@ -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.
|
||||||
|
|
32
src/Parser.c
32
src/Parser.c
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user