#include "vm/vm.h" | #include "vm/vm.h" | ||||
#include "vm/print.h" | #include "vm/print.h" | ||||
#include "parse/parse.h" | |||||
#include "parse/lex.h" | |||||
#include "io.h" | |||||
#include "bitset.h" | #include "bitset.h" | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
int main() { | |||||
l2_word ops[] = { | |||||
L2_OP_PUSH, 100, | |||||
L2_OP_PUSH, 100, | |||||
L2_OP_ADD, | |||||
L2_OP_ALLOC_INTEGER_32, | |||||
L2_OP_PUSH, 21 /* offset */, | |||||
L2_OP_PUSH, 5 /* length */, | |||||
L2_OP_ALLOC_BUFFER_STATIC, | |||||
L2_OP_POP, | |||||
L2_OP_PUSH, 16, | |||||
L2_OP_CALL, | |||||
L2_OP_HALT, | |||||
L2_OP_PUSH, 53, | |||||
L2_OP_ALLOC_INTEGER_32, | |||||
L2_OP_ALLOC_NAMESPACE, | |||||
L2_OP_HALT, | |||||
0, 0, | |||||
}; | |||||
memcpy(&ops[21], "Hello", 5); | |||||
int main(int argc, char **argv) { | |||||
if (argc != 1 && argc != 2) { | |||||
fprintf(stderr, "Usage: %s [file]\n", argv[0]); | |||||
return 1; | |||||
} | |||||
struct l2_vm vm; | |||||
l2_vm_init(&vm, ops, sizeof(ops) / sizeof(*ops)); | |||||
FILE *inf; | |||||
if (argc == 1 || (argc == 2 && strcmp(argv[1], "-") == 0)) { | |||||
inf = stdin; | |||||
} else { | |||||
inf = fopen(argv[1], "r"); | |||||
} | |||||
l2_vm_run(&vm); | |||||
struct l2_io_file_reader r; | |||||
r.r.read = l2_io_file_read; | |||||
r.f = inf; | |||||
l2_vm_print_state(&vm); | |||||
struct l2_lexer lexer; | |||||
l2_lexer_init(&lexer, &r.r); | |||||
struct l2_io_mem_writer w = {0}; | |||||
w.w.write = l2_io_mem_write; | |||||
struct l2_generator gen; | |||||
l2_gen_init(&gen, &w.w); | |||||
l2_vm_gc(&vm); | |||||
struct l2_parse_error err; | |||||
if (l2_parse_program(&lexer, &gen, &err) < 0) { | |||||
fprintf(stderr, "Parse error: %s:%i:%i: %s\n", | |||||
(argc == 2 ? argv[1] : "-"), err.line, err.ch, err.message); | |||||
return 1; | |||||
} | |||||
printf("Heap:\n"); | |||||
l2_vm_print_stack(&vm); | |||||
fprintf(stderr, "Generated bytecode:\n"); | |||||
l2_vm_print_bytecode((l2_word *)w.mem, w.len / sizeof(l2_word)); | |||||
fprintf(stderr, "\n"); | |||||
l2_vm_free(&vm); | |||||
struct l2_vm vm; | |||||
l2_vm_init(&vm, (void *)w.mem, w.len / sizeof(l2_word)); | |||||
l2_vm_run(&vm); | |||||
l2_vm_print_state(&vm); | |||||
} | } |
*/ | */ | ||||
L2_OP_ALLOC_NAMESPACE, | L2_OP_ALLOC_NAMESPACE, | ||||
/* | |||||
* Allocate a function. | |||||
* Pop <word> | |||||
* Alloc function <var> pointing to location <word> | |||||
* Push <var> | |||||
*/ | |||||
L2_OP_ALLOC_FUNCTION, | |||||
/* | /* | ||||
* Set a namespace's name to a value. | * Set a namespace's name to a value. | ||||
* Pop <key> | * Pop <key> |
void l2_gen_halt(struct l2_generator *gen); | void l2_gen_halt(struct l2_generator *gen); | ||||
void l2_gen_stack_frame(struct l2_generator *gen); | void l2_gen_stack_frame(struct l2_generator *gen); | ||||
void l2_gen_rjmp(struct l2_generator *gen, l2_word len); | |||||
void l2_gen_pop(struct l2_generator *gen); | |||||
void l2_gen_ret(struct l2_generator *gen); | |||||
void l2_gen_assignment(struct l2_generator *gen, char **ident); | void l2_gen_assignment(struct l2_generator *gen, char **ident); | ||||
void l2_gen_number(struct l2_generator *gen, double num); | void l2_gen_number(struct l2_generator *gen, double num); | ||||
void l2_gen_string(struct l2_generator *gen, char **str); | void l2_gen_string(struct l2_generator *gen, char **str); | ||||
void l2_gen_function(struct l2_generator *gen, l2_word pos); | |||||
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident); | void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident); | ||||
#endif | #endif |
L2_VAL_TYPE_BUFFER, | L2_VAL_TYPE_BUFFER, | ||||
L2_VAL_TYPE_ARRAY, | L2_VAL_TYPE_ARRAY, | ||||
L2_VAL_TYPE_NAMESPACE, | L2_VAL_TYPE_NAMESPACE, | ||||
L2_VAL_TYPE_FUNCTION, | |||||
L2_VAL_MARKED = 1 << 7, | L2_VAL_MARKED = 1 << 7, | ||||
L2_VAL_CONST = 1 << 8, | L2_VAL_CONST = 1 << 8, | ||||
} flags; | } flags; | ||||
union { | union { | ||||
int64_t integer; | int64_t integer; | ||||
double real; | double real; | ||||
struct { | |||||
l2_word pos; | |||||
l2_word namespace; | |||||
} func; | |||||
void *data; | void *data; | ||||
}; | }; | ||||
}; | }; |
l2_strset_free(&gen->stringset); | l2_strset_free(&gen->stringset); | ||||
} | } | ||||
// Postconditions: | |||||
// * Execution is halted | |||||
void l2_gen_halt(struct l2_generator *gen) { | void l2_gen_halt(struct l2_generator *gen) { | ||||
put(gen, L2_OP_HALT); | put(gen, L2_OP_HALT); | ||||
} | } | ||||
// Postconditions: | |||||
// * NStack(0) is a namespace value | |||||
void l2_gen_stack_frame(struct l2_generator *gen) { | void l2_gen_stack_frame(struct l2_generator *gen) { | ||||
put(gen, L2_OP_GEN_STACK_FRAME); | put(gen, L2_OP_GEN_STACK_FRAME); | ||||
} | } | ||||
// Preconditions: | |||||
// * Stack(0) is any value | |||||
// Postconditions: | |||||
// * The namespace contains the new value under key 'ident' | |||||
// * Stack(0) is untouched | |||||
void l2_gen_rjmp(struct l2_generator *gen, l2_word len) { | |||||
put(gen, L2_OP_PUSH); | |||||
put(gen, len); | |||||
put(gen, L2_OP_RJMP); | |||||
} | |||||
void l2_gen_pop(struct l2_generator *gen) { | |||||
put(gen, L2_OP_POP); | |||||
} | |||||
void l2_gen_ret(struct l2_generator *gen) { | |||||
put(gen, L2_OP_RET); | |||||
} | |||||
void l2_gen_assignment(struct l2_generator *gen, char **ident) { | void l2_gen_assignment(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_PUSH); | put(gen, L2_OP_PUSH); | ||||
put(gen, L2_OP_STACK_FRAME_SET); | put(gen, L2_OP_STACK_FRAME_SET); | ||||
} | } | ||||
// Postconditions; | |||||
// * Stack(0) is changed to a number value | |||||
void l2_gen_number(struct l2_generator *gen, double num) { | void l2_gen_number(struct l2_generator *gen, double num) { | ||||
uint64_t n; | uint64_t n; | ||||
memcpy(&n, &num, sizeof(num)); | memcpy(&n, &num, sizeof(num)); | ||||
put(gen, L2_OP_PUSH); | put(gen, L2_OP_PUSH); | ||||
put(gen, aligned / sizeof(l2_word)); | put(gen, aligned / sizeof(l2_word)); | ||||
put(gen, L2_OP_RJMP); | |||||
l2_word pos = gen->pos; | l2_word pos = gen->pos; | ||||
l2_bufio_put_n(&gen->writer, *str, len); | l2_bufio_put_n(&gen->writer, *str, len); | ||||
} | } | ||||
} | } | ||||
// Postconditions: | |||||
// * Stack(0) is any value | |||||
void l2_gen_function(struct l2_generator *gen, l2_word pos) { | |||||
put(gen, L2_OP_PUSH); | |||||
put(gen, pos); | |||||
put(gen, L2_OP_ALLOC_FUNCTION); | |||||
} | |||||
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) { | void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_PUSH); | put(gen, L2_OP_PUSH); |
#include "parse/parse.h" | #include "parse/parse.h" | ||||
#include <stdbool.h> | |||||
#include "gen/gen.h" | #include "gen/gen.h" | ||||
static int parse_expression( | |||||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err); | |||||
static int parse_function_impl( | |||||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | |||||
l2_gen_stack_frame(gen); | |||||
l2_lexer_consume(lexer); // { | |||||
l2_lexer_consume(lexer); // } | |||||
l2_gen_ret(gen); | |||||
return 0; | |||||
} | |||||
static int parse_function( | |||||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | |||||
l2_gen_flush(gen); | |||||
struct l2_io_writer *prev_writer = gen->writer.w; | |||||
// Generate the function to a buffer in memory | |||||
struct l2_io_mem_writer w = {0}; | |||||
w.w.write = l2_io_mem_write; | |||||
gen->writer.w = &w.w; | |||||
// Generates three words; PUSH, 0, RJMP | |||||
l2_gen_rjmp(gen, 0); | |||||
l2_word pos = gen->pos; | |||||
// Generate the function body itself | |||||
int ret = parse_function_impl(lexer, gen, err); | |||||
l2_gen_flush(gen); | |||||
gen->writer.w = prev_writer; | |||||
if (ret < 0) { | |||||
free(w.mem); | |||||
return -1; | |||||
} | |||||
l2_word *ops = (l2_word *)w.mem; | |||||
l2_word opcount = w.len / sizeof(l2_word); | |||||
// Due to the earlier gen_rjmp, the second word will be the argument to RJMP. | |||||
// Need to set it properly to skip the function body. | |||||
// The '- 3' is because we don't skip the PUSH, <count>, RJMP sequence. | |||||
ops[1] = opcount - 3; | |||||
l2_bufio_put_n(&gen->writer, ops, opcount * sizeof(l2_word)); | |||||
free(w.mem); | |||||
l2_gen_function(gen, pos); | |||||
return 0; | |||||
} | |||||
static int parse_expression( | static int parse_expression( | ||||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | ||||
struct l2_token *tok = l2_lexer_peek(lexer, 1); | struct l2_token *tok = l2_lexer_peek(lexer, 1); | ||||
l2_lexer_consume(lexer); // string | l2_lexer_consume(lexer); // string | ||||
l2_gen_string(gen, &str); | l2_gen_string(gen, &str); | ||||
return 0; | return 0; | ||||
} else if (tok->kind == L2_TOK_OPEN_BRACE) { | |||||
return parse_function(lexer, gen, err); | |||||
} | } | ||||
l2_parse_err(err, tok, "In expression: Unexpected tokens %s, %s", | l2_parse_err(err, tok, "In expression: Unexpected tokens %s, %s", | ||||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | ||||
l2_gen_stack_frame(gen); | l2_gen_stack_frame(gen); | ||||
bool first = true; | |||||
while (1) { | while (1) { | ||||
struct l2_token *tok = l2_lexer_peek(lexer, 1); | struct l2_token *tok = l2_lexer_peek(lexer, 1); | ||||
if (tok->kind == L2_TOK_EOF) { | if (tok->kind == L2_TOK_EOF) { | ||||
break; | 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) { | if (parse_expression(lexer, gen, err) < 0) { | ||||
l2_gen_halt(gen); | l2_gen_halt(gen); | ||||
l2_gen_flush(gen); | l2_gen_flush(gen); | ||||
return -1; | return -1; | ||||
} | } | ||||
first = false; | |||||
} | } | ||||
l2_gen_halt(gen); | l2_gen_halt(gen); |
printf("NAMESPACE, len %zu\n", ns->len); | printf("NAMESPACE, len %zu\n", ns->len); | ||||
} | } | ||||
break; | break; | ||||
case L2_VAL_TYPE_FUNCTION: | |||||
printf("FUNCTION, pos %u, ns %u\n", val->func.pos, val->func.namespace); | |||||
break; | |||||
} | } | ||||
} | } | ||||
printf("CALL\n"); | printf("CALL\n"); | ||||
break; | break; | ||||
case L2_OP_RJMP: | |||||
printf("RJMP\n"); | |||||
break; | |||||
case L2_OP_GEN_STACK_FRAME: | case L2_OP_GEN_STACK_FRAME: | ||||
printf("GEN_STACK_FRAME\n"); | printf("GEN_STACK_FRAME\n"); | ||||
break; | break; | ||||
printf("ALLOC_NAMESPACE\n"); | printf("ALLOC_NAMESPACE\n"); | ||||
break; | break; | ||||
case L2_OP_ALLOC_FUNCTION: | |||||
printf("ALLOC_FUNCTION\n"); | |||||
break; | |||||
case L2_OP_NAMESPACE_SET: | case L2_OP_NAMESPACE_SET: | ||||
printf("NAMESPACE_SET\n"); | printf("NAMESPACE_SET\n"); | ||||
break; | break; |
gc_mark_array(vm, val); | gc_mark_array(vm, val); | ||||
} else if (typ == L2_VAL_TYPE_NAMESPACE) { | } else if (typ == L2_VAL_TYPE_NAMESPACE) { | ||||
gc_mark_namespace(vm, val); | gc_mark_namespace(vm, val); | ||||
} else if (typ == L2_VAL_TYPE_FUNCTION) { | |||||
gc_mark_namespace(vm, &vm->values[val->func.namespace]); | |||||
} | } | ||||
} | } | ||||
vm->iptr = word; | vm->iptr = word; | ||||
break; | break; | ||||
case L2_OP_RJMP: | |||||
word = vm->stack[vm->sptr - 1]; | |||||
vm->sptr -= 1; | |||||
vm->iptr += word; | |||||
break; | |||||
case L2_OP_GEN_STACK_FRAME: | case L2_OP_GEN_STACK_FRAME: | ||||
word = alloc_val(vm); | word = alloc_val(vm); | ||||
vm->values[word].flags = L2_VAL_TYPE_NAMESPACE; | vm->values[word].flags = L2_VAL_TYPE_NAMESPACE; | ||||
vm->sptr += 1; | vm->sptr += 1; | ||||
break; | break; | ||||
case L2_OP_ALLOC_FUNCTION: | |||||
word = alloc_val(vm); | |||||
vm->values[word].flags = L2_VAL_TYPE_FUNCTION; | |||||
vm->values[word].func.pos = vm->stack[--vm->sptr]; | |||||
vm->values[word].func.namespace = vm->nstack[vm->nsptr - 1]; | |||||
vm->stack[vm->sptr] = word; | |||||
vm->sptr += 1; | |||||
break; | |||||
case L2_OP_NAMESPACE_SET: | case L2_OP_NAMESPACE_SET: | ||||
{ | { | ||||
l2_word key = vm->stack[vm->sptr - 1]; | l2_word key = vm->stack[vm->sptr - 1]; |