2024-09-09 16:41:49 +00:00
|
|
|
#include <mlimits.h>
|
|
|
|
#include <merror.h>
|
2024-09-13 15:11:18 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <stdint.h>
|
2024-09-09 16:41:49 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2024-09-13 15:11:18 +00:00
|
|
|
#include <elf.h>
|
2024-09-09 16:41:49 +00:00
|
|
|
|
|
|
|
#include "parse.h"
|
|
|
|
#include "lex.h"
|
2024-09-13 15:11:18 +00:00
|
|
|
#include "mips.h"
|
2024-09-09 16:41:49 +00:00
|
|
|
|
2024-09-11 16:06:09 +00:00
|
|
|
static int next_token(struct parser *parser, struct token *tok)
|
2024-09-09 16:41:49 +00:00
|
|
|
{
|
|
|
|
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)
|
2024-09-09 16:41:49 +00:00
|
|
|
{
|
|
|
|
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,
|
2024-09-09 16:41:49 +00:00
|
|
|
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)
|
2024-09-09 16:41:49 +00:00
|
|
|
{
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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, ®))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-09-11 16:47:27 +00:00
|
|
|
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);
|
2024-09-11 16:47:27 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-09-09 16:41:49 +00:00
|
|
|
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);
|
2024-09-09 16:41:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2024-09-09 16:41:49 +00:00
|
|
|
|
|
|
|
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);
|
2024-09-09 16:41:49 +00:00
|
|
|
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;
|
2024-09-09 16:41:49 +00:00
|
|
|
}
|