mirror of
https://github.com/sfall-team/sslc.git
synced 2026-07-27 16:52:49 -07:00
Fix break statement stack leftover
This commit is contained in:
@@ -348,6 +348,9 @@ There are several changes in this version of sslc which may result in problems f
|
||||
|
||||
### Changelog
|
||||
|
||||
**sfall 4.5:**
|
||||
- fixed stack leftover from the `break` statement
|
||||
|
||||
**sfall 4.4.7:**
|
||||
- added Linux & WebAssembly builds
|
||||
|
||||
|
||||
@@ -28,14 +28,11 @@ static int startOffset;
|
||||
|
||||
typedef struct {
|
||||
int startPos;
|
||||
int numBreaks;
|
||||
int numContinue;
|
||||
} LoopInfo;
|
||||
|
||||
LoopInfo loopStack[100]; // pointers to beginning of while loops
|
||||
int loopStackPos = 0;
|
||||
int breakStack[2048]; // pointers to arguments to JMP (break statements)
|
||||
int breakStackPos = 0;
|
||||
int continueStack[2048]; // pointers to arguments to JMP (continue statements)
|
||||
int continueStackPos = 0;
|
||||
|
||||
@@ -712,7 +709,6 @@ static int writeStatement(NodeList *n, int i, FILE *f) {
|
||||
writeInt(0, f);
|
||||
top = outputTell(f);
|
||||
loopStack[++loopStackPos].startPos = top;
|
||||
loopStack[loopStackPos].numBreaks = 0;
|
||||
loopStack[loopStackPos].numContinue = 0;
|
||||
i = writeExpression(n, i+1, f);
|
||||
writeOp(O_WHILE, f);
|
||||
@@ -734,9 +730,6 @@ static int writeStatement(NodeList *n, int i, FILE *f) {
|
||||
pos = outputTell(f);
|
||||
patchOffset(falseAddr+OPCODE_SIZE, pos, f);
|
||||
|
||||
for (j = 0; j < loopStack[loopStackPos].numBreaks; j++) { // for each break, change it's JMP argument to proper address
|
||||
patchOffset(breakStack[breakStackPos--] + OPCODE_SIZE, pos, f);
|
||||
}
|
||||
continueStackPos -= loopStack[loopStackPos].numContinue; // remove all "continue" pointers found in current loop from the stack,
|
||||
// this will only apply to "WHILE" loops
|
||||
loopStackPos--;
|
||||
@@ -849,9 +842,10 @@ static int writeStatement(NodeList *n, int i, FILE *f) {
|
||||
i++;
|
||||
break;
|
||||
case T_BREAK:
|
||||
loopStack[loopStackPos].numBreaks++;
|
||||
breakStack[++breakStackPos] = outputTell(f); // address will be patched to point to exit from loop
|
||||
writeInt(0, f);
|
||||
// "break" statement is only allowed inside for/foreach/while loops.
|
||||
// All of them are implemented using O_WHILE which requires stack
|
||||
// to have an address where to jump when condition is false.
|
||||
// So we just using this address to jump to the end of loop.
|
||||
writeOp(O_JMP, f);
|
||||
i++;
|
||||
break;
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
#define VERSION_BUILD 4
|
||||
#define VERSION_REV 0
|
||||
|
||||
#define VERSION_STRING "4.4.7"
|
||||
#define VERSION_STRING "4.5"
|
||||
|
||||
#ifdef BUILDING_DLL
|
||||
#define FILE_STRING "parser.dll"
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,100 @@
|
||||
procedure some_noop(variable param) begin
|
||||
end
|
||||
|
||||
procedure test_loops() begin
|
||||
variable i;
|
||||
|
||||
display_msg("Break in while loop...");
|
||||
i = 0;
|
||||
while (i < 5) do begin
|
||||
call some_noop("while loop begin");
|
||||
if i == 2 then begin
|
||||
break;
|
||||
end
|
||||
i++;
|
||||
call some_noop("while loop end");
|
||||
end
|
||||
|
||||
display_msg("Continue in while loop...");
|
||||
i = 0;
|
||||
while (i < 5) do begin
|
||||
call some_noop("while loop begin");
|
||||
if i == 2 then begin
|
||||
i += 2;
|
||||
continue;
|
||||
end
|
||||
i++;
|
||||
call some_noop("while loop end");
|
||||
end
|
||||
|
||||
display_msg("Break in for loop...");
|
||||
for (i := 0; i < 5; i++) begin
|
||||
call some_noop("for loop begin");
|
||||
if i == 2 then begin
|
||||
break;
|
||||
end
|
||||
call some_noop("for loop end");
|
||||
end
|
||||
|
||||
display_msg("Continue in for loop...");
|
||||
for (i := 0; i < 5; i++) begin
|
||||
call some_noop("for loop begin");
|
||||
if i == 2 then begin
|
||||
continue;
|
||||
end
|
||||
call some_noop("for loop end");
|
||||
end
|
||||
|
||||
variable arr := [1, 2, 3, 4, 5];
|
||||
display_msg("Break in foreach loop...");
|
||||
foreach (i in arr) begin
|
||||
call some_noop("foreach loop begin");
|
||||
if i == 2 then begin
|
||||
break;
|
||||
end
|
||||
call some_noop("foreach loop end");
|
||||
end
|
||||
display_msg("Continue in foreach loop...");
|
||||
foreach (i in arr) begin
|
||||
call some_noop("foreach loop begin");
|
||||
if i == 2 then begin
|
||||
continue;
|
||||
end
|
||||
call some_noop("foreach loop end");
|
||||
end
|
||||
|
||||
|
||||
display_msg("End of testing break/continue in loops");
|
||||
end
|
||||
|
||||
procedure test_nested_loop begin
|
||||
display_msg("Testing break in nested loop...");
|
||||
variable i, value;
|
||||
for (i := 0; i < 5; i++) begin
|
||||
display_msg("======== Item: " + i);
|
||||
if i == 1 then begin
|
||||
value = 1;
|
||||
end else begin
|
||||
value = 0;
|
||||
end
|
||||
display_msg("Value: " + value);
|
||||
if (value != 0) then begin
|
||||
display_msg("Interesting item: " + i);
|
||||
while (value != 0) do begin
|
||||
display_msg("While loop for item: " + i);
|
||||
break; // should do nothing
|
||||
display_msg("This should not be displayed for item: " + i); // Never displayed
|
||||
end
|
||||
display_msg("After while loop for item: " + i + ", value: " + value);
|
||||
end else begin
|
||||
display_msg("Not interesting item: " + i);
|
||||
end
|
||||
display_msg("End of item " + i);
|
||||
end
|
||||
display_msg("Finished testing nesting loops.");
|
||||
end
|
||||
|
||||
procedure start begin
|
||||
call test_loops();
|
||||
call test_nested_loop();
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
Set include directory: ../include
|
||||
Compiling gl_break_statement.ssl
|
||||
[Message] <gl_break_statement.ssl>:1:42: Eliminating variable id 0
|
||||
[Message] <gl_break_statement.ssl>:8:6: Using constant variable store for initializer
|
||||
[Message] <gl_break_statement.ssl>:8:8: Eating dead store to variable 0
|
||||
[Message] <gl_break_statement.ssl>:50:23: Using constant variable store for initializer
|
||||
[Message] <gl_break_statement.ssl>:50:23: Eating dead store to variable 3
|
||||
[Message] <gl_break_statement.ssl>:58:23: Using constant variable store for initializer
|
||||
[Message] <gl_break_statement.ssl>:58:23: Eating dead store to variable 6
|
||||
[Message] <gl_break_statement.ssl>:73:11: Using constant variable store for initializer
|
||||
[Message] <gl_break_statement.ssl>:73:14: Eating dead store to variable 0
|
||||
[Message] <gl_break_statement.ssl>:86:28: Eating statement hidden by return
|
||||
[Message] <none>:-1: Removing unused string 'This should not be displayed for item: ' from program stringspace
|
||||
Reference in New Issue
Block a user