Browse Source

mostly parsing stuuff

master
Martin Dørum 3 years 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

printf("Options:\n"); printf("Options:\n");
printf(" --help: Print this help text\n"); printf(" --help: Print this help text\n");
printf(" --bytecode: Print the generated bytecode, don't execute\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"); printf(" --step: Step through the program\n");
} }


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


int was_inf_set = 0; int was_inf_set = 0;
return 0; return 0;
} else if (!dashes && strcmp(argv[i], "--bytecode") == 0) { } else if (!dashes && strcmp(argv[i], "--bytecode") == 0) {
do_print_bytecode = 1; do_print_bytecode = 1;
} else if (!dashes && strcmp(argv[i], "--tokens") == 0) {
do_print_tokens = 1;
} else if (!dashes && strcmp(argv[i], "--step") == 0) { } else if (!dashes && strcmp(argv[i], "--step") == 0) {
do_step = 1; do_step = 1;
} else if (strcmp(argv[i], "--") == 0) { } else if (strcmp(argv[i], "--") == 0) {
r.f = inf; r.f = inf;
struct l2_lexer lexer; struct l2_lexer lexer;
l2_lexer_init(&lexer, &r.r); l2_lexer_init(&lexer, &r.r);
if (do_print_tokens) {
lexer.do_log_tokens = 1;
}


// Init gen with its output writer // Init gen with its output writer
struct l2_io_mem_writer w = {0}; struct l2_io_mem_writer w = {0};


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

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

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

/* /*
* Call a function. * Call a function.
* Pop <argc> * Pop <argc>
* Pop <func>
* Pop argc times * Pop argc times
* Pop <func>
* Push <iptr> + 1 * Push <iptr> + 1
* Push array with args * Push array with args
* Call <func> * Call <func>

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

int line; int line;
int ch; int ch;
int parens; int parens;
int do_log_tokens;


struct l2_bufio_reader reader; struct l2_bufio_reader reader;
}; };

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

#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



#include <stdlib.h> #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) { static int parse_number(const char *str, double *num) {
// TODO: Floats // TODO: Floats
size_t len = strlen(str); size_t len = strlen(str);
lexer->line = 1; lexer->line = 1;
lexer->ch = 1; lexer->ch = 1;
lexer->parens = 0; lexer->parens = 0;
lexer->do_log_tokens = 0;
l2_bufio_reader_init(&lexer->reader, r); l2_bufio_reader_init(&lexer->reader, r);
} }




while (offset >= lexer->tokidx) { while (offset >= lexer->tokidx) {
read_tok(lexer, &lexer->toks[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]; return &lexer->toks[offset];

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

#include "parse/parse.h" #include "parse/parse.h"


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


static int is_end_tok(struct l2_token *tok) { static int is_end_tok(struct l2_token *tok) {
tok->kind == L2_TOK_EOF; 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( 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);


static int parse_object( static int parse_object(
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_trace_func();
// { and EOL are already skipped // { and EOL are already skipped


l2_gen_namespace(gen); l2_gen_namespace(gen);
break; break;
} }


l2_trace_scope("object key/val");

if (tok->kind != L2_TOK_IDENT) { if (tok->kind != L2_TOK_IDENT) {
l2_parse_err(err, tok, "In object literal: Expected identifier, got %s\n", l2_parse_err(err, tok, "In object literal: Expected identifier, got %s\n",
l2_token_kind_name(tok->kind)); l2_token_kind_name(tok->kind));


static int parse_function_impl( static int parse_function_impl(
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_trace_func();
// { and EOL are already skipped // { and EOL are already skipped


int first = 1; int first = 1;
while (1) { while (1) {
l2_trace_scope("function expr");
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) {
l2_parse_err(err, tok, "In function: Unexpected EOF"); l2_parse_err(err, tok, "In function: Unexpected EOF");


static int parse_function_or_object( static int parse_function_or_object(
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_trace_func();
l2_lexer_consume(lexer); // { l2_lexer_consume(lexer); // {
l2_lexer_skip_opt(lexer, L2_TOK_EOL); l2_lexer_skip_opt(lexer, L2_TOK_EOL);


} }
} }


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( static int parse_sub_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) {
l2_trace_func();
struct l2_token *tok = l2_lexer_peek(lexer, 1); struct l2_token *tok = l2_lexer_peek(lexer, 1);
struct l2_token *tok2 = l2_lexer_peek(lexer, 2); struct l2_token *tok2 = l2_lexer_peek(lexer, 2);


tok = l2_lexer_peek(lexer, 1); tok = l2_lexer_peek(lexer, 1);
tok2 = l2_lexer_peek(lexer, 2); 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) { if (parse_expression(lexer, gen, err) < 0) {
return -1; return -1;
} }
} }


l2_lexer_consume(lexer); // ) l2_lexer_consume(lexer); // )
return 0;
} else if (tok->kind == L2_TOK_NUMBER) { } else if (tok->kind == L2_TOK_NUMBER) {
l2_trace_scope("number");
l2_gen_number(gen, tok->v.num); l2_gen_number(gen, tok->v.num);
l2_lexer_consume(lexer); // number l2_lexer_consume(lexer); // number
return 0;
} else if (tok->kind == L2_TOK_IDENT) { } else if (tok->kind == L2_TOK_IDENT) {
l2_trace_scope("ident");
char *ident = l2_token_extract_str(tok); char *ident = l2_token_extract_str(tok);
l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident
l2_gen_stack_frame_lookup(gen, &ident); l2_gen_stack_frame_lookup(gen, &ident);
return 0;
} else if (tok->kind == L2_TOK_QUOT && tok2->kind == L2_TOK_IDENT) { } else if (tok->kind == L2_TOK_QUOT && tok2->kind == L2_TOK_IDENT) {
l2_trace_scope("atom");
char *str = l2_token_extract_str(tok2); char *str = l2_token_extract_str(tok2);
l2_lexer_consume(lexer); // ' l2_lexer_consume(lexer); // '
l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident
l2_gen_atom(gen, &str); l2_gen_atom(gen, &str);
return 0;
} else if (tok->kind == L2_TOK_STRING) { } else if (tok->kind == L2_TOK_STRING) {
l2_trace_scope("string");
char *str = l2_token_extract_str(tok); char *str = l2_token_extract_str(tok);
l2_lexer_consume(lexer); // string l2_lexer_consume(lexer); // string
l2_gen_string(gen, &str); l2_gen_string(gen, &str);
return 0;
} else if (tok->kind == L2_TOK_OPEN_BRACE) { } 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( 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) {
l2_trace_func();
struct l2_token *tok = l2_lexer_peek(lexer, 1); struct l2_token *tok = l2_lexer_peek(lexer, 1);
struct l2_token *tok2 = l2_lexer_peek(lexer, 2); struct l2_token *tok2 = l2_lexer_peek(lexer, 2);


if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) { if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) {
l2_trace_scope("assignment");
char *ident = l2_token_extract_str(tok); char *ident = l2_token_extract_str(tok);
l2_lexer_consume(lexer); // ident l2_lexer_consume(lexer); // ident
l2_lexer_consume(lexer); // := l2_lexer_consume(lexer); // :=
} }


l2_gen_assignment(gen, &ident); 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( int l2_parse_program(
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_trace_func();
l2_lexer_skip_opt(lexer, L2_TOK_EOL); l2_lexer_skip_opt(lexer, L2_TOK_EOL);


int first = 1; int first = 1;

+ 35
- 0
lib/trace.c View File

#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



case L2_OP_FUNC_CALL: case L2_OP_FUNC_CALL:
{ {
l2_word func_id = vm->stack[--vm->sptr];
l2_word argc = 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); l2_word arr_id = alloc_val(vm);
vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY; vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY;
arr->data[i] = vm->stack[vm->sptr + i]; 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); enum l2_value_type typ = l2_vm_value_type(func);


// C functions are called differently from language functions // C functions are called differently from language functions

Loading…
Cancel
Save