Fix break statement stack leftover

This commit is contained in:
Vasilii Rogin
2025-06-12 22:17:29 +03:00
parent fb17b9a933
commit 2266ed2518
7 changed files with 122 additions and 11 deletions
+3
View File
@@ -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
+4 -10
View File
@@ -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
View File
@@ -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"
@@ -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