@@ -8,6 +8,21 @@ | |||
#include <stdio.h> | |||
#include <string.h> | |||
void step_through(struct l2_vm *vm) { | |||
printf("=====\n\nInitial state:\n"); | |||
l2_vm_print_state(vm); | |||
char buf[16]; | |||
while ((enum l2_opcode)vm->ops[vm->iptr] != L2_OP_HALT) { | |||
size_t iptr = vm->iptr; | |||
printf("\n======\n\n(%d) Will run instr: ", vm->iptr); | |||
l2_vm_print_op(vm->ops, vm->opcount, &iptr); | |||
fgets(buf, sizeof(buf), stdin); | |||
l2_vm_step(vm); | |||
l2_vm_print_state(vm); | |||
} | |||
} | |||
int main(int argc, char **argv) { | |||
if (argc != 1 && argc != 2) { | |||
fprintf(stderr, "Usage: %s [file]\n", argv[0]); | |||
@@ -52,10 +67,17 @@ int main(int argc, char **argv) { | |||
struct l2_vm vm; | |||
l2_vm_init(&vm, (void *)w.mem, w.len / sizeof(l2_word)); | |||
l2_vm_run(&vm); | |||
step_through(&vm); | |||
free(w.mem); | |||
printf("State after executing:\n"); | |||
l2_vm_print_state(&vm); | |||
while (l2_vm_gc(&vm)); | |||
printf("State after GC:\n"); | |||
l2_vm_print_state(&vm); | |||
l2_vm_free(&vm); | |||
} |
@@ -39,7 +39,7 @@ const char *l2_token_kind_name(enum l2_token_kind kind) { | |||
case L2_TOK_PERIOD: | |||
return "period"; | |||
case L2_TOK_COLON_EQ: | |||
return "period"; | |||
return "colon-equals"; | |||
case L2_TOK_EOL: | |||
return "end-of-line"; | |||
case L2_TOK_EOF: | |||
@@ -202,6 +202,7 @@ static void read_ident(struct l2_lexer *lexer, struct l2_token *tok) { | |||
case ',': | |||
case '.': | |||
case ':': | |||
case ';': | |||
case EOF: | |||
tok->v.str[idx] = '\0'; | |||
return; | |||
@@ -267,6 +268,14 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
tok->kind = L2_TOK_CLOSE_BRACKET; | |||
break; | |||
case ';': | |||
tok->kind = L2_TOK_EOL; | |||
do { | |||
read_ch(lexer); | |||
skip_whitespace(lexer); | |||
} while (peek_ch(lexer) == ';'); | |||
break; | |||
case ',': | |||
read_ch(lexer); | |||
tok->kind = L2_TOK_COMMA; |
@@ -17,6 +17,7 @@ static int parse_function_impl( | |||
l2_lexer_consume(lexer); // { | |||
l2_lexer_skip_opt(lexer, L2_TOK_EOL); | |||
int first = 1; | |||
while (1) { | |||
struct l2_token *tok = l2_lexer_peek(lexer, 1); | |||
if (tok->kind == L2_TOK_EOF) { | |||
@@ -27,11 +28,17 @@ static int parse_function_impl( | |||
break; | |||
} | |||
// The previous expr left a value on the stack which we have to pop | |||
if (!first) { | |||
l2_gen_pop(gen); | |||
} | |||
if (parse_expression(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
l2_lexer_skip_opt(lexer, L2_TOK_EOL); | |||
first = 0; | |||
} | |||
l2_gen_ret(gen); | |||
@@ -84,11 +91,26 @@ static int parse_sub_expression( | |||
if (tok->kind == L2_TOK_OPEN_PAREN) { | |||
l2_lexer_consume(lexer); // ( | |||
tok = l2_lexer_peek(lexer, 1); | |||
// Special case: (foo) should be interpreted as a function call | |||
if ( | |||
tok->kind == L2_TOK_IDENT && | |||
l2_lexer_peek(lexer, 2)->kind == L2_TOK_CLOSE_PAREN) { | |||
char *ident = l2_token_extract_str(tok); | |||
l2_lexer_consume(lexer); // ident | |||
l2_lexer_consume(lexer); // ) | |||
l2_gen_push(gen, 0); // Arg count | |||
l2_gen_namespace_lookup(gen, &ident); | |||
l2_gen_func_call(gen); | |||
return 0; | |||
} | |||
if (parse_expression(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
tok = l2_lexer_peek(lexer, 1); | |||
if (tok->kind != L2_TOK_CLOSE_PAREN) { | |||
l2_parse_err(err, tok, "In paren expression: Expected close paren, got %s", | |||
l2_token_kind_name(tok->kind)); | |||
@@ -160,8 +182,9 @@ static int parse_expression( | |||
int l2_parse_program( | |||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | |||
int first = 1; | |||
l2_lexer_skip_opt(lexer, L2_TOK_EOL); | |||
int first = 1; | |||
while (1) { | |||
struct l2_token *tok = l2_lexer_peek(lexer, 1); | |||
if (tok->kind == L2_TOK_EOF) { | |||
@@ -180,7 +203,6 @@ int l2_parse_program( | |||
} | |||
l2_lexer_skip_opt(lexer, L2_TOK_EOL); | |||
first = 0; | |||
} | |||