Browse Source

parsing/codegen, plus vm work

master
Martin Dørum 3 years ago
parent
commit
48be0c18b1

+ 3
- 76
cmd/main.c View File

@@ -1,67 +1,10 @@
#include "vm/vm.h"
#include "vm/print.h"
#include "bitset.h"

#include <stdio.h>
#include <string.h>

void print_var(struct l2_vm_value *val) {
switch (val->flags & 0x0f) {
case L2_VAL_TYPE_NONE:
printf("NONE\n");
break;

case L2_VAL_TYPE_INTEGER:
printf("INTEGER %zi\n", val->integer);
break;

case L2_VAL_TYPE_REAL:
printf("REAL %f\n", val->real);
break;

case L2_VAL_TYPE_ARRAY:
{
if (val->data == NULL) {
printf("ARRAY, empty\n");
return;
}

struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
printf("ARRAY, len %zu\n", arr->len);
for (size_t i = 0; i < arr->len; ++i) {
printf(" %zu: %u\n", i, arr->data[i]);
}
}
break;

case L2_VAL_TYPE_BUFFER:
{
if (val->data == NULL) {
printf("BUFFER, empty\n");
return;
}

struct l2_vm_buffer *buf = (struct l2_vm_buffer *)val->data;
printf("BUFFER, len %zu\n", buf->len);
for (size_t i = 0; i < buf->len; ++i) {
printf(" %zu: %c\n", i, buf->data[i]);
}
}
break;

case L2_VAL_TYPE_NAMESPACE:
{
if (val->data == NULL) {
printf("NAMESPACE, empty\n");
return;
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
printf("NAMESPACE, len %zu\n", ns->len);
}
break;
}
}

int main() {
l2_word ops[] = {
L2_OP_PUSH, 100,
@@ -88,28 +31,12 @@ int main() {

l2_vm_run(&vm);

printf("Stack:\n");
for (l2_word i = 0; i < vm.sptr; ++i) {
printf(" %i: %i\n", i, vm.stack[i]);
}

printf("Heap:\n");
for (l2_word i = 0; i < vm.valuessize; ++i) {
if (l2_bitset_get(&vm.valueset, i)) {
printf(" %u: ", i);
print_var(&vm.values[i]);
}
}
l2_vm_print_state(&vm);

l2_vm_gc(&vm);

printf("Heap:\n");
for (l2_word i = 0; i < vm.valuessize; ++i) {
if (l2_bitset_get(&vm.valueset, i)) {
printf(" %u: ", i);
print_var(&vm.values[i]);
}
}
l2_vm_print_stack(&vm);

l2_vm_free(&vm);
}

+ 28
- 5
include/lang2/bytecode.h View File

@@ -52,8 +52,32 @@ enum l2_opcode {
*/
L2_OP_CALL,

/*
* Generate a stack frame.
* Alloc namespace <var>
* NSPush <var>
*/
L2_OP_GEN_STACK_FRAME,

/*
* Look up a value from the current stack frame.
* Pop <word>
* Find <val> in stack frame using <word>
* Push <val>
*/
L2_OP_STACK_FRAME_LOOKUP,

/*
* Set a value in the current stack frame.
* Pop <key>
* Read <val>
* Assign <val> to stack frame
*/
L2_OP_STACK_FRAME_SET,

/*
* Return from a function.
* NSPop
* Pop <word>
* Jump to <word>
*/
@@ -86,9 +110,9 @@ enum l2_opcode {

/*
* Allocate a real from two words.
* Pop <word1>
* Pop <word2>
* Alloc real <var> from <word1> << 32 | <word2>
* Pop <high>
* Pop <low>
* Alloc real <var> from <high> << 32 | <low>
* Push <var>
*/
L2_OP_ALLOC_REAL_64,
@@ -127,10 +151,9 @@ enum l2_opcode {
/*
* Set a namespace's name to a value.
* Pop <key>
* Pop <val>
* Read <val>
* Read <ns>
* Assign <val> to <ns[<key>]>
* Push <val>
*/
L2_OP_NAMESPACE_SET,


+ 5
- 1
include/lang2/gen/gen.h View File

@@ -10,10 +10,14 @@ struct l2_generator {
struct l2_bufio_writer writer;
};

void l2_gen_init(struct l2_generator *gen);
void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w);
void l2_gen_flush(struct l2_generator *gen);
void l2_gen_free(struct l2_generator *gen);

void l2_gen_halt(struct l2_generator *gen);
void l2_gen_stack_frame(struct l2_generator *gen);
void l2_gen_assignment(struct l2_generator *gen, char **ident);
void l2_gen_number(struct l2_generator *gen, double num);
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident);

#endif

+ 2
- 2
include/lang2/parse/lex.h View File

@@ -34,12 +34,12 @@ struct l2_token {
};

void l2_token_free(struct l2_token *tok);
struct l2_token l2_token_move(struct l2_token *tok);
char *l2_token_extract_str(struct l2_token *tok);
void l2_token_print(struct l2_token *tok, struct l2_io_writer *w);

struct l2_lexer {
struct l2_token currtok;
struct l2_token toks[2];
struct l2_token toks[4];
int tokidx;
int line;
int ch;

+ 11
- 1
include/lang2/parse/parse.h View File

@@ -4,6 +4,16 @@
#include "lex.h"
#include "gen/gen.h"

int l2_parse_program(struct l2_lexer *lexer, struct l2_generator *gen);
struct l2_parse_error {
int line;
int ch;
char *message;
};

void l2_parse_err(struct l2_parse_error *err, struct l2_token *tok, const char *fmt, ...);
void l2_parse_error_free(struct l2_parse_error *err);

int l2_parse_program(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err);

#endif

+ 15
- 0
include/lang2/vm/print.h View File

@@ -0,0 +1,15 @@
#ifndef L2_VM_PRINT_H
#define L2_VM_PRINT_H

#include "vm.h"

void l2_vm_print_val(struct l2_vm_value *val);
void l2_vm_print_state(struct l2_vm *vm);
void l2_vm_print_heap(struct l2_vm *vm);
void l2_vm_print_stack(struct l2_vm *vm);
void l2_vm_print_nstack(struct l2_vm *vm);

void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr);
void l2_vm_print_bytecode(l2_word *ops, size_t opcount);

#endif

+ 6
- 2
include/lang2/vm/vm.h View File

@@ -24,6 +24,8 @@ struct l2_vm_value {
};
};

#define l2_vm_value_type(val) ((val).flags & 0x0f)

struct l2_vm_buffer {
size_t len;
char data[];
@@ -49,15 +51,17 @@ l2_word l2_vm_namespace_get(struct l2_vm_value *ns, l2_word key);
struct l2_vm {
l2_word *ops;
size_t opcount;
l2_word iptr;

struct l2_vm_value *values;
size_t valuessize;
struct l2_bitset valueset;

l2_word stack[1024];
unsigned char stackflags[1024];
l2_word iptr;
l2_word sptr;

l2_word nstack[1024];
l2_word nsptr;
};

void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount);

+ 34
- 4
lib/gen/gen.c View File

@@ -6,9 +6,14 @@ static void put(struct l2_generator *gen, l2_word word) {
l2_bufio_put_n(&gen->writer, &word, sizeof(word));
}

void l2_gen_init(struct l2_generator *gen) {
void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w) {
l2_strset_init(&gen->atoms);
l2_strset_init(&gen->strings);
l2_bufio_writer_init(&gen->writer, w);
}

void l2_gen_flush(struct l2_generator *gen) {
l2_bufio_flush(&gen->writer);
}

void l2_gen_free(struct l2_generator *gen) {
@@ -16,22 +21,47 @@ void l2_gen_free(struct l2_generator *gen) {
l2_strset_free(&gen->strings);
}

// Postconditions:
// * Execution is halted
void l2_gen_halt(struct l2_generator *gen) {
put(gen, L2_OP_HALT);
}

// Postconditions:
// * NStack(0) is a namespace value
void l2_gen_stack_frame(struct l2_generator *gen) {
put(gen, L2_OP_ALLOC_NAMESPACE);
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_assignment(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atoms, ident);
put(gen, L2_OP_PUSH);
put(gen, atom_id);
put(gen, L2_OP_NAMESPACE_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) {
uint64_t n;
memcpy(&n, &num, sizeof(num));
put(gen, L2_OP_PUSH_2);
put(gen, n >> 32);
put(gen, n);
put(gen, n >> 32);
put(gen, L2_OP_ALLOC_REAL_64);
}

// Postconditions:
// * Stack(0) is any value
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atoms, ident);
put(gen, L2_OP_PUSH);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_LOOKUP);
}

+ 36
- 0
lib/parse/error.c View File

@@ -0,0 +1,36 @@
#include "parse/parse.h"

#include <stdio.h>
#include <stdarg.h>

void l2_parse_err(struct l2_parse_error *err, struct l2_token *tok, const char *fmt, ...) {
err->line = tok->line;
err->ch = tok->ch;
char buf[256];

va_list va;
va_start(va, fmt);
int n = vsnprintf(buf, sizeof(buf), fmt, va);

if (n < 0) {
const char *message = "Failed to generate error message!";
err->message = malloc(strlen(message) + 1);
strcpy(err->message, message);
va_end(va);
return;
} else if (n + 1 < sizeof(buf)) {
err->message = malloc(n + 1);
strcpy(err->message, buf);
va_end(va);
return;
}

// Need to allocate for this one
err->message = malloc(n + 1);
vsnprintf(err->message, n + 1, fmt, va);
va_end(va);
}

void l2_parse_error_free(struct l2_parse_error *err) {
free(err->message);
}

+ 42
- 8
lib/parse/lex.c View File

@@ -2,6 +2,23 @@

#include <stdlib.h>

static int parse_number(const char *str, double *num) {
size_t len = strlen(str);
*num = 0;
int power = 1;
for (int i = (int)len - 1; i >= 0; --i) {
char ch = str[i];
if (ch >= '0' && ch <= '9') {
*num += (ch - '0') * power;
power *= 10;
} else {
return -1;
}
}

return 0;
}

const char *l2_token_kind_name(enum l2_token_kind kind) {
switch (kind) {
case L2_TOK_OPEN_PAREN:
@@ -41,13 +58,10 @@ void l2_token_free(struct l2_token *tok) {
}
}

struct l2_token l2_token_move(struct l2_token *tok) {
struct l2_token dup = *tok;
if (tok->kind == L2_TOK_STRING) {
tok->v.str = NULL;
}

return dup;
char *l2_token_extract_str(struct l2_token *tok) {
char *str = tok->v.str;
tok->v.str = NULL;
return str;
}

void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) {
@@ -201,41 +215,50 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) {
tok->line = lexer->line;
tok->ch = lexer->ch;

int ch = read_ch(lexer);
int ch = peek_ch(lexer);
switch (ch) {
case '(':
read_ch(lexer);
tok->kind = L2_TOK_OPEN_PAREN;
break;

case ')':
read_ch(lexer);
tok->kind = L2_TOK_CLOSE_PAREN;
break;

case '{':
read_ch(lexer);
tok->kind = L2_TOK_OPEN_BRACE;
break;

case '}':
read_ch(lexer);
tok->kind = L2_TOK_CLOSE_BRACE;
break;

case '[':
read_ch(lexer);
tok->kind = L2_TOK_OPEN_BRACKET;
break;

case ']':
read_ch(lexer);
tok->kind = L2_TOK_CLOSE_BRACKET;
break;

case ',':
read_ch(lexer);
tok->kind = L2_TOK_COMMA;
break;

case '.':
read_ch(lexer);
tok->kind = L2_TOK_PERIOD;
break;

case ':':
read_ch(lexer);
{
ch = read_ch(lexer);
switch (ch) {
@@ -256,11 +279,22 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) {
break;

case '"':
read_ch(lexer);
read_string(lexer, tok);
break;

default:
read_ident(lexer, tok);
if (tok->kind != L2_TOK_IDENT) {
break;
}

double num;
if (parse_number(tok->v.str, &num) >= 0) {
free(tok->v.str);
tok->kind = L2_TOK_NUMBER;
tok->v.num = num;
}
break;
}
}

+ 27
- 5
lib/parse/parse.c View File

@@ -2,23 +2,41 @@

#include "gen/gen.h"

static int parse_expression(struct l2_lexer *lexer, struct l2_generator *gen) {
static int parse_expression(
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 *tok2 = l2_lexer_peek(lexer, 2);

if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) {
parse_expression(lexer, gen);
l2_gen_assignment(gen, &tok->v.str);
char *ident = l2_token_extract_str(tok);
l2_lexer_get(lexer); // ident
l2_lexer_get(lexer); // :=

if (parse_expression(lexer, gen, err) < 0) {
free(ident);
return -1;
}

l2_gen_assignment(gen, &ident);
return 0;
} else if (tok->kind == L2_TOK_NUMBER) {
l2_gen_number(gen, tok->v.num);
l2_lexer_get(lexer); // number
return 0;
} else if (tok->kind == L2_TOK_IDENT) {
char *ident = l2_token_extract_str(tok);
l2_lexer_get(lexer); // ident
l2_gen_namespace_lookup(gen, &ident);
return 0;
}

l2_parse_err(err, tok, "In expression: Unexpected tokens %s, %s",
l2_token_kind_name(tok->kind), l2_token_kind_name(tok2->kind));
return -1;
}

int l2_parse_program(struct l2_lexer *lexer, struct l2_generator *gen) {
int l2_parse_program(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_gen_stack_frame(gen);

while (1) {
@@ -27,10 +45,14 @@ int l2_parse_program(struct l2_lexer *lexer, struct l2_generator *gen) {
break;
}

if (parse_expression(lexer, gen) < 0) {
if (parse_expression(lexer, gen, err) < 0) {
l2_gen_halt(gen);
l2_gen_flush(gen);
return -1;
}
}

l2_gen_halt(gen);
l2_gen_flush(gen);
return 0;
}

+ 202
- 0
lib/vm/print.c View File

@@ -0,0 +1,202 @@
#include "vm/print.h"

#include <stdio.h>

void l2_vm_print_val(struct l2_vm_value *val) {
switch (val->flags & 0x0f) {
case L2_VAL_TYPE_NONE:
printf("NONE\n");
break;

case L2_VAL_TYPE_INTEGER:
printf("INTEGER %zi\n", val->integer);
break;

case L2_VAL_TYPE_REAL:
printf("REAL %f\n", val->real);
break;

case L2_VAL_TYPE_ARRAY:
{
if (val->data == NULL) {
printf("ARRAY, empty\n");
return;
}

struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
printf("ARRAY, len %zu\n", arr->len);
for (size_t i = 0; i < arr->len; ++i) {
printf(" %zu: %u\n", i, arr->data[i]);
}
}
break;

case L2_VAL_TYPE_BUFFER:
{
if (val->data == NULL) {
printf("BUFFER, empty\n");
return;
}

struct l2_vm_buffer *buf = (struct l2_vm_buffer *)val->data;
printf("BUFFER, len %zu\n", buf->len);
for (size_t i = 0; i < buf->len; ++i) {
printf(" %zu: %c\n", i, buf->data[i]);
}
}
break;

case L2_VAL_TYPE_NAMESPACE:
{
if (val->data == NULL) {
printf("NAMESPACE, empty\n");
return;
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
printf("NAMESPACE, len %zu\n", ns->len);
}
break;
}
}

void l2_vm_print_state(struct l2_vm *vm) {
printf("Stack:\n");
l2_vm_print_stack(vm);
printf("Heap:\n");
l2_vm_print_heap(vm);
printf("NStack:\n");
l2_vm_print_nstack(vm);
}

void l2_vm_print_heap(struct l2_vm *vm) {
for (l2_word i = 0; i < vm->valuessize; ++i) {
if (l2_bitset_get(&vm->valueset, i)) {
printf(" %u: ", i);
l2_vm_print_val(&vm->values[i]);
}
}
}

void l2_vm_print_stack(struct l2_vm *vm) {
for (l2_word i = 0; i < vm->sptr; ++i) {
printf(" %i: %i\n", i, vm->stack[i]);
}
}

void l2_vm_print_nstack(struct l2_vm *vm) {
for (l2_word i = 0; i < vm->nsptr; ++i) {
printf(" %i: %i\n", i, vm->nstack[i]);
}
}

static void print_op_num(l2_word *ops, size_t opcount, size_t ptr) {
if (ptr >= opcount) {
printf("<EOF>");
} else {
printf("%i", ops[ptr]);
}
}

void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
enum l2_opcode opcode = (enum l2_opcode)ops[(*ptr)++];

switch (opcode) {
case L2_OP_NOP:
printf("NOP\n");
break;

case L2_OP_PUSH:
printf("PUSH ");
print_op_num(ops, opcount, (*ptr)++);
printf("\n");
break;

case L2_OP_PUSH_2:
printf("PUSH2 ");
print_op_num(ops, opcount, (*ptr)++);
printf(" ");
print_op_num(ops, opcount, (*ptr)++);
printf("\n");
break;

case L2_OP_POP:
printf("POP\n");
break;

case L2_OP_DUP:
printf("DUP\n");
break;

case L2_OP_ADD:
printf("ADD\n");
break;

case L2_OP_CALL:
printf("CALL\n");
break;

case L2_OP_GEN_STACK_FRAME:
printf("GEN_STACK_FRAME\n");
break;

case L2_OP_STACK_FRAME_LOOKUP:
printf("STACK_FRAME_LOOKUP\n");
break;

case L2_OP_STACK_FRAME_SET:
printf("STACK_FRAME_SET\n");
break;

case L2_OP_RET:
printf("RET\n");
break;

case L2_OP_ALLOC_INTEGER_32:
printf("ALLOC_INTEGER_32\n");
break;

case L2_OP_ALLOC_INTEGER_64:
printf("ALLOC_INTEGER_64\n");
break;

case L2_OP_ALLOC_REAL_32:
printf("ALLOC_REAL_32\n");
break;

case L2_OP_ALLOC_REAL_64:
printf("ALLOC_REAL_64\n");
break;

case L2_OP_ALLOC_BUFFER_STATIC:
printf("ALLOC_BUFFER_STATIC\n");
break;

case L2_OP_ALLOC_BUFFER_ZERO:
printf("ALLOC_BUFFER_ZERO\n");
break;

case L2_OP_ALLOC_ARRAY:
printf("ALLOC_ARRAY\n");
break;

case L2_OP_ALLOC_NAMESPACE:
printf("ALLOC_NAMESPACE\n");
break;

case L2_OP_NAMESPACE_SET:
printf("NAMESPACE_SET\n");
break;

case L2_OP_HALT:
printf("HALT\n");
break;
}
}

void l2_vm_print_bytecode(l2_word *ops, size_t opcount) {
size_t ptr = 0;
while (ptr < opcount) {
l2_vm_print_op(ops, opcount, &ptr);
}
}

+ 64
- 38
lib/vm/vm.c View File

@@ -34,35 +34,46 @@ static double u32s_to_double(uint32_t high, uint32_t low) {
return d;
}

static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val);
static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val);

static void gc_mark(struct l2_vm *vm, l2_word id) {
printf("GC MARK %i\n", id);
struct l2_vm_value *val = &vm->values[id];
val->flags |= L2_VAL_MARKED;

int typ = val->flags & 0x0f;
int typ = l2_vm_value_type(*val);
if (typ == L2_VAL_TYPE_ARRAY) {
if (val->data == NULL) {
return;
}

struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
for (size_t i = 0; i < arr->len; ++i) {
gc_mark(vm, arr->data[i]);
}
gc_mark_array(vm, val);
} else if (typ == L2_VAL_TYPE_NAMESPACE) {
if (val->data == NULL) {
return;
}
gc_mark_namespace(vm, val);
}
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
for (size_t i = 0; i < ns->size; ++i) {
l2_word key = ns->data[i];
if (key == 0 || key == ~(l2_word)0) {
continue;
}
static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val) {
if (val->data == NULL) {
return;
}

gc_mark(vm, ns->data[ns->size + i]);
struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
for (size_t i = 0; i < arr->len; ++i) {
gc_mark(vm, arr->data[i]);
}
}

static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val) {
if (val->data == NULL) {
return;
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
for (size_t i = 0; i < ns->size; ++i) {
l2_word key = ns->data[i];
if (key == 0 || key == ~(l2_word)0) {
continue;
}

gc_mark(vm, ns->data[ns->size + i]);
}
}

@@ -71,7 +82,7 @@ static void gc_free(struct l2_vm *vm, l2_word id) {
struct l2_vm_value *val = &vm->values[id];
l2_bitset_unset(&vm->valueset, id);

int typ = val->flags & 0x0f;
int typ = l2_vm_value_type(*val);
if (typ == L2_VAL_TYPE_ARRAY || typ == L2_VAL_TYPE_BUFFER || typ == L2_VAL_TYPE_NAMESPACE) {
free(val->data);
// Don't need to do anything more; the next round of GC will free
@@ -103,6 +114,7 @@ void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
vm->opcount = opcount;
vm->iptr = 0;
vm->sptr = 0;
vm->nsptr = 0;

vm->values = NULL;
vm->valuessize = 0;
@@ -129,10 +141,10 @@ void l2_vm_free(struct l2_vm *vm) {
}

size_t l2_vm_gc(struct l2_vm *vm) {
for (l2_word sptr = 0; sptr < vm->sptr; ++sptr) {
if (vm->stackflags[sptr]) {
gc_mark(vm, vm->stack[sptr]);
}
for (l2_word nsptr = 0; nsptr < vm->nsptr; ++nsptr) {
struct l2_vm_value *val = &vm->values[vm->nstack[nsptr]];
val->flags |= L2_VAL_MARKED;
gc_mark_namespace(vm, val);
}

return gc_sweep(vm);
@@ -154,7 +166,6 @@ void l2_vm_step(struct l2_vm *vm) {

case L2_OP_PUSH:
vm->stack[vm->sptr] = vm->ops[vm->iptr];
vm->stackflags[vm->sptr] = 0;
vm->sptr += 1;
vm->iptr += 1;
break;
@@ -162,8 +173,6 @@ void l2_vm_step(struct l2_vm *vm) {
case L2_OP_PUSH_2:
vm->stack[vm->sptr] = vm->ops[vm->iptr];
vm->stack[vm->sptr + 1] = vm->ops[vm->iptr + 1];
vm->stackflags[vm->sptr] = 0;
vm->stackflags[vm->sptr + 1] = 0;
vm->sptr += 2;
vm->iptr += 2;
break;
@@ -174,26 +183,51 @@ void l2_vm_step(struct l2_vm *vm) {

case L2_OP_DUP:
vm->stack[vm->sptr] = vm->ops[vm->sptr - 1];
vm->stackflags[vm->sptr] = 0;
vm->sptr += 1;
break;

case L2_OP_ADD:
vm->stack[vm->sptr - 2] += vm->stack[vm->sptr - 1];
vm->stackflags[vm->sptr - 2] = 0;
vm->sptr -= 1;
break;

case L2_OP_CALL:
word = vm->stack[vm->sptr - 1];
vm->stack[vm->sptr - 1] = vm->iptr + 1;
vm->stackflags[vm->sptr - 1] = 0;
vm->iptr = word;
break;

case L2_OP_GEN_STACK_FRAME:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
vm->values[word].data = NULL; // Will be allocated on first insert
vm->nstack[vm->nsptr] = word;
vm->nsptr += 1;
break;

case L2_OP_STACK_FRAME_LOOKUP:
{
l2_word key = vm->stack[vm->sptr - 1];
struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
vm->stack[vm->sptr - 1] = l2_vm_namespace_get(ns, key);
}
break;

case L2_OP_STACK_FRAME_SET:
{
l2_word key = vm->stack[vm->sptr - 1];
l2_word val = vm->stack[vm->sptr - 2];
struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
l2_vm_namespace_set(ns, key, val);
vm->sptr -= 1;
}
break;

case L2_OP_RET:
vm->nsptr -= 1;
vm->iptr = vm->stack[vm->sptr - 1];
vm->sptr -= 1;
vm->nsptr -= 1;
break;

case L2_OP_ALLOC_INTEGER_32:
@@ -201,7 +235,6 @@ void l2_vm_step(struct l2_vm *vm) {
vm->values[word].flags = L2_VAL_TYPE_INTEGER;
vm->values[word].integer = vm->stack[--vm->sptr];
vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1;
break;

@@ -213,7 +246,6 @@ void l2_vm_step(struct l2_vm *vm) {
(uint64_t)vm->stack[vm->sptr - 2]);
vm->sptr -= 2;
vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1;
break;

@@ -222,7 +254,6 @@ void l2_vm_step(struct l2_vm *vm) {
vm->values[word].flags = L2_VAL_TYPE_REAL;
vm->values[word].real = u32_to_float(vm->stack[--vm->sptr]);
vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1;
break;

@@ -232,7 +263,6 @@ void l2_vm_step(struct l2_vm *vm) {
vm->values[word].real = u32s_to_double(vm->stack[vm->sptr - 1], vm->stack[vm->sptr - 2]);
vm->sptr -= 2;
vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1;
break;

@@ -248,7 +278,6 @@ void l2_vm_step(struct l2_vm *vm) {
(unsigned char *)vm->values[word].data + sizeof(struct l2_vm_buffer),
vm->ops + offset, length);
vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1;
}
break;
@@ -261,7 +290,6 @@ void l2_vm_step(struct l2_vm *vm) {
vm->values[word].data = calloc(1, sizeof(struct l2_vm_buffer) + length);
((struct l2_vm_buffer *)vm->values[word].data)->len = length;
vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1;
}
break;
@@ -271,7 +299,6 @@ void l2_vm_step(struct l2_vm *vm) {
vm->values[word].flags = L2_VAL_TYPE_ARRAY;
vm->values[word].data = NULL; // Will be allocated on first insert
vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1;
break;

@@ -280,7 +307,6 @@ void l2_vm_step(struct l2_vm *vm) {
vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
vm->values[word].data = NULL; // Will be allocated on first insert
vm->stack[vm->sptr] = word;
vm->stackflags[vm->sptr] = 1;
vm->sptr += 1;
break;


+ 2
- 2
test/build.bx View File

@@ -1,5 +1,5 @@
files := src ../lib
includes := snow ../include/lang2
defines := SNOW_ENABLED
sanitizers := address
cflags := -g -O3
#sanitizers := address undefined
cflags := -g

+ 50
- 0
test/src/eval.t.c View File

@@ -0,0 +1,50 @@
#include "parse/parse.h"
#include "vm/vm.h"
#include "vm/print.h"

#include <stdio.h>
#include <snow/snow.h>

static struct l2_lexer lex;
static struct l2_io_mem_reader r;
static struct l2_generator gen;
static struct l2_io_mem_writer w;
static struct l2_vm vm;
static struct l2_parse_error err;

static struct l2_vm_value *var_lookup(const char *name) {
l2_word atom_id = l2_strset_get(&gen.atoms, name);
l2_word id = l2_vm_namespace_get(&vm.values[vm.nstack[0]], atom_id);
return &vm.values[id];
}

static void init(const char *str) {
r.r.read = l2_io_mem_read;
r.idx = 0;
r.len = strlen(str);
r.mem = str;
l2_lexer_init(&lex, &r.r);

w.w.write = l2_io_mem_write;
w.len = 0;
w.mem = NULL;
l2_gen_init(&gen, (struct l2_io_writer *)&w);
}

static void done() {
l2_gen_free(&gen);
free(w.mem);
}

describe(parse) {
test("parse program") {
init("foo := 10");
defer(done());
assert(l2_parse_program(&lex, &gen, &err) >= 0);

l2_vm_init(&vm, (l2_word *)w.mem, w.len / sizeof(l2_word));
l2_vm_run(&vm);
assert(l2_vm_value_type(*var_lookup("foo")) == L2_VAL_TYPE_REAL);
assert(var_lookup("foo")->real == 10);
}
}

Loading…
Cancel
Save