diff --git a/examples/while_demo.ltor b/examples/while_demo.ltor index 5861502..b6e6211 100644 --- a/examples/while_demo.ltor +++ b/examples/while_demo.ltor @@ -1,7 +1,14 @@ +# show case of 'continue' and 'break' keyword in their natural environment set i to 0 while 1 do if i > 10 then break end + if i = 5 then + set i to i+1 + continue + end + print_number(i) set i to i+1 end +print_number(i) diff --git a/src/line_processing.c b/src/line_processing.c index 16cc9f3..24c3745 100644 --- a/src/line_processing.c +++ b/src/line_processing.c @@ -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 (state->skipping && int_stack_length(state->blockStack) == state->blockStackAnchor) { // end of skipping + if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("end of skipping \n"); state->skipping = 0; } state->linePtr++; 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")) { int 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; lastLoopAnchor--; } - state->blockStackAnchor = lastLoopAnchor+1; + state->blockStackAnchor = lastLoopAnchor; 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++; return 1; } + struct SetStatement setStatementParsing; if (recognize_set_statement(str, &setStatementParsing)) { if (LINE_PROCESSING_DEBUG_LEVEL >= 2) { @@ -454,69 +528,6 @@ int process_line(struct StateContainer* state, char* str) 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 int res; byte resType; diff --git a/src/main.c b/src/main.c index 38a06e9..7768e92 100644 --- a/src/main.c +++ b/src/main.c @@ -17,13 +17,13 @@ #define INTERACTIVE_FLAG 8 #define STDIN_EXP_FLAG 16 -int help_mode() { - char* helpStr = "Usage: langatator [options] [file]\n" +int help_mode(char* cmdName) { + char* helpStr = "Usage: %s [options] [file]\n" " -h --help print this usage and exit\n" " -v --version print version information and exit\n" " -i --interactive force interactive mode\n" " -e --stdin-expression evaluate expression from stdin\n"; - printf(helpStr); + printf(helpStr, cmdName); return 0; } @@ -47,7 +47,7 @@ int file_mode(char* fileName) { FILE* f = fopen(fileName, "rb"); 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; } fseek(f, 0, SEEK_END); @@ -56,7 +56,7 @@ int file_mode(char* fileName) { char* buff = (char*) malloc(length); 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; } if (buff) { @@ -96,7 +96,7 @@ int main (int argc, char** argv) { } // no flag match if (str_starts_with("--", argv[i])) { - printf(stderr, "Invalid flag '%s'\n", argv[i]); + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); return 1; } nonFlagArgumentCount++; @@ -104,11 +104,11 @@ int main (int argc, char** argv) { } 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 & INTERACTIVE_FLAG) return interactive_mode(); if (flags & STDIN_EXP_FLAG) return stdin_expression_mode(); - help_mode(); + help_mode(cmdName); return 1; } diff --git a/tests/test_line_processing.c b/tests/test_line_processing.c index 2974a9a..f892a48 100644 --- a/tests/test_line_processing.c +++ b/tests/test_line_processing.c @@ -115,4 +115,38 @@ void test_line_processing() assert(!state2->skipping); printf("got i: %d \n", 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")); }