Browse Source

mostly parsing stuuff

master
Martin Dørum 1 year ago
parent
commit
41331f4be0
8 changed files with 191 additions and 41 deletions
  1. 10
    0
      cmd/main.c
  2. 1
    1
      include/lang2/bytecode.h
  3. 1
    0
      include/lang2/parse/lex.h
  4. 33
    0
      include/lang2/trace.h
  5. 25
    0
      lib/parse/lex.c
  6. 83
    38
      lib/parse/parse.c
  7. 35
    0
      lib/trace.c
  8. 3
    2
      lib/vm/vm.c

+ 10
- 0
cmd/main.c View File

@@ -29,11 +29,13 @@ static void usage(const char *argv0) {
printf("Options:\n");
printf(" --help: Print this help text\n");
printf(" --bytecode: Print the generated bytecode, don't execute\n");
printf(" --tokens: Print the tokens as the program is parsed, don't execute\n");
printf(" --step: Step through the program\n");
}

int main(int argc, char **argv) {
int do_print_bytecode = 0;
int do_print_tokens = 0;
int do_step = 0;

int was_inf_set = 0;
@@ -46,6 +48,8 @@ int main(int argc, char **argv) {
return 0;
} else if (!dashes && strcmp(argv[i], "--bytecode") == 0) {
do_print_bytecode = 1;
} else if (!dashes && strcmp(argv[i], "--tokens") == 0) {
do_print_tokens = 1;
} else if (!dashes && strcmp(argv[i], "--step") == 0) {
do_step = 1;
} else if (strcmp(argv[i], "--") == 0) {
@@ -72,6 +76,9 @@ int main(int argc, char **argv) {
r.f = inf;
struct l2_lexer lexer;
l2_lexer_init(&lexer, &r.r);
if (do_print_tokens) {
lexer.do_log_tokens = 1;
}

// Init gen with its output writer
struct l2_io_mem_writer w = {0};
@@ -93,6 +100,9 @@ int main(int argc, char **argv) {

if (do_print_bytecode) {
l2_vm_print_bytecode((l2_word *)w.mem, w.len / sizeof(l2_word));
}

if (do_print_bytecode || do_print_tokens) {
free(w.mem);
return 0;
}

+ 1
- 1
include/lang2/bytecode.h View File

@@ -47,8 +47,8 @@ enum l2_opcode {
/*
* Call a function.
* Pop <argc>
* Pop <func>
* Pop argc times
* Pop <func>
* Push <iptr> + 1
* Push array with args
* Call <func>

+ 1
- 0
include/lang2/parse/lex.h View File

@@ -46,6 +46,7 @@ struct l2_lexer {
int line;
int ch;
int parens;
int do_log_tokens;

struct l2_bufio_reader reader;
};

+ 33
- 0
include/lang2/trace.h View File

@@ -0,0 +1,33 @@
#ifndef L2_TRACE_H
#define L2_TRACE_H

#ifndef L2_ENABLE_TRACE

#define l2_trace_scope(name) do {} while (0)
#define l2_trace_func() do {} while (0)
#define l2_trace_push(name) do {} while (0)
#define l2_trace_pop() do {} while (0)
#define l2_trace(name) do {} while (0)

#else

extern int l2_trace_depth;

#ifdef __GNUC__
#define l2_trace_scope(name) \
l2_trace_push(name); \
__attribute__((cleanup(l2_trace_cleanup))) int l2_trace_scope
#define l2_trace_func() l2_trace_scope(__func__)
#else
#define l2_trace_scope(name) l2_trace(name)
#define l2_trace_func() l2_trace(__func__)
#endif

void l2_trace_push(const char *name);
void l2_trace_pop();
void l2_trace(const char *name);
void l2_trace_cleanup(void *unused);

#endif

#endif

+ 25
- 0
lib/parse/lex.c View File

@@ -2,6 +2,27 @@

#include <stdlib.h>

static void log_token(struct l2_token *tok) {
switch (tok->kind) {
case L2_TOK_STRING:
case L2_TOK_IDENT:
case L2_TOK_ERROR:
printf("%i:%i\t%s '%s'\n", tok->line, tok->ch,
l2_token_kind_name(tok->kind), tok->v.str);
break;

case L2_TOK_NUMBER:
printf("%i:%i\t%s '%g'\n", tok->line, tok->ch,
l2_token_kind_name(tok->kind), tok->v.num);
break;

default:
printf("%i:%i\t%s\n", tok->line, tok->ch,
l2_token_kind_name(tok->kind));
break;
}
}

static int parse_number(const char *str, double *num) {
// TODO: Floats
size_t len = strlen(str);
@@ -77,6 +98,7 @@ void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) {
lexer->line = 1;
lexer->ch = 1;
lexer->parens = 0;
lexer->do_log_tokens = 0;
l2_bufio_reader_init(&lexer->reader, r);
}

@@ -342,6 +364,9 @@ struct l2_token *l2_lexer_peek(struct l2_lexer *lexer, int count) {

while (offset >= lexer->tokidx) {
read_tok(lexer, &lexer->toks[lexer->tokidx++]);
if (lexer->do_log_tokens) {
log_token(&lexer->toks[lexer->tokidx - 1]);
}
}

return &lexer->toks[offset];

+ 83
- 38
lib/parse/parse.c View File

@@ -1,5 +1,6 @@
#include "parse/parse.h"

#include "trace.h"
#include "gen/gen.h"

static int is_end_tok(struct l2_token *tok) {
@@ -9,11 +10,19 @@ static int is_end_tok(struct l2_token *tok) {
tok->kind == L2_TOK_EOF;
}

static int is_sub_expr_tok(struct l2_token *tok) {
return
tok->kind == L2_TOK_IDENT || tok->kind == L2_TOK_OPEN_PAREN ||
tok->kind == L2_TOK_OPEN_BRACE || tok->kind == L2_TOK_OPEN_BRACKET ||
tok->kind == L2_TOK_STRING || tok->kind == L2_TOK_NUMBER;
}

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

static int parse_object(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_func();
// { and EOL are already skipped

l2_gen_namespace(gen);
@@ -27,6 +36,8 @@ static int parse_object(
break;
}

l2_trace_scope("object key/val");

if (tok->kind != L2_TOK_IDENT) {
l2_parse_err(err, tok, "In object literal: Expected identifier, got %s\n",
l2_token_kind_name(tok->kind));
@@ -65,10 +76,12 @@ static int parse_object(

static int parse_function_impl(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_func();
// { and EOL are already skipped

int first = 1;
while (1) {
l2_trace_scope("function expr");
struct l2_token *tok = l2_lexer_peek(lexer, 1);
if (tok->kind == L2_TOK_EOF) {
l2_parse_err(err, tok, "In function: Unexpected EOF");
@@ -142,6 +155,7 @@ static int parse_function(

static int parse_function_or_object(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_func();
l2_lexer_consume(lexer); // {
l2_lexer_skip_opt(lexer, L2_TOK_EOL);

@@ -159,8 +173,51 @@ static int parse_function_or_object(
}
}

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

static int parse_opt_post_sub_expr(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_func();
struct l2_token *tok = l2_lexer_peek(lexer, 1);
struct l2_token *tok2 = l2_lexer_peek(lexer, 2);

if (tok->kind == L2_TOK_OPEN_PAREN && tok2->kind == L2_TOK_CLOSE_PAREN) {
l2_trace_scope("noadic func call");
l2_lexer_consume(lexer); // (
l2_lexer_consume(lexer); // )
l2_gen_push(gen, 0);
l2_gen_func_call(gen);
} else if (is_sub_expr_tok(tok)) {
l2_trace_scope("func call");
l2_word count = 0;
while (!is_end_tok(l2_lexer_peek(lexer, 1))) {
count += 1;
if (parse_sub_expression(lexer, gen, err) < 0) {
return -1;
}
}

l2_gen_push(gen, count);
l2_gen_func_call(gen);
} else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT) {
l2_trace_scope("lookup");
char *ident = l2_token_extract_str(tok2);
l2_lexer_consume(lexer); // .
l2_lexer_consume(lexer); // ident
l2_gen_namespace_lookup(gen, &ident);
} else {
l2_parse_err(err, tok, "In post expression: Unexpected token %s",
l2_token_kind_name(tok->kind));
return -1;
}

return 0;
}

static int parse_sub_expression(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_func();
struct l2_token *tok = l2_lexer_peek(lexer, 1);
struct l2_token *tok2 = l2_lexer_peek(lexer, 2);

@@ -169,18 +226,7 @@ static int parse_sub_expression(
tok = l2_lexer_peek(lexer, 1);
tok2 = l2_lexer_peek(lexer, 2);

// Special case: (foo) should be interpreted as a function call
if (tok->kind == L2_TOK_IDENT && tok2->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_stack_frame_lookup(gen, &ident);
l2_gen_func_call(gen);
return 0;
}

l2_trace_scope("parenthesized expression");
if (parse_expression(lexer, gen, err) < 0) {
return -1;
}
@@ -192,42 +238,53 @@ static int parse_sub_expression(
}

l2_lexer_consume(lexer); // )
return 0;
} else if (tok->kind == L2_TOK_NUMBER) {
l2_trace_scope("number");
l2_gen_number(gen, tok->v.num);
l2_lexer_consume(lexer); // number
return 0;
} else if (tok->kind == L2_TOK_IDENT) {
l2_trace_scope("ident");
char *ident = l2_token_extract_str(tok);
l2_lexer_consume(lexer); // ident
l2_gen_stack_frame_lookup(gen, &ident);
return 0;
} else if (tok->kind == L2_TOK_QUOT && tok2->kind == L2_TOK_IDENT) {
l2_trace_scope("atom");
char *str = l2_token_extract_str(tok2);
l2_lexer_consume(lexer); // '
l2_lexer_consume(lexer); // ident
l2_gen_atom(gen, &str);
return 0;
} else if (tok->kind == L2_TOK_STRING) {
l2_trace_scope("string");
char *str = l2_token_extract_str(tok);
l2_lexer_consume(lexer); // string
l2_gen_string(gen, &str);
return 0;
} else if (tok->kind == L2_TOK_OPEN_BRACE) {
return parse_function_or_object(lexer, gen, err);
if (parse_function_or_object(lexer, gen, err) < 0) {
return -1;
}
} else {
l2_parse_err(err, tok, "In expression: Unexpected token %s",
l2_token_kind_name(tok->kind));
return -1;
}

while (!is_end_tok(l2_lexer_peek(lexer, 1))) {
if (parse_opt_post_sub_expr(lexer, gen, err) < 0) {
return -1;
}
}

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

static int parse_expression(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_func();
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) {
l2_trace_scope("assignment");
char *ident = l2_token_extract_str(tok);
l2_lexer_consume(lexer); // ident
l2_lexer_consume(lexer); // :=
@@ -238,30 +295,18 @@ static int parse_expression(
}

l2_gen_assignment(gen, &ident);
return 0;
} else if (tok->kind == L2_TOK_IDENT && !is_end_tok(tok2)) {
char *ident = l2_token_extract_str(tok);
l2_lexer_consume(lexer);

l2_word count = 0;
while (!is_end_tok(l2_lexer_peek(lexer, 1))) {
count += 1;
if (parse_sub_expression(lexer, gen, err) < 0) {
return -1;
}
} else {
if (parse_sub_expression(lexer, gen, err) < 0) {
return -1;
}

l2_gen_push(gen, count);
l2_gen_stack_frame_lookup(gen, &ident);
l2_gen_func_call(gen);
return 0;
}

return parse_sub_expression(lexer, gen, err);
return 0;
}

int l2_parse_program(
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) {
l2_trace_func();
l2_lexer_skip_opt(lexer, L2_TOK_EOL);

int first = 1;

+ 35
- 0
lib/trace.c View File

@@ -0,0 +1,35 @@
#include "trace.h"

#ifdef L2_ENABLE_TRACE

#include <stdio.h>

int l2_trace_depth = 0;

void l2_trace_push(const char *name) {
for (int i = 0; i < l2_trace_depth; ++i) {
fprintf(stderr, " ");
}

fprintf(stderr, "%s {\n", name);
l2_trace_depth += 1;
}

void l2_trace_pop() {
l2_trace_depth -= 1;
for (int i = 0; i < l2_trace_depth; ++i) {
fprintf(stderr, " ");
}

fprintf(stderr, "}\n");
}

void l2_trace(const char *name) {
fprintf(stderr, "TRACE %s\n", name);
}

void l2_trace_cleanup(void *unused) {
l2_trace_pop();
}

#endif

+ 3
- 2
lib/vm/vm.c View File

@@ -238,9 +238,7 @@ void l2_vm_step(struct l2_vm *vm) {

case L2_OP_FUNC_CALL:
{
l2_word func_id = vm->stack[--vm->sptr];
l2_word argc = vm->stack[--vm->sptr];
struct l2_vm_value *func = &vm->values[func_id];

l2_word arr_id = alloc_val(vm);
vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY;
@@ -255,6 +253,9 @@ void l2_vm_step(struct l2_vm *vm) {
arr->data[i] = vm->stack[vm->sptr + i];
}

l2_word func_id = vm->stack[--vm->sptr];
struct l2_vm_value *func = &vm->values[func_id];

enum l2_value_type typ = l2_vm_value_type(func);

// C functions are called differently from language functions

Loading…
Cancel
Save