mips/masm/parse.c

1313 lines
26 KiB
C
Raw Normal View History

#include <mlimits.h>
#include <merror.h>
2024-09-13 15:11:18 +00:00
#include <netinet/in.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
2024-09-13 15:11:18 +00:00
#include <elf.h>
#include "parse.h"
#include "lex.h"
2024-09-13 15:11:18 +00:00
#include "mips.h"
2024-09-11 16:06:09 +00:00
static 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;
}
2024-09-11 16:06:09 +00:00
static 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;
}
2024-09-11 16:06:09 +00:00
static 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;
}
2024-09-11 16:06:09 +00:00
static 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;
}
2024-09-11 16:06:09 +00:00
/* each instruction has a given parse format
* internal to the parser */
enum mips_parse_format {
// register type: rs, rt, td
MIPS_PARSE_R,
// register type: rs, rt
MIPS_PARSE_R2,
// register type: rd
MIPS_PARSE_RD,
// register type: rs
MIPS_PARSE_RS,
// imeediate type: rs, rt, immd
MIPS_PARSE_I,
// jump type: offset
MIPS_PARSE_J,
// offset 16b type: offset
MIPS_PARSE_O16,
// offset 26b type: offset
MIPS_PARSE_O26,
// breanch equal type: rs, rt, offset
MIPS_PARSE_BE,
// branch zero type: rs, offset
MIPS_PARSE_BZ,
// store and load: rt, offset(base)
MIPS_PARSE_SL,
// store and load immediate: rt, immediate
MIPS_PARSE_SLI,
// shift: rd, rt, sa
MIPS_PARSE_S,
// shift variable: rd, rt, rs
MIPS_PARSE_SV,
// none:
MIPS_PARSE_NONE,
};
#define FORMAT(ins, format) \
[MIPS_INS_##ins] = MIPS_PARSE_##format, \
const enum mips_parse_format mips_parse_formats[] = {
FORMAT(ADD, R)
FORMAT(ADDI, I)
FORMAT(ADDIU, I)
FORMAT(ADDU, R)
FORMAT(AND, R)
FORMAT(ANDI, I)
FORMAT(BAL, O16)
FORMAT(BALC, O26)
FORMAT(BC, O26)
FORMAT(BEQ, BE)
FORMAT(BEQL, BE)
FORMAT(BGEZ, BZ)
FORMAT(BGEZAL, BZ)
FORMAT(BGEZALL, BZ)
FORMAT(BGEZL, BZ)
FORMAT(BGTZ, BZ)
FORMAT(BGTZL, BZ)
FORMAT(BLEZ, BZ)
FORMAT(BLEZL, BZ)
FORMAT(BLTZ, BZ)
FORMAT(BLTZAL, BZ)
FORMAT(BLTZALL, BZ)
FORMAT(BLTZL, BZ)
FORMAT(BNE, BE)
FORMAT(BNEL, BE)
2024-09-13 15:11:18 +00:00
FORMAT(DIV, R)
FORMAT(MOD, R)
FORMAT(DIVU, R)
FORMAT(MODU, R)
2024-09-11 16:06:09 +00:00
FORMAT(J, J)
FORMAT(JAL, J)
2024-09-13 15:11:18 +00:00
FORMAT(JALR, RS) // TODO: handle rd
2024-09-11 16:06:09 +00:00
FORMAT(JALX, J)
2024-09-13 15:11:18 +00:00
FORMAT(JR, RS)
2024-09-11 16:06:09 +00:00
FORMAT(LB, SL)
FORMAT(LBU, SL)
FORMAT(LH, SL)
FORMAT(LHU, SL)
FORMAT(LUI, SLI)
FORMAT(LW, SL)
FORMAT(LWL, SL)
FORMAT(LWR, SL)
FORMAT(MFHI, RD)
FORMAT(MFLO, RD)
FORMAT(MTHI, RS)
FORMAT(MTLO, RS)
2024-09-13 15:11:18 +00:00
FORMAT(MUL, R)
FORMAT(MUH, R)
FORMAT(MULU, R)
FORMAT(MUHU, R)
2024-09-11 16:06:09 +00:00
FORMAT(MULT, R2)
FORMAT(SB, SL)
FORMAT(SH, SL)
FORMAT(SW, SL)
FORMAT(SWL, SL)
FORMAT(SLL, S)
FORMAT(SLLV, SV)
FORMAT(SLT, R)
FORMAT(SLTI, I)
FORMAT(SLTIU, I)
FORMAT(SLTU, R)
FORMAT(SRA, S)
FORMAT(SRAV, SV)
FORMAT(SRL, S)
FORMAT(SRLV, SV)
FORMAT(SYSCALL, NONE)
FORMAT(OR, R)
FORMAT(ORI, I)
FORMAT(NOR, R)
FORMAT(SUB, R)
FORMAT(SUBU, R)
FORMAT(XOR, R)
FORMAT(XORI, I)
};
#undef FORMAT
2024-09-13 15:11:18 +00:00
#define MAX5 (1 << 5)
#define MAX16 (1 << 16)
#define MAX26 (1 << 25)
#define MAX32 (1 << 31)
2024-09-11 16:06:09 +00:00
2024-09-13 15:11:18 +00:00
static int get_reference(struct parser *parser, uint64_t *offset,
struct reference *ref, unsigned char type)
2024-09-11 16:06:09 +00:00
{
struct token token;
if (next_token(parser, &token))
return M_ERROR;
if (token.type == TOK_NUMBER) {
2024-09-13 15:11:18 +00:00
2024-09-11 16:06:09 +00:00
*offset = token.number;
return M_SUCCESS;
}
if (token.type != TOK_IDENT) {
ERROR_POS(token, "unexpected token of type '%s'",
token_str(token.type));
return M_ERROR;
}
strcpy(ref->name, token.text);
ref->type = type;
ref->addend = 0;
// return zero for now
*offset = 0;
return M_SUCCESS;
}
2024-09-13 15:11:18 +00:00
static int get_offset(struct parser *parser, int32_t *offset,
2024-09-11 16:06:09 +00:00
struct reference *ref)
{
2024-09-13 15:11:18 +00:00
uint64_t off;
if (get_reference(parser, &off, ref, R_MIPS_PC16))
return M_ERROR;
if (off % 4) {
ERROR_POS((*parser->lexer), "cannot use offset of '%ld', must "
"be divisble by four", off);
return M_ERROR;
}
if (off > MAX16) {
ERROR("offset '%d' cannot be larger than 16 bits", off);
return M_ERROR;
}
*offset = off;
return M_SUCCESS;
}
static int get_offset_26(struct parser *parser, int32_t *offset,
struct reference *ref)
{
uint64_t off;
if (get_reference(parser, &off, ref, R_MIPS_PC26_S2))
return M_ERROR;
if (off % 4) {
ERROR_POS((*parser->lexer), "cannot use offset of '%ld', must "
"be divisble by four", off);
return M_ERROR;
}
if (off > MAX26) {
ERROR("offset '%d' cannot be larger than 26 bits", off);
return M_ERROR;
}
*offset = off;
return M_SUCCESS;
2024-09-11 16:06:09 +00:00
}
static int get_target(struct parser *parser, uint32_t *offset,
struct reference *ref)
{
2024-09-13 15:11:18 +00:00
uint64_t off;
if (get_reference(parser, &off, ref, R_MIPS_26))
return M_ERROR;
if (off > MAX26) {
ERROR("target '%d' cannot be larger than 26 bits", off);
return M_ERROR;
}
*offset = off;
return M_SUCCESS;
2024-09-11 16:06:09 +00:00
}
static int get_instruction(const char *ident, struct mips_instruction *res)
{
for (int i = 0; i < __MIPS_INS_LEN; i++) {
struct mips_instruction ins =
mips_instructions[i];
if (strcasecmp(ident, ins.name) == 0) {
if (res != NULL)
*res = ins;
return M_SUCCESS;
}
}
return M_ERROR;
}
static int parse_register(struct parser *parser, enum mips_register *reg)
{
struct token token;
if (assert_token(parser, TOK_REG, &token))
return M_ERROR;
int len = strlen(token.text);
int c0 = len > 0 ? token.text[0] : '\0',
c1 = len > 1 ? token.text[1] : '\0',
c2 = len > 2 ? token.text[2] : '\0',
c3 = len > 3 ? token.text[3] : '\0';
// $zero
if (c0 == 'z') {
if (c1 == 'e' && c2 == 'r' && c3 == 'o') {
*reg = MIPS_REG_ZERO;
return M_SUCCESS;
}
}
// $a0-a3 $at
else if (c0 == 'a') {
if (c1 == 't') {
*reg = MIPS_REG_AT;
return M_SUCCESS;
}
if (c1 >= '0' && c1 <= '3') {
*reg = MIPS_REG_A0;
*reg += c1 - '0';
return M_SUCCESS;
}
}
// $v0-v1
else if (c0 == 'v') {
if (c1 >= '0' && c1 <= '1') {
*reg = MIPS_REG_V0;
*reg += c1 - '0';
return M_SUCCESS;
}
}
// $t0-t9
else if (c0 == 't') {
if (c1 >= '0' && c1 <= '7') {
*reg = MIPS_REG_T0;
*reg += c1 - '0';
return M_SUCCESS;
}
// reg T8-T9 are not in order with T0-T7
if (c1 >= '8' && c1 <= '9') {
*reg = MIPS_REG_T8;
*reg += c1 - '8';
return M_SUCCESS;
}
}
// $s0-s7 $sp
else if (c0 == 's') {
if (c1 >= '0' && c1 <= '7') {
*reg = MIPS_REG_S0;
*reg += c1 - '0';
return M_SUCCESS;
}
if (c1 == 'p') {
*reg = MIPS_REG_SP;
return M_SUCCESS;
}
}
// $k0-k1
else if (c0 == 'k') {
if (c1 >= '0' && c1 <= '1') {
*reg = MIPS_REG_K0;
*reg += c1 - '0';
return M_SUCCESS;
}
}
// $gp
else if (c0 == 'g') {
if (c1 == 'p') {
*reg = MIPS_REG_GP;
return M_SUCCESS;
}
}
// $fp
else if (c0 == 'f') {
if (c1 == 'p') {
*reg = MIPS_REG_FP;
return M_SUCCESS;
}
}
// $rp
else if (c0 == 'r') {
2024-09-13 15:11:18 +00:00
if (c1 == 'a') {
2024-09-11 16:06:09 +00:00
*reg = MIPS_REG_RA;
return M_SUCCESS;
}
}
// $0-31 (non aliased register names)
else if (c0 >= '0' && c0 <= '9') {
int i = c0 - '0';
if (c1 >= '0' && c1 <= '9') {
i *= 10;
i += c1 - '0';
}
if (i <= 31) {
*reg = i;
return M_SUCCESS;
}
}
ERROR_POS(token, "unknown register $%s", token.text);
return M_ERROR;
}
2024-09-14 00:15:56 +00:00
static int get_reg_offset(struct parser *parser,
struct ins_expr *expr)
2024-09-13 15:11:18 +00:00
{
struct token token;
enum mips_register reg;
2024-09-14 00:15:56 +00:00
struct mips_instruction *fi = &expr->ins[0];
struct mips_instruction *si = &expr->ins[1]; // possibly pseudo
struct reference *fr = &expr->ref[0];
struct reference *sr = &expr->ref[1];
expr->ins_len = 1;
fr->type = R_MIPS_NONE;
2024-09-13 15:11:18 +00:00
// =============================================
// defaults
2024-09-14 00:15:56 +00:00
fi->data.rs = MIPS_REG_ZERO;
fi->data.immd = 0;
2024-09-13 15:11:18 +00:00
if (peek_token(parser, &token))
return M_ERROR;
2024-09-14 00:15:56 +00:00
if (token.type == TOK_IDENT)
goto label;
else if (token.type == TOK_LPAREN)
2024-09-13 15:11:18 +00:00
goto reg;
else
goto off;
// =============================================
2024-09-14 00:15:56 +00:00
label:
next_token(parser, &token);
expr->ins_len = 2;
// move over first instruction to add in a LUI
*si = *fi;
si->data.rs = MIPS_REG_AT;
si->data.offset = 0;
// update LUI
*fi = mips_instructions[MIPS_INS_LUI];
fi->data.rt = MIPS_REG_AT;
fi->data.immd = 0;
// update references
strcpy(fr->name, token.text);
fr->type = R_MIPS_HI16;
fr->addend = 0;
strcpy(sr->name, token.text);
sr->type = R_MIPS_LO16;
sr->addend = 0;
goto end;
// =============================================
2024-09-13 15:11:18 +00:00
off:
2024-09-14 00:15:56 +00:00
if (assert_token(parser, TOK_NUMBER, &token))
2024-09-13 15:11:18 +00:00
return M_ERROR;
2024-09-14 00:15:56 +00:00
fi->data.offset = htons(token.number);
2024-09-13 15:11:18 +00:00
if (peek_token(parser, &token))
return M_ERROR;
if (token.type == TOK_LPAREN)
goto reg;
else
goto end;
// =============================================
reg:
if (assert_token(parser, TOK_LPAREN, NULL))
return M_ERROR;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-14 00:15:56 +00:00
fi->data.rs = reg;
2024-09-13 15:11:18 +00:00
if (assert_token(parser, TOK_RPAREN, NULL))
return M_ERROR;
// =============================================
end:
if (peek_token(parser, &token))
return M_ERROR;
return M_SUCCESS;
}
static int parse_number(struct parser *parser, uint32_t *n, uint32_t max)
{
struct token token;
if (assert_token(parser, TOK_NUMBER, &token))
return M_ERROR;
if (max && token.number > max) {
ERROR_POS(token, "number cannot be larger than '%d'", max);
return M_ERROR;
}
*n = token.number;
return M_SUCCESS;
}
2024-09-11 16:06:09 +00:00
static int parse_instruction_r(struct parser *parser,
struct mips_instruction *ins)
{
// format: rs, rt, rd
enum mips_register reg;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rd = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rs = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rt = reg;
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_r2(struct parser *parser,
struct mips_instruction *ins)
{
// format: rs, rt
enum mips_register reg;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rs = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rt = reg;
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_rs(struct parser *parser,
struct mips_instruction *ins)
{
// format: rs
enum mips_register reg;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rs = reg;
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_rd(struct parser *parser,
struct mips_instruction *ins)
{
// format: rd
enum mips_register reg;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rd = reg;
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_i(struct parser *parser,
struct mips_instruction *ins)
{
// format: rs, rt, immd
enum mips_register reg;
struct token token;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rt = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rs = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (assert_token(parser, TOK_NUMBER, &token))
return M_ERROR;
if (token.number >= MAX16)
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.immd = htons(token.number);
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_offset(struct parser *parser,
uint32_t max,
struct mips_instruction *ins,
struct reference *ref)
{
2024-09-13 15:11:18 +00:00
int32_t n;
2024-09-11 16:06:09 +00:00
switch (max) {
case MAX26:
2024-09-13 15:11:18 +00:00
if (get_offset_26(parser, &n, ref))
return M_ERROR;
ins->data.offs26 = htonl(n);
2024-09-11 16:06:09 +00:00
break;
case MAX16:
2024-09-13 15:11:18 +00:00
if (get_offset(parser, &n, ref))
return M_ERROR;
ins->data.offset = htons(n);
2024-09-11 16:06:09 +00:00
break;
2024-09-13 15:11:18 +00:00
default:
return M_ERROR;
2024-09-11 16:06:09 +00:00
}
return M_SUCCESS;
}
static int parse_instruction_j(struct parser *parser,
struct mips_instruction *ins,
struct reference *ref)
{
uint32_t n;
if (get_target(parser, &n, ref) || n > MAX26)
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.target = n;
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
2024-09-13 15:11:18 +00:00
static int parse_instruction_branch_equal(struct parser *parser,
struct mips_instruction *ins,
struct reference *ref)
2024-09-11 16:06:09 +00:00
{
2024-09-13 15:11:18 +00:00
enum mips_register reg;
if (parse_register(parser, &reg))
2024-09-11 16:06:09 +00:00
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rs = reg;
2024-09-11 16:06:09 +00:00
2024-09-13 15:11:18 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
2024-09-11 16:06:09 +00:00
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rt = reg;
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
int32_t off;
if (get_offset(parser, &off, ref))
return M_ERROR;
ins->data.offset = htons(off);
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_branch(struct parser *parser,
struct mips_instruction *ins,
struct reference *ref)
{
enum mips_register reg;
2024-09-13 15:11:18 +00:00
int32_t n;
2024-09-11 16:06:09 +00:00
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rs = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
2024-09-13 15:11:18 +00:00
if (get_offset(parser, &n, ref))
2024-09-11 16:06:09 +00:00
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.offset = htons(n);
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_sl(struct parser *parser,
2024-09-14 00:15:56 +00:00
struct ins_expr *expr)
2024-09-11 16:06:09 +00:00
{
enum mips_register reg;
2024-09-14 00:15:56 +00:00
struct mips_instruction *ins = &expr->ins[0];
2024-09-11 16:06:09 +00:00
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rt = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
2024-09-14 00:15:56 +00:00
if (get_reg_offset(parser, expr))
2024-09-11 16:06:09 +00:00
return M_ERROR;
return M_SUCCESS;
}
static int parse_instruction_sli(struct parser *parser,
struct mips_instruction *ins)
{
enum mips_register reg;
struct token token;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rt = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX16)
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.immd = htons(token.number);
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_s(struct parser *parser,
struct mips_instruction *ins)
{
enum mips_register reg;
struct token token;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rd = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rt = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX5)
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.shamt = token.number;
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
static int parse_instruction_sv(struct parser *parser,
struct mips_instruction *ins)
{
enum mips_register reg;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rd = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rt = reg;
2024-09-11 16:06:09 +00:00
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_register(parser, &reg))
return M_ERROR;
2024-09-13 15:11:18 +00:00
ins->data.rs = reg;
2024-09-11 16:06:09 +00:00
return M_SUCCESS;
}
2024-09-13 15:11:18 +00:00
static int parse_pseudo_li(struct parser *parser, struct ins_expr *expr)
{
enum mips_register reg;
uint32_t immd;
if (parse_register(parser, &reg))
return M_ERROR;
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_number(parser, &immd, MAX16))
return M_ERROR;
expr->ins_len = 1;
expr->ins[0] = mips_instructions[MIPS_INS_ORI];
expr->ins[0].data.rt = reg;
expr->ins[0].data.rs = MIPS_REG_ZERO;
expr->ins[0].data.immd = htons(immd);
expr->ref[0].type = R_MIPS_NONE;
return M_SUCCESS;
}
static int parse_pseudo_la(struct parser *parser, struct ins_expr *expr)
{
enum mips_register reg;
struct token token;
uint16_t hi = 0, lo = 0;
if (parse_register(parser, &reg))
return M_ERROR;
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (next_token(parser, &token))
return M_ERROR;
if (token.type == TOK_IDENT) {
expr->ref[0].type = R_MIPS_HI16;
expr->ref[0].addend = 0;
strcpy(expr->ref[0].name, token.text);
expr->ref[1].type = R_MIPS_LO16;
expr->ref[1].addend = 0;
strcpy(expr->ref[1].name, token.text);
} else if (token.type == TOK_NUMBER && token.number > MAX32) {
hi = token.number >> 16;
lo = token.number & 0x0000ffff;
expr->ref[0].type = R_MIPS_NONE;
expr->ref[1].type = R_MIPS_NONE;
} else {
return M_ERROR;
}
expr->ins_len = 2;
expr->ins[0] = mips_instructions[MIPS_INS_LUI];
expr->ins[0].data.rt = reg;
expr->ins[0].data.immd = htons(hi);
expr->ins[1] = mips_instructions[MIPS_INS_ORI];
expr->ins[1].data.rt = reg;
expr->ins[1].data.rs = MIPS_REG_ZERO;
expr->ins[1].data.immd = htons(lo);
return M_SUCCESS;
}
static int parse_pseudo_move(struct parser *parser, struct ins_expr *expr)
{
enum mips_register rd, rs;
if (parse_register(parser, &rd))
return M_ERROR;
if (assert_token(parser, TOK_COMMA, NULL))
return M_ERROR;
if (parse_register(parser, &rs))
return M_ERROR;
expr->ins_len = 1;
expr->ins[0] = mips_instructions[MIPS_INS_OR];
expr->ins[0].data.rs = rs;
expr->ins[0].data.rt = MIPS_REG_ZERO;
expr->ins[0].data.rd = rd;
expr->ref[0].type = R_MIPS_NONE;
return M_SUCCESS;
}
static int parse_pseudo_instruction(struct parser *parser,
struct ins_expr *expr,
struct token ident)
{
// disablle logging in the logging
// module
extern int log_disabled;
log_disabled = 1;
int res = M_ERROR;
struct lexer_state state;
lexer_save(parser->lexer, &state);
#define CHK(name) if (strcmp(ident.text, #name) == 0)
CHK(li)
res = parse_pseudo_li(parser, expr);
else CHK(la)
res = parse_pseudo_la(parser, expr);
else CHK(move)
res = parse_pseudo_move(parser, expr);
if (res)
lexer_load(parser->lexer, &state);
expr->ins[0].data.raw = 0;
expr->ins[1].data.raw = 0;
expr->ref[0] = (struct reference) {0};
expr->ref[1] = (struct reference) {0};
log_disabled = 0;
return res;
}
2024-09-11 16:06:09 +00:00
static int parse_instruction(struct parser *parser,
struct ins_expr *expr,
struct token ident)
{
struct mips_instruction instruction;
enum mips_parse_format format;
int res = M_SUCCESS;
2024-09-13 15:11:18 +00:00
if (parse_pseudo_instruction(parser, expr, ident) == M_SUCCESS)
return M_SUCCESS;
2024-09-11 16:06:09 +00:00
if (get_instruction(ident.text, &instruction)) {
ERROR_POS(ident, "unknown instruction '%s'", ident.text);
return M_ERROR;
}
struct mips_instruction *ins = &expr->ins[0];
struct reference *ref = &expr->ref[0];
// this will only ever generate one instruction
expr->ins_len = 1;
*ins = instruction;
2024-09-13 15:11:18 +00:00
ref->type = R_MIPS_NONE;
2024-09-11 16:06:09 +00:00
format = mips_parse_formats[instruction.type];
switch (format) {
case MIPS_PARSE_R:
res = parse_instruction_r(parser, ins);
break;
case MIPS_PARSE_R2:
res = parse_instruction_r2(parser, ins);
break;
case MIPS_PARSE_RS:
res = parse_instruction_rs(parser, ins);
break;
case MIPS_PARSE_RD:
res = parse_instruction_rd(parser, ins);
break;
case MIPS_PARSE_I:
res = parse_instruction_i(parser, ins);
break;
case MIPS_PARSE_J:
res = parse_instruction_j(parser, ins, ref);
break;
case MIPS_PARSE_O16:
res = parse_instruction_offset(parser, MAX16, ins, ref);
break;
case MIPS_PARSE_O26:
res = parse_instruction_offset(parser, MAX26, ins, ref);
break;
case MIPS_PARSE_BE:
2024-09-13 15:11:18 +00:00
res = parse_instruction_branch_equal(parser, ins, ref);
2024-09-11 16:06:09 +00:00
break;
case MIPS_PARSE_BZ:
res = parse_instruction_branch(parser, ins, ref);
break;
case MIPS_PARSE_SL:
2024-09-14 00:15:56 +00:00
res = parse_instruction_sl(parser, expr);
2024-09-11 16:06:09 +00:00
break;
case MIPS_PARSE_SLI:
res = parse_instruction_sli(parser, ins);
break;
case MIPS_PARSE_S:
res = parse_instruction_s(parser, ins);
break;
case MIPS_PARSE_SV:
res = parse_instruction_sv(parser, ins);
break;
case MIPS_PARSE_NONE:
res = M_SUCCESS;
break;
}
if (res == M_SUCCESS && assert_eol(parser))
return M_ERROR;
return res;
}
static int parse_directive_align(struct parser *parser,
struct mips_directive *directive)
{
struct token token;
if (assert_token(parser, TOK_NUMBER, &token))
return M_ERROR;
if (token.number < 0) {
ERROR_POS(token, "cannot align negative");
return M_ERROR;
}
if (token.number > MAX16) {
ERROR_POS(token, "cannot align more than 65kb");
return M_ERROR;
}
directive->type = MIPS_DIRECTIVE_ALIGN;
directive->align = token.number;
return M_SUCCESS;
}
static int parse_directive_space(struct parser *parser,
struct mips_directive *directive)
{
struct token token;
if (assert_token(parser, TOK_NUMBER, &token))
return M_ERROR;
if (token.number < 0) {
ERROR_POS(token, "cannot reserve negative");
return M_ERROR;
}
if (token.number > MAX16) {
ERROR_POS(token, "cannot reserve more than 65kb");
return M_ERROR;
}
directive->type = MIPS_DIRECTIVE_SPACE;
directive->space = token.number;
return M_SUCCESS;
}
static int parse_directive_whb(struct parser *parser,
struct mips_directive *directive,
enum mips_directive_type type)
{
struct token token;
uint32_t size = 0;
uint32_t len = 0;
switch (type) {
case MIPS_DIRECTIVE_WORD:
size = UINT32_MAX;
break;
case MIPS_DIRECTIVE_HALF:
size = UINT16_MAX;
break;
case MIPS_DIRECTIVE_BYTE:
size = UINT8_MAX;
break;
default:
}
directive->type = type;
while (1) {
if (assert_token(parser, TOK_NUMBER, &token))
return M_ERROR;
if (len >= MAX_ARG_LENGTH) {
ERROR_POS(token, "directives cannot be longer than "
"%d arguments", MAX_ARG_LENGTH);
return M_ERROR;
}
if (token.number > size) {
ERROR_POS(token, "number cannot execede max size of: "
"%d", size);
return M_ERROR;
}
switch (type) {
case MIPS_DIRECTIVE_WORD:
directive->words[len++] = token.number;
break;
case MIPS_DIRECTIVE_HALF:
directive->halfs[len++] = token.number;
break;
case MIPS_DIRECTIVE_BYTE:
directive->bytes[len++] = token.number;
break;
default:
}
if (peek_token(parser, &token))
return M_ERROR;
if (token.type == TOK_COMMA) {
next_token(parser, NULL);
continue;
}
break;
}
directive->len = len;
return M_SUCCESS;
}
static int parse_directive_extern(struct parser *parser,
struct mips_directive *directive)
{
struct token token;
if (assert_token(parser, TOK_IDENT, &token))
return M_ERROR;
directive->type = MIPS_DIRECTIVE_EXTERN;
strcpy(directive->name, token.text);
return M_SUCCESS;
}
static int parse_directive_globl(struct parser *parser,
struct mips_directive *directive)
{
struct token token;
if (assert_token(parser, TOK_IDENT, &token))
return M_ERROR;
directive->type = MIPS_DIRECTIVE_GLOBL;
strcpy(directive->name, token.text);
return M_SUCCESS;
}
static int parse_directive_ascii(struct parser *parser,
struct mips_directive *directive,
enum mips_directive_type type)
{
struct token token;
if (assert_token(parser, TOK_STRING, &token))
return M_ERROR;
directive->type = type;
strcpy(directive->name, token.text);
return M_SUCCESS;
}
2024-09-11 16:06:09 +00:00
static int parse_section(struct mips_directive *directive,
char name[MAX_LEX_LENGTH])
{
directive->type = MIPS_DIRECTIVE_SECTION;
strcpy(directive->name, name);
return M_SUCCESS;
}
static int parse_directive(struct parser *parser,
struct mips_directive *directive)
{
struct token token;
if (assert_token(parser, TOK_DIRECTIVE, &token))
return M_ERROR;
// .align n
if (strcmp(token.text, "align") == 0)
return parse_directive_align(parser, directive);
else if (strcmp(token.text, "space") == 0)
return parse_directive_space(parser, directive);
else if (strcmp(token.text, "word") == 0)
return parse_directive_whb(parser, directive,
MIPS_DIRECTIVE_WORD);
else if (strcmp(token.text, "half") == 0)
return parse_directive_whb(parser, directive,
MIPS_DIRECTIVE_HALF);
else if (strcmp(token.text, "byte") == 0)
return parse_directive_whb(parser, directive,
MIPS_DIRECTIVE_BYTE);
else if (strcmp(token.text, "extern") == 0)
return parse_directive_extern(parser, directive);
else if (strcmp(token.text, "globl") == 0)
return parse_directive_globl(parser, directive);
else if (strcmp(token.text, "ascii") == 0)
return parse_directive_ascii(parser, directive,
MIPS_DIRECTIVE_ASCII);
else if (strcmp(token.text, "asciiz") == 0)
return parse_directive_ascii(parser, directive,
MIPS_DIRECTIVE_ASCIIZ);
2024-09-11 16:06:09 +00:00
else
return parse_section(directive, token.text);
}
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;
2024-09-11 16:06:09 +00:00
return 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;
2024-09-11 16:06:09 +00:00
strcpy(expr->label, token.text);
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;
2024-09-11 16:06:09 +00:00
res = 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;
return M_SUCCESS;
}
void parser_free(struct parser *parser)
{
2024-09-11 16:06:09 +00:00
(void) parser;
}