From e49a666eaaa92553248a57875dea8da227c5d8bd Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Sat, 30 May 2020 13:19:55 -0700 Subject: [PATCH] aindump/ainedit: inline strings Remove the --inline-strings option and implement this behavior as the default (removing the old behavior). This is done for string only; messages are still given as integers. This implementation is a bit different than the broken implementation it replaces: instead of trying to completely rebuild the string table from scratch, we simply leave the string table as-is and do a hash-table lookup to get the corresponding index for all string arguments. If the string cannot be found, then it is added at the end of the table. This is NOT implemented for messages because the message table can contain many duplicate strings and the message index actually matters for the purpose of tracking previously read messages. This is a breaking change. --- src/tools/aindump/aindump.c | 8 +-- src/tools/aindump/aindump.h | 3 +- src/tools/aindump/dasm.c | 33 +++------- src/tools/aindump/macros.c | 8 +-- src/tools/ainedit/ainedit.c | 9 +-- src/tools/ainedit/ainedit.h | 2 +- src/tools/ainedit/asm.c | 126 ++++++++++++++---------------------- 7 files changed, 64 insertions(+), 125 deletions(-) diff --git a/src/tools/aindump/aindump.c b/src/tools/aindump/aindump.c index d9ddb7f..66be5c1 100644 --- a/src/tools/aindump/aindump.c +++ b/src/tools/aindump/aindump.c @@ -113,7 +113,6 @@ static void usage(void) puts(" -e, --enums Dump enums section"); puts(" -d, --decrypt Dump decrypted AIN file"); puts(" --map Dump AIN file map"); - puts(" --inline-strings Dump code in inline-strings mode"); puts(" --no-macros Don't use macros in code output"); puts(" --input-encoding Specify the text encoding of the AIN file (default: CP932)"); puts(" --output-encoding Specify the text encoding of the output file (default: UTF-8)"); @@ -473,7 +472,6 @@ enum { LOPT_ENUMS, LOPT_DECRYPT, LOPT_MAP, - LOPT_INLINE_STRINGS, LOPT_NO_MACROS, LOPT_INPUT_ENCODING, LOPT_OUTPUT_ENCODING @@ -488,7 +486,7 @@ int main(int argc, char *argv[]) char *input_encoding = "CP932"; char *output_encoding = "UTF-8"; int err = AIN_SUCCESS; - unsigned int flags = DASM_NO_STRINGS; + unsigned int flags = 0; struct ain *ain; int dump_targets[256]; @@ -516,7 +514,6 @@ int main(int argc, char *argv[]) { "enums", no_argument, 0, LOPT_ENUMS }, { "decrypt", no_argument, 0, LOPT_DECRYPT }, { "map", no_argument, 0, LOPT_MAP }, - { "inline-strings", no_argument, 0, LOPT_INLINE_STRINGS }, { "no-macros", no_argument, 0, LOPT_NO_MACROS }, { "input-encoding", required_argument, 0, LOPT_INPUT_ENCODING }, { "output-encoding", required_argument, 0, LOPT_OUTPUT_ENCODING }, @@ -606,9 +603,6 @@ int main(int argc, char *argv[]) case LOPT_MAP: dump_targets[dump_ptr++] = LOPT_MAP; break; - case LOPT_INLINE_STRINGS: - flags &= ~DASM_NO_STRINGS; - break; case LOPT_NO_MACROS: flags |= DASM_NO_MACROS; break; diff --git a/src/tools/aindump/aindump.h b/src/tools/aindump/aindump.h index 68140a1..aef1372 100644 --- a/src/tools/aindump/aindump.h +++ b/src/tools/aindump/aindump.h @@ -25,8 +25,7 @@ struct ain_function; enum { DASM_RAW = 1, - DASM_NO_STRINGS = 2, - DASM_NO_MACROS = 4, + DASM_NO_MACROS = 2, }; struct code_reader { diff --git a/src/tools/aindump/dasm.c b/src/tools/aindump/dasm.c index 072dd45..eddf421 100644 --- a/src/tools/aindump/dasm.c +++ b/src/tools/aindump/dasm.c @@ -331,30 +331,17 @@ static void print_argument(struct dasm_state *dasm, int32_t arg, enum instructio case T_STRING: if (arg < 0 || arg >= ain->nr_strings) DASM_ERROR(dasm, "Invalid string number: %d", arg); - if (dasm->flags & DASM_NO_STRINGS) { - fprintf(dasm->out, "0x%x ", arg); - *comment = ain->strings[arg]->text; - } else { - dasm_print_string(dasm, ain->strings[arg]->text); - } + dasm_print_string(dasm, ain->strings[arg]->text); break; case T_MSG: if (arg < 0 || arg >= ain->nr_messages) DASM_ERROR(dasm, "Invalid message number: %d", arg); - if (dasm->flags & DASM_NO_STRINGS) { - fprintf(dasm->out, "0x%x ", arg); - *comment = ain->messages[arg]->text; - } else { - dasm_print_string(dasm, ain->messages[arg]->text); - } + fprintf(dasm->out, "0x%x ", arg); + *comment = ain->messages[arg]->text; break; case T_LOCAL: - if (dasm->func < 0) { + if (dasm->func < 0) DASM_ERROR(dasm, "Attempt to access local variable outside of function"); - //WARNING("Attempt to access local variable outside of function"); - //dasm_print_string(dasm, "???"); - break; - } if (arg < 0 || arg >= ain->functions[dasm->func].nr_vars) DASM_ERROR(dasm, "Invalid variable number: %d", arg); dasm_print_local_variable(dasm, &ain->functions[dasm->func], arg); @@ -481,18 +468,16 @@ static void print_instruction(struct dasm_state *dasm) static void print_switch_case(struct dasm_state *dasm, struct ain_switch_case *c) { - fprintf(dasm->out, ".CASE %" SIZE_T_FMT "d:%" SIZE_T_FMT "d ", c->parent - dasm->ain->switches, c - c->parent->cases); + unsigned swi = (unsigned)(c->parent - dasm->ain->switches); + unsigned ci = (unsigned)(c - c->parent->cases); switch (c->parent->case_type) { case AIN_SWITCH_INT: + fprintf(dasm->out, ".CASE %u:%u ", swi, ci); fprintf(dasm->out, "%d", c->value); break; case AIN_SWITCH_STRING: - if (dasm->flags & DASM_NO_STRINGS) { - fprintf(dasm->out, "%d ; ", c->value); - dasm_print_string(dasm, dasm->ain->strings[c->value]->text); - } else { - dasm_print_string(dasm, dasm->ain->strings[c->value]->text); - } + fprintf(dasm->out, ".STRCASE %u:%u ", swi, ci); + dasm_print_string(dasm, dasm->ain->strings[c->value]->text); break; default: WARNING("Unknown switch case type: %d", c->parent->case_type); diff --git a/src/tools/aindump/macros.c b/src/tools/aindump/macros.c index ad14ebd..8083b09 100644 --- a/src/tools/aindump/macros.c +++ b/src/tools/aindump/macros.c @@ -127,14 +127,8 @@ static void F_LOCALASSIGN_emit(struct dasm_state *dasm, int32_t *args) static void STRING_LOCALASSIGN_emit(struct dasm_state *dasm, int32_t *args) { print_local(dasm, args[0]); - fprintf(dasm->out, " 0x%x ; ", args[1]); + fputc(' ', dasm->out); dasm_print_string(dasm, dasm->ain->strings[args[1]]->text); - /* - char *u = sjis2utf(dasm->ain->strings[args[1]]->text, 0); - print_local(dasm, args[0]); - fprintf(dasm->out, " 0x%x ; \"%s\"", args[1], u); - free(u); - */ } static void LOCALCREATE_emit(struct dasm_state *dasm, int32_t *args) diff --git a/src/tools/ainedit/ainedit.c b/src/tools/ainedit/ainedit.c index 6cd7265..dcd31c3 100644 --- a/src/tools/ainedit/ainedit.c +++ b/src/tools/ainedit/ainedit.c @@ -37,7 +37,6 @@ static void usage(void) puts(" --transcode Change the AIN file's text encoding"); puts(" -o, --output Set output file path"); puts(" --raw Read code in raw mode"); - puts(" --inline-strings Read code in inline-strings mode"); puts(" --input-encoding Specify the text encoding of the input file(s) (default: UTF-8)"); puts(" --output-encoding Specify the text encoding of the output file (default: CP932)"); puts(" --ain-encoding Specify the text encoding of the input AIN file"); @@ -54,7 +53,6 @@ enum { LOPT_TRANSCODE, LOPT_OUTPUT, LOPT_RAW, - LOPT_INLINE_STRINGS, LOPT_INPUT_ENCODING, LOPT_OUTPUT_ENCODING, LOPT_AIN_ENCODING, @@ -95,7 +93,7 @@ int main(int argc, char *argv[]) const char *output_encoding = "CP932"; const char *ain_encoding = "CP932"; bool transcode = false; - uint32_t flags = ASM_NO_STRINGS; + uint32_t flags = 0; while (1) { static struct option long_options[] = { { "help", no_argument, 0, LOPT_HELP }, @@ -105,7 +103,6 @@ int main(int argc, char *argv[]) { "transcode", required_argument, 0, LOPT_TRANSCODE }, { "output", required_argument, 0, LOPT_OUTPUT }, { "raw", no_argument, 0, LOPT_RAW }, - { "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 }, @@ -146,10 +143,6 @@ int main(int argc, char *argv[]) case LOPT_RAW: flags |= ASM_RAW; break; - case LOPT_INLINE_STRINGS: - WARNING("Inline strings mode doesn't quite work yet..."); - flags &= ~ASM_NO_STRINGS; - break; case LOPT_INPUT_ENCODING: input_encoding = optarg; break; diff --git a/src/tools/ainedit/ainedit.h b/src/tools/ainedit/ainedit.h index 4bd05dd..902339f 100644 --- a/src/tools/ainedit/ainedit.h +++ b/src/tools/ainedit/ainedit.h @@ -23,12 +23,12 @@ enum { ASM_RAW = 1, - ASM_NO_STRINGS = 2, }; #define PSEUDO_OP_OFFSET 0xF000 enum asm_pseudo_opcode { PO_CASE = PSEUDO_OP_OFFSET, + PO_STRCASE, PO_DEFAULT, PO_SETSTR, PO_SETMSG, diff --git a/src/tools/ainedit/asm.c b/src/tools/ainedit/asm.c index 922f3bc..0429171 100644 --- a/src/tools/ainedit/asm.c +++ b/src/tools/ainedit/asm.c @@ -23,6 +23,7 @@ #include "ainedit.h" #include "system4.h" #include "system4/ain.h" +#include "system4/hashtable.h" #include "system4/instructions.h" #include "system4/string.h" #include "asm_parser.tab.h" @@ -56,6 +57,7 @@ KHASH_MAP_INIT_STR(string_ht, size_t); const struct instruction asm_pseudo_ops[NR_PSEUDO_OPS - PSEUDO_OP_OFFSET] = { PSEUDO_OP(PO_CASE, ".CASE", 2), + PSEUDO_OP(PO_STRCASE, ".STRCASE", 2), PSEUDO_OP(PO_DEFAULT, ".DEFAULT", 1), PSEUDO_OP(PO_SETSTR, ".SETSTR", 2), PSEUDO_OP(PO_SETMSG, ".SETMSG", 2), @@ -108,10 +110,7 @@ struct asm_state { int32_t func; int32_t func_stack[ASM_FUNC_STACK_SIZE]; int32_t lib; - struct string_table strings; - struct string_table messages; - khash_t(string_ht) *strings_index; - khash_t(string_ht) *messages_index; + struct hash_table *str_ht; }; const_pure int32_t asm_instruction_width(int opcode) @@ -121,43 +120,6 @@ const_pure int32_t asm_instruction_width(int opcode) return instruction_width(opcode); } -static int string_table_add(struct string_table *t, const char *s) -{ - if (!t->allocated) { - t->allocated = 4096; - t->strings = xmalloc(t->allocated * sizeof(struct string*)); - } else if (t->allocated <= t->size) { - t->allocated *= 2; - t->strings = xrealloc(t->strings, t->allocated * sizeof(struct string*)); - } - - t->strings[t->size++] = make_string(s, strlen(s)); - return t->size - 1; -} - -static int asm_add_message(struct asm_state *state, const char *s) -{ - char *u = encode_text(s); - int i = string_table_add(&state->messages, u); - free(u); - return i; -} - -static int asm_add_string(struct asm_state *state, const char *s) -{ - int ret; - char *u = encode_text(s); - khiter_t k = kh_put(string_ht, state->strings_index, u, &ret); - if (!ret) { - // nothing - } else if (ret == 1) { - kh_value(state->strings_index, k) = string_table_add(&state->strings, u); - } else { - ERROR("Hash table lookup failed (%d)", ret); - } - return kh_value(state->strings_index, k); -} - static void init_asm_state(struct asm_state *state, struct ain *ain, uint32_t flags) { memset(state, 0, sizeof(*state)); @@ -165,14 +127,22 @@ static void init_asm_state(struct asm_state *state, struct ain *ain, uint32_t fl state->flags = flags; state->func = -1; state->lib = -1; - state->strings_index = kh_init(string_ht); - state->messages_index = kh_init(string_ht); + state->str_ht = ht_create(4096); + + for (intptr_t i = 0; i < ain->nr_strings; i++) { + struct ht_slot *p = ht_put(state->str_ht, ain->strings[i]->text); + if (p->value) { + char *u = encode_text_for_print(ain->strings[i]->text); + WARNING("Duplicate string in ain file: \"%s\"", u); + free(u); + } + p->value = (void*)(i+1); + } } static void fini_asm_state(struct asm_state *state) { - kh_destroy(string_ht, state->strings_index); - kh_destroy(string_ht, state->messages_index); + ht_free(state->str_ht); } static void asm_write_opcode(struct asm_state *state, uint16_t opcode) @@ -281,6 +251,23 @@ static void realloc_message_table(struct ain *ain, int i) ain->nr_messages = i+1; } +static int asm_add_string(struct asm_state *state, const char *str) +{ + char *sjis = encode_text(str); + struct ht_slot *p = ht_put(state->str_ht, sjis); + if (p->value) { + free(sjis); + return (intptr_t)p->value - 1; + } + + int i = state->ain->nr_strings; + realloc_string_table(state->ain, i); + state->ain->strings[i] = make_string(sjis, strlen(sjis)); + p->key = state->ain->strings[i]->text; + free(sjis); + return i; +} + static uint32_t asm_resolve_arg(struct asm_state *state, enum opcode opcode, enum instruction_argtype type, const char *arg) { if (state->flags & ASM_RAW) @@ -326,24 +313,14 @@ static uint32_t asm_resolve_arg(struct asm_state *state, enum opcode opcode, enu return f - ain->functions; } case T_STRING: { - if (state->flags & ASM_NO_STRINGS) { - int32_t i = parse_integer_constant(state, arg); - if (i < 0) - ASM_ERROR(state, "String index out of bounds: '%s'", arg); - realloc_string_table(ain, i); - return i; - } return asm_add_string(state, arg); } case T_MSG: { - if (state->flags & ASM_NO_STRINGS) { - int32_t i = parse_integer_constant(state, arg); - if (i < 0) - ASM_ERROR(state, "Message index out of bounds: '%s'", arg); - realloc_message_table(ain, i); - return i; - } - return asm_add_message(state, arg); + int32_t i = parse_integer_constant(state, arg); + if (i < 0) + ASM_ERROR(state, "Message index out of bounds: '%s'", arg); + realloc_message_table(ain, i); + return i; } case T_LOCAL: { int n, count = 0; @@ -514,11 +491,18 @@ void handle_pseudo_op(struct asm_state *state, struct parse_instruction *instr) decompose_switch_index(state, kv_A(*instr->args, 0)->text, &n_switch, &n_case); struct ain_switch *swi = &state->ain->switches[n_switch]; - if (swi->case_type == AIN_SWITCH_STRING && !(state->flags & ASM_NO_STRINGS)) { - c = asm_add_string(state, kv_A(*instr->args, 1)->text); - } else { - c = parse_integer_constant(state, kv_A(*instr->args, 1)->text); - } + c = parse_integer_constant(state, kv_A(*instr->args, 1)->text); + realloc_switch_cases(swi, n_case); + swi->cases[n_case].address = state->buf_ptr; + swi->cases[n_case].value = c; + break; + } + case PO_STRCASE: { + int n_switch, n_case, c; + decompose_switch_index(state, kv_A(*instr->args, 0)->text, &n_switch, &n_case); + + struct ain_switch *swi = &state->ain->switches[n_switch]; + c = asm_add_string(state, kv_A(*instr->args, 1)->text); realloc_switch_cases(swi, n_case); swi->cases[n_case].address = state->buf_ptr; swi->cases[n_case].value = c; @@ -712,7 +696,7 @@ void handle_pseudo_op(struct asm_state *state, struct parse_instruction *instr) asm_write_argument(state, asm_resolve_arg(state, PUSH, T_LOCAL, kv_A(*instr->args, 0)->text)); asm_write_opcode(state, REF); asm_write_opcode(state, S_PUSH); - asm_write_argument(state, asm_resolve_arg(state, PUSH, T_INT, kv_A(*instr->args, 1)->text)); + asm_write_argument(state, asm_resolve_arg(state, S_PUSH, T_STRING, kv_A(*instr->args, 1)->text)); asm_write_opcode(state, S_ASSIGN); asm_write_opcode(state, DELETE); break; @@ -968,16 +952,6 @@ void asm_assemble_jam(const char *filename, struct ain *ain, uint32_t flags) ain->code = state.buf; ain->code_size = state.buf_ptr; - if (!(state.flags & ASM_NO_STRINGS)) { - ain_free_strings(ain); - ain->strings = state.strings.strings; - ain->nr_strings = state.strings.size; - - ain_free_messages(ain); - ain->messages = state.messages.strings; - ain->nr_messages = state.messages.size; - } - validate_ain(ain); fini_asm_state(&state);