Browse Source

started on functions

master
Martin Dørum 3 years ago
parent
commit
feaef07544
8 changed files with 172 additions and 41 deletions
  1. 39
    28
      cmd/main.c
  2. 8
    0
      include/lang2/bytecode.h
  3. 4
    0
      include/lang2/gen/gen.h
  4. 5
    0
      include/lang2/vm/vm.h
  5. 21
    13
      lib/gen/gen.c
  6. 66
    0
      lib/parse/parse.c
  7. 12
    0
      lib/vm/print.c
  8. 17
    0
      lib/vm/vm.c

+ 39
- 28
cmd/main.c View File

@@ -1,42 +1,53 @@
#include "vm/vm.h"
#include "vm/print.h"
#include "parse/parse.h"
#include "parse/lex.h"
#include "io.h"
#include "bitset.h"

#include <stdio.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);
}

+ 8
- 0
include/lang2/bytecode.h View File

@@ -155,6 +155,14 @@ enum l2_opcode {
*/
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.
* Pop <key>

+ 4
- 0
include/lang2/gen/gen.h View File

@@ -24,9 +24,13 @@ 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_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_number(struct l2_generator *gen, double num);
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);

#endif

+ 5
- 0
include/lang2/vm/vm.h View File

@@ -14,12 +14,17 @@ struct l2_vm_value {
L2_VAL_TYPE_BUFFER,
L2_VAL_TYPE_ARRAY,
L2_VAL_TYPE_NAMESPACE,
L2_VAL_TYPE_FUNCTION,
L2_VAL_MARKED = 1 << 7,
L2_VAL_CONST = 1 << 8,
} flags;
union {
int64_t integer;
double real;
struct {
l2_word pos;
l2_word namespace;
} func;
void *data;
};
};

+ 21
- 13
lib/gen/gen.c View File

@@ -24,23 +24,28 @@ void l2_gen_free(struct l2_generator *gen) {
l2_strset_free(&gen->stringset);
}

// 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_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) {
size_t atom_id = l2_strset_put(&gen->atomset, ident);
put(gen, L2_OP_PUSH);
@@ -48,8 +53,6 @@ void l2_gen_assignment(struct l2_generator *gen, char **ident) {
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));
@@ -70,6 +73,7 @@ void l2_gen_string(struct l2_generator *gen, char **str) {

put(gen, L2_OP_PUSH);
put(gen, aligned / sizeof(l2_word));
put(gen, L2_OP_RJMP);
l2_word pos = gen->pos;

l2_bufio_put_n(&gen->writer, *str, len);
@@ -95,8 +99,12 @@ void l2_gen_string(struct l2_generator *gen, char **str) {
}
}

// 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) {
size_t atom_id = l2_strset_put(&gen->atomset, ident);
put(gen, L2_OP_PUSH);

+ 66
- 0
lib/parse/parse.c View File

@@ -1,7 +1,62 @@
#include "parse/parse.h"

#include <stdbool.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(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
struct l2_token *tok = l2_lexer_peek(lexer, 1);
@@ -33,6 +88,8 @@ static int parse_expression(
l2_lexer_consume(lexer); // string
l2_gen_string(gen, &str);
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",
@@ -44,17 +101,26 @@ int l2_parse_program(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_gen_stack_frame(gen);

bool first = true;

while (1) {
struct l2_token *tok = l2_lexer_peek(lexer, 1);
if (tok->kind == L2_TOK_EOF) {
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) {
l2_gen_halt(gen);
l2_gen_flush(gen);
return -1;
}

first = false;
}

l2_gen_halt(gen);

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

@@ -57,6 +57,10 @@ void l2_vm_print_val(struct l2_vm_value *val) {
printf("NAMESPACE, len %zu\n", ns->len);
}
break;

case L2_VAL_TYPE_FUNCTION:
printf("FUNCTION, pos %u, ns %u\n", val->func.pos, val->func.namespace);
break;
}
}

@@ -136,6 +140,10 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
printf("CALL\n");
break;

case L2_OP_RJMP:
printf("RJMP\n");
break;

case L2_OP_GEN_STACK_FRAME:
printf("GEN_STACK_FRAME\n");
break;
@@ -184,6 +192,10 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
printf("ALLOC_NAMESPACE\n");
break;

case L2_OP_ALLOC_FUNCTION:
printf("ALLOC_FUNCTION\n");
break;

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

+ 17
- 0
lib/vm/vm.c View File

@@ -47,6 +47,8 @@ static void gc_mark(struct l2_vm *vm, l2_word id) {
gc_mark_array(vm, val);
} else if (typ == L2_VAL_TYPE_NAMESPACE) {
gc_mark_namespace(vm, val);
} else if (typ == L2_VAL_TYPE_FUNCTION) {
gc_mark_namespace(vm, &vm->values[val->func.namespace]);
}
}

@@ -196,6 +198,12 @@ void l2_vm_step(struct l2_vm *vm) {
vm->iptr = word;
break;

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

case L2_OP_GEN_STACK_FRAME:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
@@ -309,6 +317,15 @@ void l2_vm_step(struct l2_vm *vm) {
vm->sptr += 1;
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:
{
l2_word key = vm->stack[vm->sptr - 1];

Loading…
Cancel
Save