summaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
authorJohnny Richard <johnny@johnnyrichard.com>2025-04-11 01:15:01 +0200
committerJohnny Richard <johnny@johnnyrichard.com>2025-04-14 23:11:22 +0200
commite7f69c8fbbbcbddde84933b2becd91e787d1ac63 (patch)
tree16cd17da17133494dd06aab614724e76b059d4ad /src/parser.c
Intial commit
Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c173
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;
+}