Implement break/continue statements.
This commit is contained in:
parent
4e62bbdc51
commit
b7f8d8666e
|
@ -90,6 +90,8 @@ enum TokenTypes {
|
||||||
TY_VOID, // "void" type keyword
|
TY_VOID, // "void" type keyword
|
||||||
|
|
||||||
KW_FUNC, // :: function name incoming
|
KW_FUNC, // :: function name incoming
|
||||||
|
KW_BREAK, // "break" keyword
|
||||||
|
KW_CONTINUE, // "continue" keyword
|
||||||
|
|
||||||
KW_PRINT,
|
KW_PRINT,
|
||||||
KW_IF,
|
KW_IF,
|
||||||
|
@ -176,6 +178,8 @@ enum SyntaxOps {
|
||||||
OP_PRINT, // Print statement
|
OP_PRINT, // Print statement
|
||||||
|
|
||||||
OP_FUNC = 40, // Define a function
|
OP_FUNC = 40, // Define a function
|
||||||
|
OP_BREAK, // Break out of the loop
|
||||||
|
OP_CONTINUE, // Continue the loop
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -271,6 +275,8 @@ struct FileData {
|
||||||
long CurrentLine;
|
long CurrentLine;
|
||||||
// The column of the file we are currently working on, -1 if it is finished
|
// The column of the file we are currently working on, -1 if it is finished
|
||||||
long CurrentColumn;
|
long CurrentColumn;
|
||||||
|
// The depth of the loop currently being parsed.
|
||||||
|
long CurrentLoopDepth;
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -434,7 +440,11 @@ struct ASTNode* CallFunction();
|
||||||
|
|
||||||
struct ASTNode* ReturnStatement();
|
struct ASTNode* ReturnStatement();
|
||||||
|
|
||||||
int ParseOptionalPointer(struct SymbolTableEntry** Composite);
|
struct ASTNode* BreakStatement();
|
||||||
|
|
||||||
|
struct ASTNode* ContinueStatement();
|
||||||
|
|
||||||
|
int ReadTypeOrKeyword(struct SymbolTableEntry** Composite);
|
||||||
|
|
||||||
int ValueAt(int Type);
|
int ValueAt(int Type);
|
||||||
|
|
||||||
|
@ -503,7 +513,7 @@ void DieBinary(char* Error, int Number);
|
||||||
* * * * C O D E G E N E R A T I O N * * * *
|
* * * * C O D E G E N E R A T I O N * * * *
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
int AssembleTree(struct ASTNode* Node, int Register, int ParentOp);
|
int AssembleTree(struct ASTNode* Node, int Register, int LoopBeginLabel, int LoopEndLabel, int ParentOp);
|
||||||
|
|
||||||
void DeallocateAllRegisters();
|
void DeallocateAllRegisters();
|
||||||
|
|
||||||
|
@ -583,7 +593,7 @@ int AsCompareJmp(int Operation, int RegisterLeft, int RegisterRight, int Label);
|
||||||
|
|
||||||
int AsCompare(int Operation, int RegisterLeft, int RegisterRight);
|
int AsCompare(int Operation, int RegisterLeft, int RegisterRight);
|
||||||
|
|
||||||
int AsIf(struct ASTNode* Node);
|
int AsIf(struct ASTNode* Node, int LoopStartLabel, int LoopEndLabel);
|
||||||
|
|
||||||
int NewLabel(void);
|
int NewLabel(void);
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ static int Started = 0;
|
||||||
* @return dependant on the Node. Typically the Register that stores the result of the Node's operation.
|
* @return dependant on the Node. Typically the Register that stores the result of the Node's operation.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
int AssembleTree(struct ASTNode* Node, int Register, int LoopBeginLabel, int LoopEndLabel, int ParentOp) {
|
||||||
int LeftVal, RightVal;
|
int LeftVal, RightVal;
|
||||||
if (!Started && OptDumpTree)
|
if (!Started && OptDumpTree)
|
||||||
DumpTree(Node, 0);
|
DumpTree(Node, 0);
|
||||||
|
@ -73,15 +73,15 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
printf("Current operation: %d\r\n", Node->Operation);
|
printf("Current operation: %d\r\n", Node->Operation);
|
||||||
switch (Node->Operation) {
|
switch (Node->Operation) {
|
||||||
case OP_IF:
|
case OP_IF:
|
||||||
return AsIf(Node);
|
return AsIf(Node, LoopBeginLabel, LoopEndLabel);
|
||||||
|
|
||||||
case OP_LOOP:
|
case OP_LOOP:
|
||||||
return AsWhile(Node);
|
return AsWhile(Node);
|
||||||
|
|
||||||
case OP_COMP:
|
case OP_COMP:
|
||||||
AssembleTree(Node->Left, -1, Node->Operation);
|
AssembleTree(Node->Left, -1, -1, -1, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
AssembleTree(Node->Right, -1, Node->Operation);
|
AssembleTree(Node->Right, -1, -1, -1, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -90,17 +90,17 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
|
|
||||||
case OP_FUNC:
|
case OP_FUNC:
|
||||||
AsFunctionPreamble(Node->Symbol);
|
AsFunctionPreamble(Node->Symbol);
|
||||||
AssembleTree(Node->Left, -1, Node->Operation);
|
AssembleTree(Node->Left, -1, -1, -1, Node->Operation);
|
||||||
AsFunctionEpilogue(Node->Symbol);
|
AsFunctionEpilogue(Node->Symbol);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Node->Left)
|
if (Node->Left)
|
||||||
LeftVal = AssembleTree(Node->Left, -1, Node->Operation);
|
LeftVal = AssembleTree(Node->Left, -1, -1, -1, Node->Operation);
|
||||||
|
|
||||||
if (Node->Right)
|
if (Node->Right)
|
||||||
RightVal = AssembleTree(Node->Right, LeftVal, Node->Operation);
|
RightVal = AssembleTree(Node->Right, LeftVal, -1, -1, Node->Operation);
|
||||||
|
|
||||||
switch (Node->Operation) {
|
switch (Node->Operation) {
|
||||||
case OP_ADD:
|
case OP_ADD:
|
||||||
|
@ -130,6 +130,14 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
RightVal = AsLoad(Node->Size);
|
RightVal = AsLoad(Node->Size);
|
||||||
return AsMul(LeftVal, RightVal);
|
return AsMul(LeftVal, RightVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_BREAK:
|
||||||
|
AsJmp(LoopEndLabel);
|
||||||
|
return -1;
|
||||||
|
case OP_CONTINUE:
|
||||||
|
AsJmp(LoopBeginLabel);
|
||||||
|
return -1;
|
||||||
|
|
||||||
case OP_ADDRESS:
|
case OP_ADDRESS:
|
||||||
return AsAddr(Node->Symbol);
|
return AsAddr(Node->Symbol);
|
||||||
|
|
||||||
|
@ -353,7 +361,7 @@ int AsAlignMemory(int Type, int Offset, int Direction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble an If statement
|
// Assemble an If statement
|
||||||
int AsIf(struct ASTNode* Node) {
|
int AsIf(struct ASTNode* Node, int LoopStartLabel, int LoopEndLabel) {
|
||||||
int FalseLabel, EndLabel;
|
int FalseLabel, EndLabel;
|
||||||
|
|
||||||
FalseLabel = NewLabel();
|
FalseLabel = NewLabel();
|
||||||
|
@ -362,11 +370,11 @@ int AsIf(struct ASTNode* Node) {
|
||||||
|
|
||||||
|
|
||||||
// Left is the condition
|
// Left is the condition
|
||||||
AssembleTree(Node->Left, FalseLabel, Node->Operation);
|
AssembleTree(Node->Left, FalseLabel, -1, -1, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
// Middle is the true block
|
// Middle is the true block
|
||||||
AssembleTree(Node->Middle, -1, Node->Operation);
|
AssembleTree(Node->Middle, -1, LoopStartLabel, LoopEndLabel, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
// Right is the optional else
|
// Right is the optional else
|
||||||
|
@ -376,7 +384,7 @@ int AsIf(struct ASTNode* Node) {
|
||||||
AsLabel(FalseLabel);
|
AsLabel(FalseLabel);
|
||||||
|
|
||||||
if (Node->Right) {
|
if (Node->Right) {
|
||||||
AssembleTree(Node->Right, -1, Node->Operation);
|
AssembleTree(Node->Right, -1, LoopStartLabel, LoopEndLabel, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
AsLabel(EndLabel);
|
AsLabel(EndLabel);
|
||||||
}
|
}
|
||||||
|
@ -467,14 +475,14 @@ int AsWhile(struct ASTNode* Node) {
|
||||||
AsLabel(BodyLabel);
|
AsLabel(BodyLabel);
|
||||||
|
|
||||||
// Assemble the condition - this should include a jump to end!
|
// Assemble the condition - this should include a jump to end!
|
||||||
AssembleTree(Node->Left, BreakLabel, Node->Operation);
|
AssembleTree(Node->Left, BreakLabel, BodyLabel, BreakLabel, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
// Assemble the body
|
// Assemble the body
|
||||||
AssembleTree(Node->Right, -1, Node->Operation);
|
AssembleTree(Node->Right, -1, BodyLabel, BreakLabel, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
// Jump back to the body - as we've already failed the condition check if we get here
|
// Jump back to the body - as awe've already failed the condition check if we get here
|
||||||
AsJmp(BodyLabel);
|
AsJmp(BodyLabel);
|
||||||
|
|
||||||
// Set up the label to break out of the loop.
|
// Set up the label to break out of the loop.
|
||||||
|
@ -877,7 +885,7 @@ int AsCallWrapper(struct ASTNode* Node) {
|
||||||
int Register, Args = 0;
|
int Register, Args = 0;
|
||||||
|
|
||||||
while (CompositeTree) {
|
while (CompositeTree) {
|
||||||
Register = AssembleTree(CompositeTree->Right, -1, CompositeTree->Operation);
|
Register = AssembleTree(CompositeTree->Right, -1, -1, -1, CompositeTree->Operation);
|
||||||
AsCopyArgs(Register, CompositeTree->Size);
|
AsCopyArgs(Register, CompositeTree->Size);
|
||||||
if (Args == 0) Args = CompositeTree->Size;
|
if (Args == 0) Args = CompositeTree->Size;
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
|
|
|
@ -67,6 +67,12 @@ void DumpTree(struct ASTNode* Node, int level) {
|
||||||
case OP_COMP:
|
case OP_COMP:
|
||||||
fprintf(stdout, "\n\n");
|
fprintf(stdout, "\n\n");
|
||||||
return;
|
return;
|
||||||
|
case OP_CONTINUE:
|
||||||
|
fprintf(stdout, "OP_CONTINUE\n");
|
||||||
|
return;
|
||||||
|
case OP_BREAK:
|
||||||
|
fprintf(stdout, "OP_BREAK\n");
|
||||||
|
return;
|
||||||
case OP_FUNC:
|
case OP_FUNC:
|
||||||
fprintf(stdout, "OP_FUNC %s\n", Node->Symbol->Name);
|
fprintf(stdout, "OP_FUNC %s\n", Node->Symbol->Name);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -288,9 +288,17 @@ static int ReadKeyword(char* Str) {
|
||||||
return KW_ALIAS;
|
return KW_ALIAS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
if (!strcmp(Str, "break"))
|
||||||
|
return KW_BREAK;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
if (!strcmp(Str, "char"))
|
if (!strcmp(Str, "char"))
|
||||||
return TY_CHAR;
|
return TY_CHAR;
|
||||||
|
if (!strcmp(Str, "continue"))
|
||||||
|
return KW_CONTINUE;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
|
|
17
src/Parser.c
17
src/Parser.c
|
@ -172,7 +172,7 @@ int ReadAlias(struct SymbolTableEntry** Composite) {
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
Type = ParseOptionalPointer(Composite);
|
Type = ReadTypeOrKeyword(Composite);
|
||||||
|
|
||||||
if (FindAlias(CurrentIdentifier) != NULL)
|
if (FindAlias(CurrentIdentifier) != NULL)
|
||||||
DieMessage("Redefinition of type", CurrentIdentifier);
|
DieMessage("Redefinition of type", CurrentIdentifier);
|
||||||
|
@ -481,7 +481,7 @@ struct ASTNode* ParseStatement(void) {
|
||||||
case TY_LONG:
|
case TY_LONG:
|
||||||
case TY_INT:
|
case TY_INT:
|
||||||
printf("\t\tNew Variable: %s\n", CurrentIdentifier);
|
printf("\t\tNew Variable: %s\n", CurrentIdentifier);
|
||||||
Type = ParseOptionalPointer(NULL);
|
Type = ReadTypeOrKeyword(NULL);
|
||||||
VerifyToken(TY_IDENTIFIER, "ident");
|
VerifyToken(TY_IDENTIFIER, "ident");
|
||||||
BeginVariableDeclaration(Type, NULL, SC_LOCAL);
|
BeginVariableDeclaration(Type, NULL, SC_LOCAL);
|
||||||
VerifyToken(LI_SEMIC, ";"); // TODO: single line assignment?
|
VerifyToken(LI_SEMIC, ";"); // TODO: single line assignment?
|
||||||
|
@ -499,6 +499,12 @@ struct ASTNode* ParseStatement(void) {
|
||||||
case KW_RETURN:
|
case KW_RETURN:
|
||||||
return ReturnStatement();
|
return ReturnStatement();
|
||||||
|
|
||||||
|
case KW_BREAK:
|
||||||
|
return BreakStatement();
|
||||||
|
|
||||||
|
case KW_CONTINUE:
|
||||||
|
return ContinueStatement();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ParsePrecedenceASTNode(0);
|
ParsePrecedenceASTNode(0);
|
||||||
}
|
}
|
||||||
|
@ -534,7 +540,8 @@ struct ASTNode* ParseCompound() {
|
||||||
Tree = ParseStatement();
|
Tree = ParseStatement();
|
||||||
|
|
||||||
if (Tree && (Tree->Operation == OP_PRINT || Tree->Operation == OP_ASSIGN
|
if (Tree && (Tree->Operation == OP_PRINT || Tree->Operation == OP_ASSIGN
|
||||||
|| Tree->Operation == OP_RET || Tree->Operation == OP_CALL))
|
|| Tree->Operation == OP_RET || Tree->Operation == OP_CALL
|
||||||
|
|| Tree->Operation == OP_BREAK || Tree->Operation == OP_CONTINUE))
|
||||||
VerifyToken(LI_SEMIC, ";");
|
VerifyToken(LI_SEMIC, ";");
|
||||||
|
|
||||||
if (Tree) {
|
if (Tree) {
|
||||||
|
@ -581,7 +588,7 @@ void ParseGlobals() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
printf("New definition incoming..\r\n\n");
|
printf("New definition incoming..\r\n\n");
|
||||||
Type = ParseOptionalPointer(&Composite);
|
Type = ReadTypeOrKeyword(&Composite);
|
||||||
|
|
||||||
//TODO: converge pathways on this block?
|
//TODO: converge pathways on this block?
|
||||||
if (CurrentFile->CurrentSymbol.type == KW_FUNC) {
|
if (CurrentFile->CurrentSymbol.type == KW_FUNC) {
|
||||||
|
@ -607,7 +614,7 @@ void ParseGlobals() {
|
||||||
Tree = ParseFunction(Type);
|
Tree = ParseFunction(Type);
|
||||||
if (Tree && CurrentFile->AllowDefinitions) {
|
if (Tree && CurrentFile->AllowDefinitions) {
|
||||||
printf("\nBeginning assembler creation of new function %s\n", Tree->Symbol->Name);
|
printf("\nBeginning assembler creation of new function %s\n", Tree->Symbol->Name);
|
||||||
AssembleTree(Tree, -1, 0);
|
AssembleTree(Tree, -1, -1, -1, 0);
|
||||||
FreeLocals();
|
FreeLocals();
|
||||||
} else {
|
} else {
|
||||||
printf("\nFunction prototype saved\r\n");
|
printf("\nFunction prototype saved\r\n");
|
||||||
|
|
|
@ -71,7 +71,7 @@ int ValueAt(int Type) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
|
int ReadTypeOrKeyword(struct SymbolTableEntry** Composite) {
|
||||||
|
|
||||||
int Type;
|
int Type;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Stor
|
||||||
PrototypePointer = FunctionSymbol->Start;
|
PrototypePointer = FunctionSymbol->Start;
|
||||||
|
|
||||||
while (CurrentFile->CurrentSymbol.type != End) {
|
while (CurrentFile->CurrentSymbol.type != End) {
|
||||||
TokenType = ParseOptionalPointer(&Composite);
|
TokenType = ReadTypeOrKeyword(&Composite);
|
||||||
VerifyToken(TY_IDENTIFIER, "identifier");
|
VerifyToken(TY_IDENTIFIER, "identifier");
|
||||||
|
|
||||||
printf("\tReading a new element: %s of type %d, scope %s\n", CurrentIdentifier, TokenType, ScopeNames[Storage]);
|
printf("\tReading a new element: %s of type %d, scope %s\n", CurrentIdentifier, TokenType, ScopeNames[Storage]);
|
||||||
|
@ -291,6 +291,7 @@ struct ASTNode* ParseFunction(int Type) {
|
||||||
|
|
||||||
CurrentFile->FunctionEntry = OldFunction;
|
CurrentFile->FunctionEntry = OldFunction;
|
||||||
|
|
||||||
|
CurrentFile->CurrentLoopDepth = 0;
|
||||||
Tree = ParseCompound();
|
Tree = ParseCompound();
|
||||||
|
|
||||||
if (Type != RET_VOID) {
|
if (Type != RET_VOID) {
|
||||||
|
@ -433,7 +434,9 @@ struct ASTNode* WhileStatement() {
|
||||||
|
|
||||||
VerifyToken(LI_RPARE, ")");
|
VerifyToken(LI_RPARE, ")");
|
||||||
|
|
||||||
|
CurrentFile->CurrentLoopDepth++;
|
||||||
Body = ParseCompound();
|
Body = ParseCompound();
|
||||||
|
CurrentFile->CurrentLoopDepth--;
|
||||||
|
|
||||||
return ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Body, NULL, 0);
|
return ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Body, NULL, 0);
|
||||||
}
|
}
|
||||||
|
@ -489,7 +492,9 @@ struct ASTNode* ForStatement() {
|
||||||
Postop = ParseStatement();
|
Postop = ParseStatement();
|
||||||
VerifyToken(LI_RPARE, ")");
|
VerifyToken(LI_RPARE, ")");
|
||||||
|
|
||||||
|
CurrentFile->CurrentLoopDepth++;
|
||||||
Body = ParseCompound();
|
Body = ParseCompound();
|
||||||
|
CurrentFile->CurrentLoopDepth--;
|
||||||
|
|
||||||
// We need to be able to skip over the body and the postop, so we group them together.
|
// We need to be able to skip over the body and the postop, so we group them together.
|
||||||
Tree = ConstructASTNode(OP_COMP, RET_NONE, Body, NULL, Postop, NULL, 0);
|
Tree = ConstructASTNode(OP_COMP, RET_NONE, Body, NULL, Postop, NULL, 0);
|
||||||
|
@ -539,6 +544,69 @@ struct ASTNode* PrintStatement(void) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the surrounding logic for break statements
|
||||||
|
*
|
||||||
|
* They have the basic form of:
|
||||||
|
* break;
|
||||||
|
*
|
||||||
|
* If there is a loop currently being evaluated, break will insert an immediate jump to the end of the loop.
|
||||||
|
* All locals inside the loop will lose their binding at this point.
|
||||||
|
*
|
||||||
|
* It can be prototyped as the following pseudo-assembler code:
|
||||||
|
*
|
||||||
|
* while:
|
||||||
|
* check <condition>
|
||||||
|
* jne exit
|
||||||
|
* <body>
|
||||||
|
* <break>: jump exit
|
||||||
|
* jump while
|
||||||
|
* exit:
|
||||||
|
* <loop exit>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return the AST of this statement
|
||||||
|
*/
|
||||||
|
struct ASTNode* BreakStatement() {
|
||||||
|
if (CurrentFile->CurrentLoopDepth == 0)
|
||||||
|
Die("Unable to break without a loop");
|
||||||
|
|
||||||
|
Tokenise();
|
||||||
|
|
||||||
|
return ConstructASTLeaf(OP_BREAK, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the surrounding logic for continue statements
|
||||||
|
*
|
||||||
|
* They have the basic form of:
|
||||||
|
* continue;
|
||||||
|
*
|
||||||
|
* If there is a loop currently being evaluated, continue will insert an immediate jump to the start of the loop.
|
||||||
|
*
|
||||||
|
* It can be prototyped as the following pseudo-assembler code:
|
||||||
|
*
|
||||||
|
* while:
|
||||||
|
* check <condition>
|
||||||
|
* jne exit
|
||||||
|
* <body>
|
||||||
|
* <continue>: jump while
|
||||||
|
* jump while
|
||||||
|
* exit:
|
||||||
|
* <loop exit>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return the AST of this statement
|
||||||
|
*/
|
||||||
|
struct ASTNode* ContinueStatement() {
|
||||||
|
if (CurrentFile->CurrentLoopDepth == 0)
|
||||||
|
Die("Unable to break without a loop");
|
||||||
|
|
||||||
|
Tokenise();
|
||||||
|
|
||||||
|
return ConstructASTLeaf(OP_CONTINUE, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles the surrounding logic for all of the logical and semantic
|
* Handles the surrounding logic for all of the logical and semantic
|
||||||
* postfixes.
|
* postfixes.
|
||||||
|
|
21
tests/breakcontinue.er
Normal file
21
tests/breakcontinue.er
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import "tests/import/defs.eh"
|
||||||
|
|
||||||
|
int :: main() {
|
||||||
|
int x;
|
||||||
|
x = 5;
|
||||||
|
|
||||||
|
while (x < 15) {
|
||||||
|
printf("%d\n", x);
|
||||||
|
if (x =? 12) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x =? 10) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user