*/ | */ | ||||
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); | ||||
} | } |