mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-12 17:28:14 +03:00
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:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user