mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-05 05:17:59 +03:00
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.
This commit is contained in:
@@ -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 <enc> Specify the text encoding of the AIN file (default: CP932)");
|
||||
puts(" --output-encoding <enc> 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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -37,7 +37,6 @@ static void usage(void)
|
||||
puts(" --transcode <enc> Change the AIN file's text encoding");
|
||||
puts(" -o, --output <path> Set output file path");
|
||||
puts(" --raw Read code in raw mode");
|
||||
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");
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
+50
-76
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user