aindump/ainedit: STRUCTREF, etc. macros

Same idea as LOCALREF/GLOBALREF, etc. except for accessing struct
members inside of a member function. This is a bit trickier since it
requires knowing which functions belong to which structs, which isn't
directly encoded in the AIN format.
This commit is contained in:
Nunuhara Cabbage
2020-05-01 16:31:12 -07:00
parent cb085f6c5c
commit 094ce848b9
6 changed files with 216 additions and 7 deletions
+2
View File
@@ -155,6 +155,8 @@ struct ain_function {
int32_t nr_vars;
int32_t is_lambda; // XXX: if this = 1, then function is a lambda; but not all lambdas have this = 1
int32_t crc;
int32_t struct_type;
int32_t enum_type;
struct ain_variable *vars;
};
+64
View File
@@ -81,6 +81,69 @@ static void init_struct_ht(struct ain *ain)
}
}
static bool function_is_member_of(char *func_name, char *struct_name)
{
while (*func_name && *struct_name && *func_name != '@' && *func_name == *struct_name) {
func_name++;
struct_name++;
}
return !*struct_name && *func_name == '@';
}
/*
* Returns true if func_name contains the '@' character.
* We can't use strchr here because '@' is valid as the second byte of a SJIS character.
*/
static bool is_member_function(char *func_name)
{
while (*func_name) {
if (*func_name == '@')
return true;
if (SJIS_2BYTE(*func_name)) {
func_name++;
if (*func_name)
func_name++;
} else {
func_name++;
}
}
return false;
}
/*
* Infer struct member functions from function names.
*/
static void init_member_functions(struct ain *ain)
{
for (int f = 0; f < ain->nr_functions; f++) {
ain->functions[f].struct_type = -1;
ain->functions[f].enum_type = -1;
char *name = ain->functions[f].name;
if (!is_member_function(name))
continue;
for (int s = 0; s < ain->nr_structures; s++) {
if (function_is_member_of(name, ain->structures[s].name)) {
ain->functions[f].struct_type = s;
break;
}
}
if (ain->functions[f].struct_type != -1)
continue;
// check enums
for (int e = 0; e < ain->nr_enums; e++) {
if (function_is_member_of(name, ain->enums[e].name)) {
ain->functions[f].enum_type = e;
break;
}
}
if (ain->functions[f].enum_type == -1) {
char *u = sjis2utf(name, 0);
WARNING("Failed to find struct type for function \"%s\"", u);
free(u);
}
}
}
static struct func_list *get_function(struct ain *ain, const char *name)
{
int ret;
@@ -978,6 +1041,7 @@ struct ain *ain_open(const char *path, int *error)
goto err;
}
distribute_initvals(ain);
init_member_functions(ain);
free(buf);
*error = AIN_SUCCESS;
+54
View File
@@ -254,6 +254,58 @@ static bool globalpage_macro(struct dasm_state *dasm)
return true;
}
static bool structassign_macro(struct dasm_state *dasm, struct ain_struct *s, struct ain_variable *m)
{
int32_t val = dasm_arg(dasm, 0);
if (!check_next_opcode(dasm, ASSIGN))
return false;
fprintf(dasm->out, ".STRUCTASSIGN ");
dasm_print_identifier(dasm, s->name);
fputc(' ', dasm->out);
dasm_print_identifier(dasm, m->name);
fputc(' ', dasm->out);
fprintf(dasm->out, "%d\n", val);
return true;
}
static bool structpage_macro(struct dasm_state *dasm)
{
struct ain_function *f = &dasm->ain->functions[dasm->func];
if (f->struct_type < 0)
return false;
if (!check_next_opcode(dasm, PUSH))
return false;
int32_t no = dasm_arg(dasm, 0);
struct ain_struct *s = &dasm->ain->structures[f->struct_type];
if (no < 0 || no >= s->nr_members)
return false;
struct ain_variable *m = &s->members[no];
dasm_next(dasm);
if (check_opcode(dasm, REF)) {
fprintf(dasm->out, ".STRUCTREF ");
} else if (check_opcode(dasm, REFREF)) {
fprintf(dasm->out, ".STRUCTREFREF ");
} else if (check_opcode(dasm, INC)) {
fprintf(dasm->out, ".STRUCTINC ");
} else if (check_opcode(dasm, DEC)) {
fprintf(dasm->out, ".STRUCTDEC ");
} else if (check_opcode(dasm, PUSH)) {
return structassign_macro(dasm, s, m);
} else {
return false;
}
dasm_print_identifier(dasm, s->name);
fputc(' ', dasm->out);
dasm_print_identifier(dasm, m->name);
fputc('\n', dasm->out);
return true;
}
static bool _dasm_print_macro(struct dasm_state *dasm)
{
switch (dasm->instr->opcode) {
@@ -261,6 +313,8 @@ static bool _dasm_print_macro(struct dasm_state *dasm)
return localpage_macro(dasm);
case PUSHGLOBALPAGE:
return globalpage_macro(dasm);
case PUSHSTRUCTPAGE:
return structpage_macro(dasm);
default:
return false;
}
+22 -1
View File
@@ -40,6 +40,7 @@ static void usage(void)
puts(" --inline-strings Read code in inline-strings mode");
puts(" --input-encoding <enc> Specify the text encoding of the input file(s) (default: UTF-8)");
puts(" --output-encoding <enc> Specify the text encoding of the output file (default: CP932)");
puts(" --ain-encoding <enc> Specify the text encoding of the input AIN file");
//puts(" -p,--project <pje-file> Build AIN from project file");
}
@@ -56,10 +57,12 @@ enum {
LOPT_INLINE_STRINGS,
LOPT_INPUT_ENCODING,
LOPT_OUTPUT_ENCODING,
LOPT_AIN_ENCODING,
};
iconv_t ain_conv;
iconv_t print_conv;
iconv_t ain_input_conv;
char *convert_text(iconv_t cd, const char *str);
@@ -69,6 +72,16 @@ char *encode_text(const char *str)
return convert_text(ain_conv, str);
}
char *encode_text_to_input_format(char *str)
{
return convert_text(ain_input_conv, str);
}
char *encode_text_for_print(char *str)
{
return convert_text(print_conv, str);
}
int main(int argc, char *argv[])
{
initialize_instructions();
@@ -80,6 +93,7 @@ int main(int argc, char *argv[])
const char *output_file = NULL;
const char *input_encoding = "UTF-8";
const char *output_encoding = "CP932";
const char *ain_encoding = "CP932";
bool transcode = false;
uint32_t flags = ASM_NO_STRINGS;
while (1) {
@@ -94,6 +108,7 @@ int main(int argc, char *argv[])
{ "inline-strings", no_argument, 0, LOPT_INLINE_STRINGS },
{ "input-encoding", required_argument, 0, LOPT_INPUT_ENCODING },
{ "output-encoding", required_argument, 0, LOPT_OUTPUT_ENCODING },
{ "ain-encoding", required_argument, 0, LOPT_AIN_ENCODING },
};
int option_index = 0;
int c;
@@ -141,6 +156,9 @@ int main(int argc, char *argv[])
case LOPT_OUTPUT_ENCODING:
output_encoding = optarg;
break;
case LOPT_AIN_ENCODING:
ain_encoding = optarg;
break;
case '?':
ERROR("Unknown command line argument");
}
@@ -161,7 +179,10 @@ int main(int argc, char *argv[])
if ((ain_conv = iconv_open(output_encoding, input_encoding)) == (iconv_t)-1) {
ERROR("iconv_open: %s", strerror(errno));
}
if ((print_conv = iconv_open("UTF-8", output_encoding)) == (iconv_t)-1) {
if ((print_conv = iconv_open("UTF-8", input_encoding)) == (iconv_t)-1) {
ERROR("iconv_open: %s", strerror(errno));
}
if ((ain_input_conv = iconv_open(ain_encoding, input_encoding)) == (iconv_t)-1) {
ERROR("iconv_open: %s", strerror(errno));
}
+7
View File
@@ -44,6 +44,11 @@ enum asm_pseudo_opcode {
PO_GLOBALINC,
PO_GLOBALDEC,
PO_GLOBALASSIGN,
PO_STRUCTREF,
PO_STRUCTREFREF,
PO_STRUCTINC,
PO_STRUCTDEC,
PO_STRUCTASSIGN,
NR_PSEUDO_OPS
};
@@ -67,5 +72,7 @@ void read_text(const char *filename, struct ain *ain);
void ain_transcode(struct ain *ain);
char *encode_text(const char *str);
char *encode_text_to_input_format(char *str);
char *encode_text_for_print(char *str);
#endif /* AINEDIT_AINEDIT_H */
+67 -6
View File
@@ -60,17 +60,22 @@ const struct instruction asm_pseudo_ops[NR_PSEUDO_OPS - PSEUDO_OP_OFFSET] = {
PSEUDO_OP(PO_STR, ".STR", 2),
PSEUDO_OP(PO_MSG, ".MSG", 2),
MACRO(PO_LOCALREF, ".LOCALREF", 1, 10),
MACRO(PO_GLOBALREF, ".GLOBALREF", 1, 10),
MACRO(PO_LOCALREFREF, ".LOCALREFREF", 1, 10),
MACRO(PO_GLOBALREFREF, ".GLOBALREFREF", 1, 10),
MACRO(PO_LOCALINC, ".LOCALINC", 1, 10),
MACRO(PO_LOCALDEC, ".LOCALDEC", 1, 10),
MACRO(PO_LOCALASSIGN, ".LOCALASSIGN", 2, 16),
MACRO(PO_LOCALDELETE, ".LOCALDELETE", 1, 24),
MACRO(PO_LOCALCREATE, ".LOCALCREATE", 2, 34),
MACRO(PO_GLOBALREF, ".GLOBALREF", 1, 10),
MACRO(PO_GLOBALREFREF, ".GLOBALREFREF", 1, 10),
MACRO(PO_GLOBALINC, ".GLOBALINC", 1, 10),
MACRO(PO_GLOBALDEC, ".GLOBALDEC", 1, 10),
MACRO(PO_GLOBALASSIGN, ".GLOBALASSIGN", 2, 16),
MACRO(PO_STRUCTREF, ".STRUCTREF", 2, 10),
MACRO(PO_STRUCTREFREF, ".STRUCTREFREF", 2, 10),
MACRO(PO_STRUCTINC, ".STRUCTINC", 2, 10),
MACRO(PO_STRUCTDEC, ".STRUCTDEC", 2, 10),
MACRO(PO_STRUCTASSIGN, ".STRUCTASSIGN", 3, 16),
};
struct string_table {
@@ -444,6 +449,29 @@ static void decompose_switch_index(struct asm_state *state, char *in, int *switc
*case_out = n_case;
}
static int get_member_no(struct asm_state *state, char *struct_name, char *_member_name)
{
int member_no = -1;
int struct_no = asm_resolve_arg(state, PUSH, T_STRUCT, struct_name);
char *member_name = encode_text_to_input_format(_member_name);
for (int i = 0; i < state->ain->structures[struct_no].nr_members; i++) {
if (!strcmp(member_name, state->ain->structures[struct_no].members[i].name)) {
member_no = i;
break;
}
}
free(member_name);
if (member_no < 0) {
char *sname = encode_text_for_print(struct_name);
char *mname = encode_text_for_print(_member_name);
ASM_ERROR(state, "Unable to resolve struct member: %s.%s", sname, mname);
}
return member_no;
}
void handle_pseudo_op(struct asm_state *state, struct parse_instruction *instr)
{
switch (instr->opcode) {
@@ -597,6 +625,43 @@ void handle_pseudo_op(struct asm_state *state, struct parse_instruction *instr)
asm_write_opcode(state, ASSIGN);
break;
}
case PO_STRUCTREF: {
asm_write_opcode(state, PUSHSTRUCTPAGE);
asm_write_opcode(state, PUSH);
asm_write_argument(state, get_member_no(state, kv_A(*instr->args, 0)->text, kv_A(*instr->args, 1)->text));
asm_write_opcode(state, REF);
break;
}
case PO_STRUCTREFREF: {
asm_write_opcode(state, PUSHSTRUCTPAGE);
asm_write_opcode(state, PUSH);
asm_write_argument(state, get_member_no(state, kv_A(*instr->args, 0)->text, kv_A(*instr->args, 1)->text));
asm_write_opcode(state, REFREF);
break;
}
case PO_STRUCTINC: {
asm_write_opcode(state, PUSHSTRUCTPAGE);
asm_write_opcode(state, PUSH);
asm_write_argument(state, get_member_no(state, kv_A(*instr->args, 0)->text, kv_A(*instr->args, 1)->text));
asm_write_opcode(state, INC);
break;
}
case PO_STRUCTDEC: {
asm_write_opcode(state, PUSHSTRUCTPAGE);
asm_write_opcode(state, PUSH);
asm_write_argument(state, get_member_no(state, kv_A(*instr->args, 0)->text, kv_A(*instr->args, 1)->text));
asm_write_opcode(state, DEC);
break;
}
case PO_STRUCTASSIGN: {
asm_write_opcode(state, PUSHSTRUCTPAGE);
asm_write_opcode(state, PUSH);
asm_write_argument(state, get_member_no(state, kv_A(*instr->args, 0)->text, kv_A(*instr->args, 1)->text));
asm_write_opcode(state, PUSH);
asm_write_argument(state, asm_resolve_arg(state, PUSH, T_INT, kv_A(*instr->args, 2)->text));
asm_write_opcode(state, ASSIGN);
break;
}
}
}
@@ -687,10 +752,6 @@ void asm_assemble_jam(const char *filename, struct ain *ain, uint32_t flags)
// NOTE: special case: we need to record the new function address in the ain structure
if (idef->opcode == FUNC) {
//state.func = asm_resolve_arg(&state, FUNC, T_INT, kv_A(*instr->args, 0)->text);
//state.ain->functions[state.func].address = state.buf_ptr + 6;
//asm_write_opcode(&state, FUNC);
//asm_write_argument(&state, state.func);
asm_enter_function(&state, asm_resolve_arg(&state, FUNC, T_INT, kv_A(*instr->args, 0)->text));
continue;
} else if (idef->opcode == ENDFUNC) {