| */ | */ | ||||
| L2_OP_ALLOC_NAMESPACE, | 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. | * Halt execution. | ||||
| */ | */ |
| #define L2_GEN_H | #define L2_GEN_H | ||||
| #include "../io.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 | #endif |
| L2_TOK_CLOSE_BRACKET, | L2_TOK_CLOSE_BRACKET, | ||||
| L2_TOK_COMMA, | L2_TOK_COMMA, | ||||
| L2_TOK_PERIOD, | L2_TOK_PERIOD, | ||||
| L2_TOK_COLON_EQ, | |||||
| L2_TOK_EOF, | L2_TOK_EOF, | ||||
| L2_TOK_NUMBER, | L2_TOK_NUMBER, | ||||
| L2_TOK_STRING, | L2_TOK_STRING, | ||||
| L2_TOK_IDENT, | |||||
| L2_TOK_ERROR, | L2_TOK_ERROR, | ||||
| }; | }; | ||||
| #define L2_PARSE_H | #define L2_PARSE_H | ||||
| #include "lex.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 | #endif |
| void l2_strset_init(struct l2_strset *set); | void l2_strset_init(struct l2_strset *set); | ||||
| void l2_strset_free(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_put_copy(struct l2_strset *set, const char *str); | ||||
| size_t l2_strset_get(struct l2_strset *set, const char *str); | size_t l2_strset_get(struct l2_strset *set, const char *str); | ||||
| #include "bytecode.h" | #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); | |||||
| } | } |
| return "comma"; | return "comma"; | ||||
| case L2_TOK_PERIOD: | case L2_TOK_PERIOD: | ||||
| return "period"; | return "period"; | ||||
| case L2_TOK_COLON_EQ: | |||||
| return "period"; | |||||
| case L2_TOK_EOF: | case L2_TOK_EOF: | ||||
| return "end-of-file"; | return "end-of-file"; | ||||
| case L2_TOK_NUMBER: | case L2_TOK_NUMBER: | ||||
| return "number"; | return "number"; | ||||
| case L2_TOK_STRING: | case L2_TOK_STRING: | ||||
| return "string"; | return "string"; | ||||
| case L2_TOK_IDENT: | |||||
| return "ident"; | |||||
| case L2_TOK_ERROR: | case L2_TOK_ERROR: | ||||
| return "error"; | return "error"; | ||||
| } | } | ||||
| l2_bufio_reader_init(&lexer->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) { | static int read_ch(struct l2_lexer *lexer) { | ||||
| int ch = l2_bufio_get(&lexer->reader); | int ch = l2_bufio_get(&lexer->reader); | ||||
| lexer->ch += 1; | lexer->ch += 1; | ||||
| } | } | ||||
| } | } | ||||
| 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) { | static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | ||||
| skip_whitespace(lexer); | skip_whitespace(lexer); | ||||
| tok->kind = L2_TOK_PERIOD; | tok->kind = L2_TOK_PERIOD; | ||||
| break; | 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: | case EOF: | ||||
| tok->kind = L2_TOK_EOF; | tok->kind = L2_TOK_EOF; | ||||
| break; | break; | ||||
| case '"': | case '"': | ||||
| read_string(lexer, tok); | read_string(lexer, tok); | ||||
| break; | break; | ||||
| default: | |||||
| read_ident(lexer, tok); | |||||
| break; | |||||
| } | } | ||||
| } | } | ||||
| #include "gen/gen.h" | #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); | |||||
| } | |||||
| } | } |
| free(set->vals); | 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) { | if (set->len >= set->size / 2) { | ||||
| grow(set); | grow(set); | ||||
| } | } |