198 lines
3.8 KiB
C
198 lines
3.8 KiB
C
#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);
|
|
}
|