| @@ -117,6 +117,16 @@ enum l2_opcode { | |||
| */ | |||
| L2_OP_ALLOC_NAMESPACE, | |||
| /* | |||
| * Set a namespace's name to a value. | |||
| * Pop <key> | |||
| * Pop <val> | |||
| * Read <ns> | |||
| * Assign <val> to <ns[<key>]> | |||
| * Push <val> | |||
| */ | |||
| L2_OP_NAMESPACE_SET, | |||
| /* | |||
| * Halt execution. | |||
| */ | |||
| @@ -2,7 +2,17 @@ | |||
| #define L2_GEN_H | |||
| #include "../io.h" | |||
| #include "../strset.h" | |||
| void l2_gen_stack_frame(struct l2_bufio_writer *writer); | |||
| struct l2_generator { | |||
| struct l2_strset atoms; | |||
| struct l2_strset strings; | |||
| struct l2_bufio_writer writer; | |||
| }; | |||
| void l2_gen_init(struct l2_generator *gen); | |||
| void l2_gen_free(struct l2_generator *gen); | |||
| void l2_gen_stack_frame(struct l2_generator *gen); | |||
| void l2_gen_assignment(struct l2_generator *gen, char **ident); | |||
| #endif | |||
| @@ -12,9 +12,11 @@ enum l2_token_kind { | |||
| L2_TOK_CLOSE_BRACKET, | |||
| L2_TOK_COMMA, | |||
| L2_TOK_PERIOD, | |||
| L2_TOK_COLON_EQ, | |||
| L2_TOK_EOF, | |||
| L2_TOK_NUMBER, | |||
| L2_TOK_STRING, | |||
| L2_TOK_IDENT, | |||
| L2_TOK_ERROR, | |||
| }; | |||
| @@ -2,20 +2,8 @@ | |||
| #define L2_PARSE_H | |||
| #include "lex.h" | |||
| #include "../io.h" | |||
| #include "../strset.h" | |||
| #include "gen/gen.h" | |||
| struct l2_parse_state { | |||
| struct l2_lexer *lexer; | |||
| struct l2_bufio_writer writer; | |||
| struct l2_strset atoms; | |||
| struct l2_strset strings; | |||
| }; | |||
| void l2_parse_init( | |||
| struct l2_parse_state *state, | |||
| struct l2_lexer *lexer, struct l2_io_writer *w); | |||
| void l2_parse_free(struct l2_parse_state *state); | |||
| void l2_parse_program(struct l2_parse_state *state); | |||
| void l2_parse_program(struct l2_lexer *lexer, struct l2_generator *gen); | |||
| #endif | |||
| @@ -14,7 +14,7 @@ struct l2_strset { | |||
| void l2_strset_init(struct l2_strset *set); | |||
| void l2_strset_free(struct l2_strset *set); | |||
| size_t l2_strset_put_move(struct l2_strset *set, char **str); | |||
| size_t l2_strset_put(struct l2_strset *set, char **str); | |||
| size_t l2_strset_put_copy(struct l2_strset *set, const char *str); | |||
| size_t l2_strset_get(struct l2_strset *set, const char *str); | |||
| @@ -2,10 +2,27 @@ | |||
| #include "bytecode.h" | |||
| static void put(struct l2_bufio_writer *writer, l2_word word) { | |||
| l2_bufio_put_n(writer, &word, sizeof(word)); | |||
| static void put(struct l2_generator *gen, l2_word word) { | |||
| l2_bufio_put_n(&gen->writer, &word, sizeof(word)); | |||
| } | |||
| void l2_gen_stack_frame(struct l2_bufio_writer *writer) { | |||
| put(writer, L2_OP_ALLOC_NAMESPACE); | |||
| void l2_gen_init(struct l2_generator *gen) { | |||
| l2_strset_init(&gen->atoms); | |||
| l2_strset_init(&gen->strings); | |||
| } | |||
| void l2_gen_free(struct l2_generator *gen) { | |||
| l2_strset_free(&gen->atoms); | |||
| l2_strset_free(&gen->strings); | |||
| } | |||
| void l2_gen_stack_frame(struct l2_generator *gen) { | |||
| put(gen, L2_OP_ALLOC_NAMESPACE); | |||
| } | |||
| 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); | |||
| } | |||
| @@ -20,12 +20,16 @@ const char *l2_token_kind_name(enum l2_token_kind kind) { | |||
| return "comma"; | |||
| case L2_TOK_PERIOD: | |||
| return "period"; | |||
| case L2_TOK_COLON_EQ: | |||
| return "period"; | |||
| case L2_TOK_EOF: | |||
| return "end-of-file"; | |||
| case L2_TOK_NUMBER: | |||
| return "number"; | |||
| case L2_TOK_STRING: | |||
| return "string"; | |||
| case L2_TOK_IDENT: | |||
| return "ident"; | |||
| case L2_TOK_ERROR: | |||
| return "error"; | |||
| } | |||
| @@ -54,6 +58,11 @@ void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) { | |||
| l2_bufio_reader_init(&lexer->reader, r); | |||
| } | |||
| static int peek_ch(struct l2_lexer *lexer) { | |||
| int ch = l2_bufio_peek(&lexer->reader, 1); | |||
| return ch; | |||
| } | |||
| static int read_ch(struct l2_lexer *lexer) { | |||
| int ch = l2_bufio_get(&lexer->reader); | |||
| lexer->ch += 1; | |||
| @@ -137,6 +146,55 @@ static void read_string(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| } | |||
| } | |||
| static void read_ident(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| tok->kind = L2_TOK_IDENT; | |||
| tok->v.str = malloc(16); | |||
| if (tok->v.str == NULL) { | |||
| tok->kind = L2_TOK_ERROR; | |||
| tok->v.str = "Allocaton failure"; | |||
| return; | |||
| } | |||
| size_t size = 16; | |||
| size_t idx = 0; | |||
| while (1) { | |||
| int ch = peek_ch(lexer); | |||
| if (is_whitespace(ch)) { | |||
| return; | |||
| } | |||
| switch (ch) { | |||
| case '(': | |||
| case ')': | |||
| case '{': | |||
| case '}': | |||
| case '[': | |||
| case ']': | |||
| case ',': | |||
| case '.': | |||
| case ':': | |||
| case EOF: | |||
| return; | |||
| } | |||
| tok->v.str[idx++] = (char)read_ch(lexer); | |||
| if (idx >= size) { | |||
| size *= 2; | |||
| char *newbuf = realloc(tok->v.str, size); | |||
| if (newbuf == NULL) { | |||
| free(tok->v.str); | |||
| tok->kind = L2_TOK_ERROR; | |||
| tok->v.str = "Allocation failure"; | |||
| return; | |||
| } | |||
| tok->v.str = newbuf; | |||
| } | |||
| } | |||
| } | |||
| static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| skip_whitespace(lexer); | |||
| @@ -177,6 +235,22 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| tok->kind = L2_TOK_PERIOD; | |||
| break; | |||
| case ':': | |||
| { | |||
| ch = read_ch(lexer); | |||
| switch (ch) { | |||
| case '=': | |||
| tok->kind = L2_TOK_COLON_EQ; | |||
| break; | |||
| default: | |||
| tok->kind = L2_TOK_ERROR; | |||
| tok->v.str = "Unexpected character"; | |||
| break; | |||
| } | |||
| } | |||
| break; | |||
| case EOF: | |||
| tok->kind = L2_TOK_EOF; | |||
| break; | |||
| @@ -184,6 +258,10 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| case '"': | |||
| read_string(lexer, tok); | |||
| break; | |||
| default: | |||
| read_ident(lexer, tok); | |||
| break; | |||
| } | |||
| } | |||
| @@ -2,20 +2,25 @@ | |||
| #include "gen/gen.h" | |||
| void l2_parse_init( | |||
| struct l2_parse_state *state, | |||
| struct l2_lexer *lexer, struct l2_io_writer *w) { | |||
| state->lexer = lexer; | |||
| l2_bufio_writer_init(&state->writer, w); | |||
| l2_strset_init(&state->atoms); | |||
| l2_strset_init(&state->strings); | |||
| } | |||
| static void parse_expression(struct l2_lexer *lexer, struct l2_generator *gen) { | |||
| struct l2_token *tok = l2_lexer_peek(lexer, 1); | |||
| struct l2_token *tok2 = l2_lexer_peek(lexer, 2); | |||
| void l2_parse_free(struct l2_parse_state *state) { | |||
| l2_strset_free(&state->atoms); | |||
| l2_strset_free(&state->strings); | |||
| if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) { | |||
| parse_expression(lexer, gen); | |||
| l2_gen_assignment(gen, &tok->v.str); | |||
| } | |||
| } | |||
| void l2_parse_program(struct l2_parse_state *state) { | |||
| l2_gen_stack_frame(&state->writer); | |||
| void l2_parse_program(struct l2_lexer *lexer, struct l2_generator *gen) { | |||
| l2_gen_stack_frame(gen); | |||
| while (1) { | |||
| struct l2_token *tok = l2_lexer_peek(lexer, 1); | |||
| if (tok->kind == L2_TOK_EOF) { | |||
| break; | |||
| } | |||
| parse_expression(lexer, gen); | |||
| } | |||
| } | |||
| @@ -67,7 +67,7 @@ void l2_strset_free(struct l2_strset *set) { | |||
| free(set->vals); | |||
| } | |||
| size_t l2_strset_put_move(struct l2_strset *set, char **str) { | |||
| size_t l2_strset_put(struct l2_strset *set, char **str) { | |||
| if (set->len >= set->size / 2) { | |||
| grow(set); | |||
| } | |||