| // X macro: Define a macro named X, then include this file, then undef X. | // X macro: Define a macro named X, then include this file, then undef X. | ||||
| #ifdef X | #ifdef X | ||||
| X("+", l2_builtin_add); | |||||
| X("-", l2_builtin_sub); | |||||
| X("*", l2_builtin_mul); | |||||
| X("/", l2_builtin_div); | |||||
| X("print", l2_builtin_print); | X("print", l2_builtin_print); | ||||
| #endif | #endif |
| }; | }; | ||||
| void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount); | void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount); | ||||
| l2_word l2_vm_alloc(struct l2_vm *vm, enum l2_value_type typ, enum l2_value_flags flags); | |||||
| void l2_vm_free(struct l2_vm *vm); | void l2_vm_free(struct l2_vm *vm); | ||||
| void l2_vm_step(struct l2_vm *vm); | void l2_vm_step(struct l2_vm *vm); | ||||
| void l2_vm_run(struct l2_vm *vm); | void l2_vm_run(struct l2_vm *vm); |
| void l2_gen_free(struct l2_generator *gen) { | void l2_gen_free(struct l2_generator *gen) { | ||||
| l2_strset_free(&gen->atomset); | l2_strset_free(&gen->atomset); | ||||
| l2_strset_free(&gen->stringset); | l2_strset_free(&gen->stringset); | ||||
| free(gen->strings); | |||||
| } | } | ||||
| void l2_gen_halt(struct l2_generator *gen) { | void l2_gen_halt(struct l2_generator *gen) { | ||||
| put(gen, L2_OP_RJMP); | put(gen, L2_OP_RJMP); | ||||
| l2_word pos = gen->pos; | l2_word pos = gen->pos; | ||||
| gen->pos += aligned / sizeof(l2_word); | |||||
| l2_bufio_put_n(&gen->writer, *str, len); | l2_bufio_put_n(&gen->writer, *str, len); | ||||
| for (size_t i = len; i < aligned; ++i) { | for (size_t i = len; i < aligned; ++i) { | ||||
| l2_bufio_put(&gen->writer, '\0'); | l2_bufio_put(&gen->writer, '\0'); |
| while (1) { | while (1) { | ||||
| int ch = read_ch(lexer); | int ch = read_ch(lexer); | ||||
| if (ch == '"') { | if (ch == '"') { | ||||
| tok->v.str[idx] = '\0'; | |||||
| return; | return; | ||||
| } else if (ch == EOF) { | } else if (ch == EOF) { | ||||
| tok->kind = L2_TOK_EOF; | tok->kind = L2_TOK_EOF; |
| #include "strset.h" | #include "strset.h" | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <stdio.h> | |||||
| // sdbm from http://www.cse.yorku.ca/~oz/hash.html; | // sdbm from http://www.cse.yorku.ca/~oz/hash.html; | ||||
| // there are probably better algorithms out there | // there are probably better algorithms out there |
| #include <stdio.h> | #include <stdio.h> | ||||
| static void print_val(struct l2_vm *vm, struct l2_vm_value *val) { | |||||
| switch (l2_vm_value_type(val)) { | |||||
| case L2_VAL_TYPE_NONE: | |||||
| printf("(none)"); | |||||
| break; | |||||
| case L2_VAL_TYPE_INTEGER: | |||||
| printf("%zi", val->integer); | |||||
| break; | |||||
| case L2_VAL_TYPE_REAL: | |||||
| printf("%g", val->real); | |||||
| break; | |||||
| case L2_VAL_TYPE_BUFFER: | |||||
| fwrite(val->buffer->data, 1, val->buffer->len, stdout); | |||||
| break; | |||||
| case L2_VAL_TYPE_ARRAY: | |||||
| putchar('['); | |||||
| for (size_t i = 0; i < val->array->len; ++i) { | |||||
| if (i != 0) { | |||||
| printf(", "); | |||||
| } | |||||
| print_val(vm, &vm->values[val->array->data[i]]); | |||||
| } | |||||
| putchar(']'); | |||||
| break; | |||||
| case L2_VAL_TYPE_NAMESPACE: | |||||
| printf("(namespace)"); | |||||
| break; | |||||
| case L2_VAL_TYPE_FUNCTION: | |||||
| case L2_VAL_TYPE_CFUNCTION: | |||||
| printf("(function)"); | |||||
| break; | |||||
| } | |||||
| } | |||||
| l2_word l2_builtin_add(struct l2_vm *vm, struct l2_vm_array *args) { | |||||
| double sum = 0; | |||||
| for (size_t i = 0; i < args->len; ++i) { | |||||
| struct l2_vm_value *val = &vm->values[args->data[i]]; | |||||
| if (l2_vm_value_type(val) != L2_VAL_TYPE_REAL) { | |||||
| // TODO: Error | |||||
| } | |||||
| sum += val->real; | |||||
| } | |||||
| l2_word id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0); | |||||
| vm->values[id].real = sum; | |||||
| return id; | |||||
| } | |||||
| l2_word l2_builtin_sub(struct l2_vm *vm, struct l2_vm_array *args) { | |||||
| return 0; | |||||
| } | |||||
| l2_word l2_builtin_mul(struct l2_vm *vm, struct l2_vm_array *args) { | |||||
| return 0; | |||||
| } | |||||
| l2_word l2_builtin_div(struct l2_vm *vm, struct l2_vm_array *args) { | |||||
| return 0; | |||||
| } | |||||
| l2_word l2_builtin_print(struct l2_vm *vm, struct l2_vm_array *args) { | l2_word l2_builtin_print(struct l2_vm *vm, struct l2_vm_array *args) { | ||||
| printf("hey this is test\n"); | |||||
| for (size_t i = 0; i < args->len; ++i) { | |||||
| if (i != 0) { | |||||
| putchar(' '); | |||||
| } | |||||
| struct l2_vm_value *val = &vm->values[args->data[i]]; | |||||
| print_val(vm, val); | |||||
| } | |||||
| putchar('\n'); | |||||
| return 0; | return 0; | ||||
| } | } |
| void l2_vm_print_bytecode(l2_word *ops, size_t opcount) { | void l2_vm_print_bytecode(l2_word *ops, size_t opcount) { | ||||
| size_t ptr = 0; | size_t ptr = 0; | ||||
| while (ptr < opcount) { | while (ptr < opcount) { | ||||
| printf("%04zu ", ptr); | |||||
| l2_vm_print_op(ops, opcount, &ptr); | l2_vm_print_op(ops, opcount, &ptr); | ||||
| } | } | ||||
| } | } |
| vm->valuessize = 16; | vm->valuessize = 16; | ||||
| } | } | ||||
| while (id > vm->valuessize) { | |||||
| while (id >= vm->valuessize) { | |||||
| vm->valuessize *= 2; | vm->valuessize *= 2; | ||||
| } | } | ||||
| #undef X | #undef X | ||||
| } | } | ||||
| l2_word l2_vm_alloc(struct l2_vm *vm, enum l2_value_type typ, enum l2_value_flags flags) { | |||||
| l2_word id = alloc_val(vm); | |||||
| memset(&vm->values[id], 0, sizeof(vm->values[id])); | |||||
| vm->values[id].flags = typ | flags; | |||||
| return id; | |||||
| } | |||||
| void l2_vm_free(struct l2_vm *vm) { | void l2_vm_free(struct l2_vm *vm) { | ||||
| // Skip ID 0, because that's always NONE | // Skip ID 0, because that's always NONE | ||||
| for (size_t i = 1; i < vm->valuessize; ++i) { | for (size_t i = 1; i < vm->valuessize; ++i) { | ||||
| vm->stack[vm->sptr++] = arr_id; | vm->stack[vm->sptr++] = arr_id; | ||||
| l2_word ns_id = alloc_val(vm); | l2_word ns_id = alloc_val(vm); | ||||
| vm->values[ns_id].extra.ns_parent = ns_id; | |||||
| vm->values[ns_id].extra.ns_parent = func->func.namespace; | |||||
| vm->values[ns_id].ns = NULL; | vm->values[ns_id].ns = NULL; | ||||
| vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | ||||
| vm->nstack[vm->nsptr++] = ns_id; | vm->nstack[vm->nsptr++] = ns_id; |