296 lines
7.4 KiB
C
296 lines
7.4 KiB
C
|
#include "mcg.h"
|
||
|
|
||
|
static struct e_instr insn;
|
||
|
|
||
|
static const char* type_to_str(int type)
|
||
|
{
|
||
|
switch (type)
|
||
|
{
|
||
|
case EM_MNEM: return "EM_MNEM";
|
||
|
case EM_PSEU: return "EM_PSEU";
|
||
|
case EM_STARTMES: return "EM_STARTMES";
|
||
|
case EM_MESARG: return "EM_MESARG";
|
||
|
case EM_ENDMES: return "EM_ENDMES";
|
||
|
case EM_DEFILB: return "EM_DEFILB";
|
||
|
case EM_DEFDLB: return "EM_DEFDLB";
|
||
|
case EM_DEFDNAM: return "EM_DEFDNAM";
|
||
|
case EM_ERROR: return "EM_ERROR";
|
||
|
case EM_FATAL: return "EM_FATAL";
|
||
|
case EM_EOF: return "EM_EOF";
|
||
|
}
|
||
|
|
||
|
assert(0 && "invalid EM type");
|
||
|
}
|
||
|
|
||
|
static const char* argtype_to_str(int type)
|
||
|
{
|
||
|
if (type == 0) return "...";
|
||
|
if (type == ilb_ptyp) return "ilb";
|
||
|
if (type == nof_ptyp) return "nof";
|
||
|
if (type == sof_ptyp) return "sof";
|
||
|
if (type == cst_ptyp) return "cst";
|
||
|
if (type == pro_ptyp) return "pro";
|
||
|
if (type == str_ptyp) return "str";
|
||
|
if (type == ico_ptyp) return "ico";
|
||
|
if (type == uco_ptyp) return "uco";
|
||
|
if (type == fco_ptyp) return "fco";
|
||
|
return "???";
|
||
|
}
|
||
|
|
||
|
static void unknown_type(const char* s)
|
||
|
{
|
||
|
fatal("%s with unknown type '%s'",
|
||
|
s,
|
||
|
argtype_to_str(insn.em_arg.ema_argtype));
|
||
|
}
|
||
|
|
||
|
static const uint8_t* arith_to_bytes(arith a, size_t sz)
|
||
|
{
|
||
|
uint8_t* p = malloc(8);
|
||
|
|
||
|
switch (sz)
|
||
|
{
|
||
|
case 1: *(uint8_t*)p = a; break;
|
||
|
case 2: *(uint16_t*)p = a; break;
|
||
|
case 4: *(uint32_t*)p = a; break;
|
||
|
case 8: *(uint64_t*)p = a; break;
|
||
|
default:
|
||
|
fatal("bad constant size '%d'", sz);
|
||
|
}
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
static const char* ilabel_to_str(label l)
|
||
|
{
|
||
|
char s[16];
|
||
|
sprintf(s, "__I%d", l);
|
||
|
return strdup(s);
|
||
|
}
|
||
|
|
||
|
static const char* dlabel_to_str(label l)
|
||
|
{
|
||
|
char s[16];
|
||
|
sprintf(s, ".%d", l);
|
||
|
return strdup(s);
|
||
|
}
|
||
|
|
||
|
static void parse_pseu(void)
|
||
|
{
|
||
|
switch (insn.em_opcode)
|
||
|
{
|
||
|
case ps_exp: /* external proc */
|
||
|
case ps_exa: /* external array */
|
||
|
case ps_inp: /* internal proc */
|
||
|
case ps_ina: /* internal array */
|
||
|
{
|
||
|
bool export = (insn.em_opcode == ps_exp) || (insn.em_opcode == ps_exa);
|
||
|
bool proc = (insn.em_opcode == ps_exp) || (insn.em_opcode == ps_inp);
|
||
|
|
||
|
switch (insn.em_arg.ema_argtype)
|
||
|
{
|
||
|
case pro_ptyp:
|
||
|
tb_symbol(strdup(insn.em_pnam), export, proc);
|
||
|
break;
|
||
|
|
||
|
case sof_ptyp:
|
||
|
assert(insn.em_off == 0);
|
||
|
tb_symbol(strdup(insn.em_dnam), export, proc);
|
||
|
break;
|
||
|
|
||
|
case nof_ptyp:
|
||
|
assert(insn.em_off == 0);
|
||
|
tb_symbol(dlabel_to_str(insn.em_dlb), export, proc);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
unknown_type("exp, exa, inp, ina");
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ps_con: /* .data */
|
||
|
case ps_rom: /* .rom */
|
||
|
{
|
||
|
bool ro = (insn.em_opcode == ps_rom);
|
||
|
|
||
|
switch (insn.em_arg.ema_argtype)
|
||
|
{
|
||
|
case ico_ptyp:
|
||
|
case uco_ptyp:
|
||
|
{
|
||
|
arith val = atol(insn.em_string);
|
||
|
tb_data(arith_to_bytes(val, insn.em_size), insn.em_size, ro);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case str_ptyp:
|
||
|
tb_data(strdup(insn.em_string), insn.em_size, ro);
|
||
|
break;
|
||
|
|
||
|
case cst_ptyp:
|
||
|
tb_data(arith_to_bytes(insn.em_cst, EM_wordsize), EM_wordsize, ro);
|
||
|
break;
|
||
|
|
||
|
case nof_ptyp:
|
||
|
tb_data_offset(dlabel_to_str(insn.em_dlb), insn.em_off, ro);
|
||
|
break;
|
||
|
|
||
|
case ilb_ptyp:
|
||
|
tb_data_offset(ilabel_to_str(insn.em_ilb), 0, ro);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
unknown_type("con, rom");
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ps_bss:
|
||
|
{
|
||
|
switch (insn.em_arg.ema_argtype)
|
||
|
{
|
||
|
case cst_ptyp:
|
||
|
tb_bss(EM_bsssize, EM_bssinit);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
unknown_type("bss");
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ps_pro: /* procedure start */
|
||
|
if (insn.em_nlocals == -1)
|
||
|
fatal("procedures with unspecified number of locals are not supported yet");
|
||
|
|
||
|
tb_procstart(strdup(insn.em_pnam), insn.em_nlocals);
|
||
|
break;
|
||
|
|
||
|
case ps_end: /* procedure end */
|
||
|
tb_procend();
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
fatal("unknown pseudo with opcode %d\n", insn.em_opcode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static arith mes_get_cst(void)
|
||
|
{
|
||
|
EM_getinstr(&insn);
|
||
|
if (insn.em_type != EM_MESARG)
|
||
|
fatal("malformed MES");
|
||
|
return insn.em_cst;
|
||
|
}
|
||
|
|
||
|
static void parse_mes(void)
|
||
|
{
|
||
|
assert(insn.em_arg.ema_argtype == cst_ptyp);
|
||
|
switch (insn.em_cst)
|
||
|
{
|
||
|
case 0: /* error */
|
||
|
fatal("MES 0 received (explicit halt)");
|
||
|
|
||
|
case 3: /* register variable */
|
||
|
{
|
||
|
arith offset = mes_get_cst();
|
||
|
int size = mes_get_cst();
|
||
|
int type = mes_get_cst();
|
||
|
int priority = mes_get_cst();
|
||
|
tb_regvar(offset, size, type, priority);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while ((insn.em_type == EM_STARTMES) || (insn.em_type == EM_MESARG))
|
||
|
EM_getinstr(&insn);
|
||
|
|
||
|
if (insn.em_type != EM_ENDMES)
|
||
|
fatal("malformed MES");
|
||
|
}
|
||
|
|
||
|
void parse_em(void)
|
||
|
{
|
||
|
EM_getinstr(&insn);
|
||
|
tb_filestart();
|
||
|
|
||
|
while (insn.em_type != EM_EOF)
|
||
|
{
|
||
|
switch (insn.em_type)
|
||
|
{
|
||
|
case EM_PSEU:
|
||
|
parse_pseu();
|
||
|
break;
|
||
|
|
||
|
case EM_DEFILB:
|
||
|
tb_ilabel(ilabel_to_str(insn.em_ilb));
|
||
|
break;
|
||
|
|
||
|
case EM_DEFDLB:
|
||
|
tb_dlabel(dlabel_to_str(insn.em_dlb));
|
||
|
break;
|
||
|
|
||
|
case EM_DEFDNAM:
|
||
|
tb_dlabel(strdup(insn.em_dnam));
|
||
|
break;
|
||
|
|
||
|
case EM_STARTMES:
|
||
|
parse_mes();
|
||
|
break;
|
||
|
|
||
|
case EM_MNEM:
|
||
|
{
|
||
|
int flags = em_flag[insn.em_opcode - sp_fmnem];
|
||
|
|
||
|
if (flags & EM_PAR)
|
||
|
{
|
||
|
switch (insn.em_argtype)
|
||
|
{
|
||
|
case ilb_ptyp:
|
||
|
tb_insn_label(insn.em_opcode, flags,
|
||
|
ilabel_to_str(insn.em_ilb), 0);
|
||
|
break;
|
||
|
|
||
|
case nof_ptyp:
|
||
|
tb_insn_label(insn.em_opcode, flags,
|
||
|
dlabel_to_str(insn.em_dlb), insn.em_off);
|
||
|
break;
|
||
|
|
||
|
case sof_ptyp:
|
||
|
tb_insn_label(insn.em_opcode, flags,
|
||
|
strdup(insn.em_dnam), insn.em_off);
|
||
|
break;
|
||
|
|
||
|
case pro_ptyp:
|
||
|
tb_insn_label(insn.em_opcode, flags,
|
||
|
strdup(insn.em_pnam), 0);
|
||
|
break;
|
||
|
|
||
|
case cst_ptyp:
|
||
|
tb_insn_value(insn.em_opcode, flags,
|
||
|
insn.em_cst);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
unknown_type("instruction");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
tb_insn_simple(insn.em_opcode, flags);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
fatal("unrecognised instruction type '%d'", insn.em_type);
|
||
|
}
|
||
|
|
||
|
EM_getinstr(&insn);
|
||
|
}
|
||
|
|
||
|
tb_fileend();
|
||
|
}
|
||
|
|
||
|
/* vim: set sw=4 ts=4 expandtab : */
|