fix: break and continue
This commit is contained in:
parent
c3af6bd5ca
commit
bcaf2cb3b7
4 changed files with 135 additions and 83 deletions
|
@ -1,7 +1,14 @@
|
||||||
|
# show case of 'continue' and 'break' keyword in their natural environment
|
||||||
set i to 0
|
set i to 0
|
||||||
while 1 do
|
while 1 do
|
||||||
if i > 10 then
|
if i > 10 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
if i = 5 then
|
||||||
|
set i to i+1
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
print_number(i)
|
||||||
set i to i+1
|
set i to i+1
|
||||||
end
|
end
|
||||||
|
print_number(i)
|
||||||
|
|
|
@ -360,12 +360,96 @@ int process_line(struct StateContainer* state, char* str)
|
||||||
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("recognize end state->blockStackAnchor: %d \n", state->blockStackAnchor);
|
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("recognize end state->blockStackAnchor: %d \n", state->blockStackAnchor);
|
||||||
if (state->skipping && int_stack_length(state->blockStack) == state->blockStackAnchor) {
|
if (state->skipping && int_stack_length(state->blockStack) == state->blockStackAnchor) {
|
||||||
// end of skipping
|
// end of skipping
|
||||||
|
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("end of skipping \n");
|
||||||
state->skipping = 0;
|
state->skipping = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->linePtr++;
|
state->linePtr++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct IfStatement ifStatementParsing;
|
||||||
|
byte ifRecognized = recognize_if_statement(str, &ifStatementParsing);
|
||||||
|
|
||||||
|
struct WhileStatement whileStatementParsing;
|
||||||
|
byte whileRecognized = recognize_while_statement(str, &whileStatementParsing);
|
||||||
|
|
||||||
|
if (ifRecognized) {
|
||||||
|
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("If statement recognized express (%d:%d)\n", ifStatementParsing.expression_start, ifStatementParsing.expression_stop);
|
||||||
|
|
||||||
|
int_stack_push(state->blockStack, BLOCK_IF);
|
||||||
|
if (state->skipping) {
|
||||||
|
state->linePtr++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expression to evaluate
|
||||||
|
int expressLen = ifStatementParsing.expression_stop - ifStatementParsing.expression_start;
|
||||||
|
char dest[len];
|
||||||
|
str_extract((char*) &dest, str, ifStatementParsing.expression_start, expressLen);
|
||||||
|
// printf("expression to eval in if '%s' \n", dest);
|
||||||
|
int res;
|
||||||
|
byte resType;
|
||||||
|
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
|
||||||
|
if (evalStat != 0) {
|
||||||
|
printf("Syntax error for line \"%s\"\n", str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte doFollow = convert_to_bool(resType, res);
|
||||||
|
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
|
||||||
|
|
||||||
|
if (!doFollow) {
|
||||||
|
state->blockStackAnchor = int_stack_length(state->blockStack)-1;
|
||||||
|
state->skipping = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->linePtr++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (whileRecognized) {
|
||||||
|
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("While statement recognized express (%d:%d)\n", whileStatementParsing.expression_start, whileStatementParsing.expression_stop);
|
||||||
|
|
||||||
|
int_stack_push(state->blockStack, BLOCK_WHILE);
|
||||||
|
if (state->skipping) {
|
||||||
|
state->linePtr++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expression to evaluate
|
||||||
|
int expressLen = whileStatementParsing.expression_stop - whileStatementParsing.expression_start;
|
||||||
|
char dest[len];
|
||||||
|
str_extract((char*) &dest, str, whileStatementParsing.expression_start, expressLen);
|
||||||
|
// printf("expression to eval in if '%s' \n", dest);
|
||||||
|
int res;
|
||||||
|
byte resType;
|
||||||
|
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
|
||||||
|
if (evalStat != 0) {
|
||||||
|
printf("Syntax error for line \"%s\"\n", str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
byte doFollow = convert_to_bool(resType, res);
|
||||||
|
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
|
||||||
|
|
||||||
|
if (doFollow) {
|
||||||
|
// follow the line
|
||||||
|
int_stack_push(state->loopStack, state->linePtr);
|
||||||
|
}
|
||||||
|
if (!doFollow) {
|
||||||
|
state->blockStackAnchor = int_stack_length(state->blockStack)-1;
|
||||||
|
state->skipping = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->linePtr++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (state->skipping) {
|
||||||
|
// we've finish to analyse structure-aware blocks
|
||||||
|
state->linePtr++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (recognize_word(str, "continue")) {
|
if (recognize_word(str, "continue")) {
|
||||||
int lastLoopLine;
|
int lastLoopLine;
|
||||||
if (!int_stack_pop(state->loopStack, &lastLoopLine)) {
|
if (!int_stack_pop(state->loopStack, &lastLoopLine)) {
|
||||||
|
@ -400,23 +484,13 @@ int process_line(struct StateContainer* state, char* str)
|
||||||
if (state->blockStack->data[lastLoopAnchor] == BLOCK_WHILE) break;
|
if (state->blockStack->data[lastLoopAnchor] == BLOCK_WHILE) break;
|
||||||
lastLoopAnchor--;
|
lastLoopAnchor--;
|
||||||
}
|
}
|
||||||
state->blockStackAnchor = lastLoopAnchor+1;
|
state->blockStackAnchor = lastLoopAnchor;
|
||||||
state->skipping = 1;
|
state->skipping = 1;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct IfStatement ifStatementParsing;
|
|
||||||
byte ifRecognized = recognize_if_statement(str, &ifStatementParsing);
|
|
||||||
|
|
||||||
struct WhileStatement whileStatementParsing;
|
|
||||||
byte whileRecognized = recognize_while_statement(str, &whileStatementParsing);
|
|
||||||
|
|
||||||
if (state->skipping) {
|
|
||||||
// we've finish to analyse structure-aware blocks
|
|
||||||
state->linePtr++;
|
state->linePtr++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct SetStatement setStatementParsing;
|
struct SetStatement setStatementParsing;
|
||||||
if (recognize_set_statement(str, &setStatementParsing)) {
|
if (recognize_set_statement(str, &setStatementParsing)) {
|
||||||
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) {
|
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) {
|
||||||
|
@ -454,69 +528,6 @@ int process_line(struct StateContainer* state, char* str)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifRecognized) {
|
|
||||||
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("If statement recognized express (%d:%d)\n", ifStatementParsing.expression_start, ifStatementParsing.expression_stop);
|
|
||||||
|
|
||||||
// expression to evaluate
|
|
||||||
int expressLen = ifStatementParsing.expression_stop - ifStatementParsing.expression_start;
|
|
||||||
char dest[len];
|
|
||||||
str_extract((char*) &dest, str, ifStatementParsing.expression_start, expressLen);
|
|
||||||
// printf("expression to eval in if '%s' \n", dest);
|
|
||||||
int res;
|
|
||||||
byte resType;
|
|
||||||
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
|
|
||||||
if (evalStat != 0) {
|
|
||||||
printf("Syntax error for line \"%s\"\n", str);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte doFollow = convert_to_bool(resType, res);
|
|
||||||
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
|
|
||||||
|
|
||||||
if (!doFollow) {
|
|
||||||
state->blockStackAnchor = int_stack_length(state->blockStack);
|
|
||||||
state->skipping = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int_stack_push(state->blockStack, BLOCK_IF);
|
|
||||||
|
|
||||||
state->linePtr++;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (whileRecognized) {
|
|
||||||
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("While statement recognized express (%d:%d)\n", whileStatementParsing.expression_start, whileStatementParsing.expression_stop);
|
|
||||||
|
|
||||||
// expression to evaluate
|
|
||||||
int expressLen = whileStatementParsing.expression_stop - whileStatementParsing.expression_start;
|
|
||||||
char dest[len];
|
|
||||||
str_extract((char*) &dest, str, whileStatementParsing.expression_start, expressLen);
|
|
||||||
// printf("expression to eval in if '%s' \n", dest);
|
|
||||||
int res;
|
|
||||||
byte resType;
|
|
||||||
int evalStat = evaluate(state, (char*) &dest, &res, &resType);
|
|
||||||
if (evalStat != 0) {
|
|
||||||
printf("Syntax error for line \"%s\"\n", str);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
byte doFollow = convert_to_bool(resType, res);
|
|
||||||
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Got %s, doFollow: %d \n", get_repr(resType, &res), doFollow);
|
|
||||||
|
|
||||||
if (doFollow) {
|
|
||||||
// follow the line
|
|
||||||
int_stack_push(state->loopStack, state->linePtr);
|
|
||||||
}
|
|
||||||
if (!doFollow) {
|
|
||||||
state->blockStackAnchor = int_stack_length(state->blockStack);
|
|
||||||
state->skipping = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int_stack_push(state->blockStack, BLOCK_WHILE);
|
|
||||||
|
|
||||||
state->linePtr++;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we evaluate but we dont care about the result
|
// we evaluate but we dont care about the result
|
||||||
int res;
|
int res;
|
||||||
byte resType;
|
byte resType;
|
||||||
|
|
16
src/main.c
16
src/main.c
|
@ -17,13 +17,13 @@
|
||||||
#define INTERACTIVE_FLAG 8
|
#define INTERACTIVE_FLAG 8
|
||||||
#define STDIN_EXP_FLAG 16
|
#define STDIN_EXP_FLAG 16
|
||||||
|
|
||||||
int help_mode() {
|
int help_mode(char* cmdName) {
|
||||||
char* helpStr = "Usage: langatator [options] [file]\n"
|
char* helpStr = "Usage: %s [options] [file]\n"
|
||||||
" -h --help print this usage and exit\n"
|
" -h --help print this usage and exit\n"
|
||||||
" -v --version print version information and exit\n"
|
" -v --version print version information and exit\n"
|
||||||
" -i --interactive force interactive mode\n"
|
" -i --interactive force interactive mode\n"
|
||||||
" -e --stdin-expression evaluate expression from stdin\n";
|
" -e --stdin-expression evaluate expression from stdin\n";
|
||||||
printf(helpStr);
|
printf(helpStr, cmdName);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ int file_mode(char* fileName) {
|
||||||
FILE* f = fopen(fileName, "rb");
|
FILE* f = fopen(fileName, "rb");
|
||||||
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
printf(stderr, "Cannot load file '%s' status: %d\n", fileName, f);
|
fprintf(stderr, "Cannot load file '%s' status: %d\n", fileName, (int) f);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
|
@ -56,7 +56,7 @@ int file_mode(char* fileName) {
|
||||||
|
|
||||||
char* buff = (char*) malloc(length);
|
char* buff = (char*) malloc(length);
|
||||||
if (!buff) {
|
if (!buff) {
|
||||||
printf(stderr, "Could not allocate buffer to process file content\n");
|
fprintf(stderr, "Could not allocate buffer to process file content\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (buff) {
|
if (buff) {
|
||||||
|
@ -96,7 +96,7 @@ int main (int argc, char** argv) {
|
||||||
}
|
}
|
||||||
// no flag match
|
// no flag match
|
||||||
if (str_starts_with("--", argv[i])) {
|
if (str_starts_with("--", argv[i])) {
|
||||||
printf(stderr, "Invalid flag '%s'\n", argv[i]);
|
fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
nonFlagArgumentCount++;
|
nonFlagArgumentCount++;
|
||||||
|
@ -104,11 +104,11 @@ int main (int argc, char** argv) {
|
||||||
}
|
}
|
||||||
if (nonFlagArgumentCount == 1) return file_mode(argv[nonFlagArgumentPos]);
|
if (nonFlagArgumentCount == 1) return file_mode(argv[nonFlagArgumentPos]);
|
||||||
|
|
||||||
if (flags & HELP_FLAG) return help_mode();
|
if (flags & HELP_FLAG) return help_mode(cmdName);
|
||||||
if (flags & VERSION_FLAG) return version_mode();
|
if (flags & VERSION_FLAG) return version_mode();
|
||||||
if (flags & INTERACTIVE_FLAG) return interactive_mode();
|
if (flags & INTERACTIVE_FLAG) return interactive_mode();
|
||||||
if (flags & STDIN_EXP_FLAG) return stdin_expression_mode();
|
if (flags & STDIN_EXP_FLAG) return stdin_expression_mode();
|
||||||
|
|
||||||
help_mode();
|
help_mode(cmdName);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,4 +115,38 @@ void test_line_processing()
|
||||||
assert(!state2->skipping);
|
assert(!state2->skipping);
|
||||||
printf("got i: %d \n", var_store_get_int(state2->varStore, "i"));
|
printf("got i: %d \n", var_store_get_int(state2->varStore, "i"));
|
||||||
assert(9 == var_store_get_int(state2->varStore, "i"));
|
assert(9 == var_store_get_int(state2->varStore, "i"));
|
||||||
|
|
||||||
|
// test break keyword
|
||||||
|
char* lines5 = "set i to 0\n"
|
||||||
|
"while 1 do\n"
|
||||||
|
" if (i = 10) then\n"
|
||||||
|
" break\n"
|
||||||
|
" end\n"
|
||||||
|
" set i to i+1\n"
|
||||||
|
"end\n";
|
||||||
|
process_script(state2, lines5);
|
||||||
|
|
||||||
|
assert(!state2->skipping);
|
||||||
|
printf("got i: %d \n", var_store_get_int(state2->varStore, "i"));
|
||||||
|
assert(10 == var_store_get_int(state2->varStore, "i"));
|
||||||
|
|
||||||
|
// test continue keyword
|
||||||
|
char* lines6 = "set sum to 0\n"
|
||||||
|
"set i to 0\n"
|
||||||
|
"while 1 do\n"
|
||||||
|
" if (i = 5) then\n"
|
||||||
|
" set i to i+1\n"
|
||||||
|
" continue\n"
|
||||||
|
" end\n"
|
||||||
|
" if (i = 10) then\n"
|
||||||
|
" break\n"
|
||||||
|
" end\n"
|
||||||
|
" set sum to sum+1\n"
|
||||||
|
" set i to i+1\n"
|
||||||
|
"end\n";
|
||||||
|
process_script(state2, lines6);
|
||||||
|
|
||||||
|
assert(!state2->skipping);
|
||||||
|
assert(10 == var_store_get_int(state2->varStore, "i"));
|
||||||
|
assert(9 == var_store_get_int(state2->varStore, "sum"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue