summaryrefslogtreecommitdiff
path: root/masm/parse.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--masm/parse.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/masm/parse.c b/masm/parse.c
new file mode 100644
index 0000000..9876311
--- /dev/null
+++ b/masm/parse.c
@@ -0,0 +1,198 @@
+#include <mlimits.h>
+#include <merror.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "parse.h"
+#include "lex.h"
+
+int next_token(struct parser *parser, struct token *tok)
+{
+ if (parser->peek.type != TOK_EOF) {
+ if (tok != NULL)
+ *tok = parser->peek;
+ parser->peek.type = TOK_EOF;
+ return M_SUCCESS;
+ }
+ struct token token;
+ if (lexer_next(parser->lexer, &token))
+ return M_ERROR;
+ if (tok != NULL)
+ *tok = token;
+ return M_SUCCESS;
+}
+
+
+int peek_token(struct parser *parser, struct token *tok)
+{
+ if (parser->peek.type == TOK_EOF) {
+ if (next_token(parser, &parser->peek))
+ return M_ERROR;
+ }
+ if (tok != NULL)
+ *tok = parser->peek;
+ return M_SUCCESS;
+}
+
+
+int assert_token(struct parser *parser, enum token_type type,
+ struct token *tok)
+{
+ struct token token;
+ if (next_token(parser, &token))
+ return M_ERROR;
+ if (token.type != type) {
+ ERROR_POS(token, "expected a token of type '%s', got '%s'",
+ token_str(type), token_str(token.type));
+ return M_ERROR;
+ }
+ if (tok != NULL)
+ *tok = token;
+ return M_SUCCESS;
+}
+
+int assert_eol(struct parser *parser)
+{
+ struct token token;
+ if (next_token(parser, &token))
+ return M_ERROR;
+ if (token.type != TOK_NL && token.type != TOK_EOF) {
+ ERROR_POS(token, "expected a new line or end of file");
+ return M_ERROR;
+ }
+ return M_SUCCESS;
+}
+
+static int parse_constant(struct parser *parser, struct const_expr *expr,
+ struct token ident)
+{
+ struct token number;
+
+ if (assert_token(parser, TOK_EQUAL, NULL))
+ return M_ERROR;
+
+ if (assert_token(parser, TOK_NUMBER, &number))
+ return M_ERROR;
+
+ strcpy(expr->name,ident.text);
+ expr->value = number.number;
+
+ return M_SUCCESS;
+}
+
+static int parser_handle_ident(struct parser *parser, struct expr *expr)
+{
+ struct token ident;
+ struct token peek;
+
+ if (assert_token(parser, TOK_IDENT, &ident))
+ return M_ERROR;
+
+ if (peek_token(parser, &peek))
+ return M_ERROR;
+
+ if (peek.type == TOK_EQUAL) {
+ expr->type = EXPR_CONSTANT;
+ return parse_constant(parser, &expr->constant, ident);
+ } else {
+ expr->type = EXPR_INS;
+ return parser->parse_instruction(parser, &expr->ins, ident);
+ }
+}
+
+
+static int parse_label(struct parser *parser,
+ struct expr *expr)
+{
+ struct token token;
+ struct symbol symbol;
+ uint32_t index;
+
+ if (assert_token(parser, TOK_LABEL, &token))
+ return M_ERROR;
+ strcpy(expr->text, token.text);
+
+ if (symtbl_find(&parser->sym_tbl, NULL, token.text) == M_SUCCESS) {
+ ERROR_POS(token, "redefined symbol '%s'", token.text);
+ return M_ERROR;
+ }
+
+ index = parser->sec_tbl.current->start +
+ parser->sec_tbl.current->count;
+ symbol = (struct symbol) {
+ .name = "",
+ .position = index,
+ .flag = SYM_LOCAL,
+ };
+ strcpy(symbol.name, token.text);
+
+ if (symtbl_push(&parser->sym_tbl, symbol))
+ return M_ERROR;
+
+ return M_SUCCESS;
+}
+
+
+int parser_next(struct parser *parser, struct expr *expr)
+{
+ struct token token;
+ int res = M_SUCCESS;
+
+again:
+ if (peek_token(parser, &token))
+ return M_ERROR;
+
+ switch (token.type) {
+ case TOK_NL:
+ next_token(parser, NULL);
+ goto again;
+
+ case TOK_EOF:
+ res = M_EOF;
+ break;
+
+ case TOK_LABEL:
+ expr->type = EXPR_LABEL;
+ res = parse_label(parser, expr);
+ break;
+
+ case TOK_DIRECTIVE:
+ expr->type = EXPR_DIRECTIVE;
+ res = parser->parse_directive(parser,
+ &expr->directive);
+ break;
+
+ case TOK_IDENT:
+ res = parser_handle_ident(parser, expr);
+ break;
+
+ default:
+ ERROR_POS(token, "unexpected token '%s'",
+ token_str(token.type));
+ return M_ERROR;
+
+ }
+
+ return res;
+}
+
+int parser_init(struct lexer *lexer, struct parser *parser)
+{
+ parser->lexer = lexer;
+ parser->peek.type = TOK_EOF;
+ if (symtbl_init(&parser->sym_tbl))
+ return M_ERROR;
+ if (sectbl_init(&parser->sec_tbl))
+ return M_ERROR;
+ if (reftbl_init(&parser->ref_tbl))
+ return M_ERROR;
+ return M_SUCCESS;
+}
+
+
+void parser_free(struct parser *parser)
+{
+ symtbl_free(&parser->sym_tbl);
+ sectbl_free(&parser->sec_tbl);
+ reftbl_free(&parser->ref_tbl);
+}