diff options
Diffstat (limited to 'src/parser.c')
| -rw-r--r-- | src/parser.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..d978847 --- /dev/null +++ b/src/parser.c @@ -0,0 +1,173 @@ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "array.h" +#include "parser.h" +#include "lexer.h" +#include "string_view.h" + +void +parser_init(parser_t *parser, char *file_name) +{ + assert(parser && file_name); + lexer_init(&parser->lexer, file_name); +} + +void +parser_next_expected_token(parser_t *parser, token_t *token, token_kind_t kind) +{ + lexer_next_token(&parser->lexer, token); + if (token->kind != kind) { + fprintf( + stderr, + "%s:%zu:%zu: parser error: expected token <%s> but got <%s>.\n", + parser->lexer.file_name, + token->loc.lineno + 1, + token->loc.offset - token->loc.lineoffset + 1, + token_to_cstr(kind), + token_to_cstr(token->kind)); + exit(EXIT_FAILURE); + } +} + +inst_t * +parser_parse(parser_t *parser) { + inst_t *insts = array(inst_t); + + token_t token = { 0 }; + int label_count = 0; + + lexer_next_token(&parser->lexer, &token); + while (token.kind != TOKEN_EOF) { + switch (token.kind) { + case TOKEN_KW_PUSH: { + parser_next_expected_token(parser, &token, TOKEN_NUMBER); + + char value[token.value.size + 1]; + value[token.value.size] = '\0'; + memcpy(value, token.value.chars, token.value.size); + + array_append(insts, ((inst_t) { .type = INST_PUSH, .operand = atoi(value) })); + + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_ADD: { + array_append(insts, ((inst_t) { .type = INST_ADD })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_DUP: { + array_append(insts, ((inst_t) { .type = INST_DUP })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_SWAP: { + array_append(insts, ((inst_t) { .type = INST_SWAP })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_SUB: { + array_append(insts, ((inst_t) { .type = INST_SUB })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_MUL: { + array_append(insts, ((inst_t) { .type = INST_MUL })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_STORE: { + array_append(insts, ((inst_t) { .type = INST_STORE })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_LOAD: { + array_append(insts, ((inst_t) { .type = INST_LOAD })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_RET: { + array_append(insts, ((inst_t) { .type = INST_RET })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_IDENT: { + array_append(insts, ((inst_t) { .type = INST_LABEL, .operand = label_count++ })); + parser_next_expected_token(parser, &token, TOKEN_COLON); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_JMP: { + parser_next_expected_token(parser, &token, TOKEN_NUMBER); + + char value[token.value.size + 1]; + value[token.value.size] = '\0'; + memcpy(value, token.value.chars, token.value.size); + + array_append(insts, ((inst_t) { .type = INST_JMP, .operand = atoi(value) })); + + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_JMPZ: { + parser_next_expected_token(parser, &token, TOKEN_NUMBER); + + char value[token.value.size + 1]; + value[token.value.size] = '\0'; + memcpy(value, token.value.chars, token.value.size); + + array_append(insts, ((inst_t) { .type = INST_JMPZ, .operand = atoi(value) })); + + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_CALL: { + parser_next_expected_token(parser, &token, TOKEN_NUMBER); + + char value[token.value.size + 1]; + value[token.value.size] = '\0'; + memcpy(value, token.value.chars, token.value.size); + + array_append(insts, ((inst_t) { .type = INST_CALL, .operand = atoi(value) })); + + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_READI: { + array_append(insts, ((inst_t) { .type = INST_READI })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_READC: { + array_append(insts, ((inst_t) { .type = INST_READC })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_PRINTI: { + array_append(insts, ((inst_t) { .type = INST_PRINTI })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_PRINTC: { + array_append(insts, ((inst_t) { .type = INST_PRINTC })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_KW_END: { + array_append(insts, ((inst_t) { .type = INST_END })); + parser_next_expected_token(parser, &token, TOKEN_EOS); + break; + } + case TOKEN_EOS: { + break; + } + default: break; + } + lexer_next_token(&parser->lexer, &token); + } + + return insts; +} |
