mips/masm/parse.c

203 lines
4 KiB
C
Raw Normal View History

#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;
if (assert_token(parser, TOK_LABEL, &token))
return M_ERROR;
strcpy(expr->text, token.text);
2024-09-10 00:48:08 +00:00
struct symbol *ref;
if (symtbl_find(&parser->sym_tbl, &ref, token.text) == M_SUCCESS) {
if (ref->flag == SYM_GLOBAL && ref->sec == NULL) {
ref->sec = parser->sec_tbl.current;
ref->index = parser->sec_tbl.current->count;
return M_SUCCESS;
}
ERROR_POS(token, "redefined symbol '%s'", token.text);
return M_ERROR;
}
2024-09-10 00:48:08 +00:00
struct symbol symbol;
symbol = (struct symbol) {
.name = "",
2024-09-10 00:48:08 +00:00
.sec = parser->sec_tbl.current,
.index = parser->sec_tbl.current->count,
.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);
}