diff options
Diffstat (limited to '')
-rw-r--r-- | masm/parse.c | 198 |
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); +} |