mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-30 10:58:15 +03:00
aindump/ainedit: initial ain v14 support
Support for Evenicle 2 and Haha Ranman. There are a few changes in v14: * a number of new instructions (semantics yet unknown) * HLL function arguments and return values can now be complex types (e.g. arrays, enums) * support for nested arrays (this isn't necessarily new, but it doesn't occur in Rance X at all)
This commit is contained in:
+20
-7
@@ -74,11 +74,13 @@ enum ain_data_type {
|
||||
AIN_REF_ARRAY = 80,
|
||||
AIN_ITERATOR = 82, // array iterator
|
||||
AIN_ENUM1 = 86, // return value of EnumType::Parse; has type 91 in array type
|
||||
AIN_UNKNOWN_TYPE_87 = 87,
|
||||
AIN_IFACE = 89, // 2 values: [0] = struct page, [1] = vtable offset to inteface methods
|
||||
AIN_ENUM2 = 91, // used as array type of type 86; has enum type in struct type
|
||||
AIN_ENUM3 = 92, // used as argument type, and array type in EnumType::GetList; has enum type in struct type
|
||||
AIN_REF_ENUM = 93,
|
||||
AIN_UNKNOWN_TYPE_95 = 95, // function?
|
||||
AIN_UNKNOWN_TYPE_100 = 100,
|
||||
};
|
||||
|
||||
#define AIN_ARRAY_TYPE \
|
||||
@@ -186,12 +188,12 @@ struct ain_struct {
|
||||
|
||||
struct ain_hll_argument {
|
||||
char *name;
|
||||
int32_t data_type;
|
||||
struct ain_type type;
|
||||
};
|
||||
|
||||
struct ain_hll_function {
|
||||
char *name;
|
||||
int32_t data_type;
|
||||
struct ain_type return_type;
|
||||
int32_t nr_arguments;
|
||||
struct ain_hll_argument *arguments;
|
||||
};
|
||||
@@ -234,9 +236,6 @@ struct ain_enum {
|
||||
char **symbols;
|
||||
};
|
||||
|
||||
struct kh_func_ht_s;
|
||||
struct kh_struct_ht_s;
|
||||
|
||||
struct ain_section {
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
@@ -307,8 +306,8 @@ struct ain {
|
||||
struct ain_section OBJG;
|
||||
struct ain_section ENUM;
|
||||
|
||||
struct kh_func_ht_s *_func_ht;
|
||||
struct kh_struct_ht_s *_struct_ht;
|
||||
struct hash_table *_func_ht;
|
||||
struct hash_table *_struct_ht;
|
||||
};
|
||||
|
||||
const char *ain_strerror(int error);
|
||||
@@ -338,4 +337,18 @@ void ain_free_delegates(struct ain *ain);
|
||||
void ain_free_global_groups(struct ain *ain);
|
||||
void ain_free_enums(struct ain *ain);
|
||||
|
||||
static inline bool ain_array_data_type(int32_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case AIN_ARRAY:
|
||||
case AIN_REF_ARRAY:
|
||||
case AIN_ITERATOR:
|
||||
case AIN_ENUM1:
|
||||
case AIN_UNKNOWN_TYPE_87:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SYSTEM4_AIN_H */
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM4_HASHTABLE_H
|
||||
#define SYSTEM4_HASHTABLE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct ht_slot {
|
||||
const char *key;
|
||||
void *value;
|
||||
};
|
||||
|
||||
struct hash_table;
|
||||
|
||||
struct hash_table *ht_create(size_t nr_buckets);
|
||||
void ht_free(struct hash_table *ht);
|
||||
|
||||
void *ht_get(struct hash_table *ht, const char *key);
|
||||
struct ht_slot *ht_put(struct hash_table *ht, const char *key);
|
||||
void ht_foreach_value(struct hash_table *ht, void(*fun)(void*));
|
||||
|
||||
#endif /* SYSTEM4_HASHTABLE_H */
|
||||
@@ -332,6 +332,17 @@ enum opcode
|
||||
OP_0X103 = 0x103,
|
||||
OP_0X104 = 0x104,
|
||||
OP_0X105 = 0x105,
|
||||
OP_0X106 = 0x106,
|
||||
OP_0X107 = 0x107, // unused
|
||||
OP_0X108 = 0x108, // unused
|
||||
OP_0X109 = 0x109, // unused
|
||||
OP_0X10A = 0x10A,
|
||||
OP_0X10B = 0x10B,
|
||||
OP_0X10C = 0x10C,
|
||||
OP_0X10D = 0x10D,
|
||||
OP_0X10E = 0x10E,
|
||||
OP_0X10F = 0x10F,
|
||||
OP_0X110 = 0x110,
|
||||
|
||||
NR_OPCODES
|
||||
};
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "khash.h"
|
||||
#include "little_endian.h"
|
||||
#include "system4.h"
|
||||
#include "system4/ain.h"
|
||||
#include "system4/hashtable.h"
|
||||
#include "system4/instructions.h"
|
||||
#include "system4/string.h"
|
||||
#include "system4/utfsjis.h"
|
||||
@@ -39,45 +39,37 @@ struct func_list {
|
||||
};
|
||||
#define func_list_size(nr_slots) (sizeof(struct func_list) + sizeof(struct ain_function*)*(nr_slots))
|
||||
|
||||
KHASH_MAP_INIT_STR(func_ht, struct func_list*);
|
||||
KHASH_MAP_INIT_STR(struct_ht, struct ain_struct*);
|
||||
|
||||
static void init_func_ht(struct ain *ain)
|
||||
{
|
||||
ain->_func_ht = ht_create(1024);
|
||||
for (int i = 0; i < ain->nr_functions; i++) {
|
||||
int ret;
|
||||
khiter_t k = kh_put(func_ht, ain->_func_ht, ain->functions[i].name, &ret);
|
||||
if (!ret) {
|
||||
// entry with this name already exists: add to list
|
||||
struct func_list *list = kh_value(ain->_func_ht, k);
|
||||
struct ht_slot *kv = ht_put(ain->_func_ht, ain->functions[i].name);
|
||||
if (kv->value) {
|
||||
// entry with this name already exists; add to list
|
||||
struct func_list *list = kv->value;
|
||||
list = xrealloc(list, func_list_size(list->nr_slots+1));
|
||||
list->slots[list->nr_slots] = &ain->functions[i];
|
||||
list->nr_slots++;
|
||||
kh_value(ain->_func_ht, k) = list;
|
||||
} else if (ret == 1) {
|
||||
kv->value = list;
|
||||
} else {
|
||||
// empty bucket: create list
|
||||
struct func_list *list = xmalloc(func_list_size(1));
|
||||
list->nr_slots = 1;
|
||||
list->slots[0] = &ain->functions[i];
|
||||
kh_value(ain->_func_ht, k) = list;
|
||||
} else {
|
||||
ERROR("Failed to insert function into hash table (%d)", ret);
|
||||
kv->value = list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void init_struct_ht(struct ain *ain)
|
||||
{
|
||||
ain->_struct_ht = ht_create(1024);
|
||||
for (int i = 0; i < ain->nr_structures; i++) {
|
||||
int ret;
|
||||
khiter_t k = kh_put(struct_ht, ain->_struct_ht, ain->structures[i].name, &ret);
|
||||
if (!ret) {
|
||||
struct ht_slot *kv = ht_put(ain->_struct_ht, ain->structures[i].name);
|
||||
if (kv->value) {
|
||||
ERROR("Duplicate structure names: '%s'", ain->structures[i].name);
|
||||
} else if (ret == 1) {
|
||||
kh_value(ain->_struct_ht, k) = &ain->structures[i];
|
||||
} else {
|
||||
ERROR("Failed to insert struct into hash table (%d)", ret);
|
||||
}
|
||||
kv->value = &ain->structures[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,11 +138,7 @@ static void init_member_functions(struct ain *ain)
|
||||
|
||||
static struct func_list *get_function(struct ain *ain, const char *name)
|
||||
{
|
||||
int ret;
|
||||
khiter_t k = kh_put(func_ht, ain->_func_ht, name, &ret);
|
||||
if (ret)
|
||||
return NULL;
|
||||
return kh_value(ain->_func_ht, k);
|
||||
return ht_get(ain->_func_ht, name);
|
||||
}
|
||||
|
||||
struct ain_function *ain_get_function(struct ain *ain, char *name)
|
||||
@@ -192,10 +180,7 @@ err:
|
||||
|
||||
struct ain_struct *ain_get_struct(struct ain *ain, char *name)
|
||||
{
|
||||
khiter_t k = kh_get(struct_ht, ain->_struct_ht, name);
|
||||
if (k == kh_end(ain->_struct_ht))
|
||||
return NULL;
|
||||
return kh_value(ain->_struct_ht, k);
|
||||
return ht_get(ain->_struct_ht, name);
|
||||
}
|
||||
|
||||
static const char *errtab[AIN_MAX_ERROR] = {
|
||||
@@ -321,25 +306,25 @@ char *ain_strtype_d(struct ain *ain, struct ain_type *v)
|
||||
case AIN_ITERATOR:
|
||||
return container_type_string(ain, v);
|
||||
case AIN_ENUM1:
|
||||
if (!v->array_type || v->array_type->struc == -1 || !ain)
|
||||
if (!v->array_type || v->array_type->struc == -1 || !ain || v->array_type->struc >= ain->nr_enums)
|
||||
return strdup("enum");
|
||||
//return strdup(ain->enums[v->array_type->struc]);
|
||||
return type_sprintf("%s#86", ain->enums[v->array_type->struc].name);
|
||||
case AIN_UNKNOWN_TYPE_87: return strdup("type_87");
|
||||
case AIN_IFACE:
|
||||
if (v->struc == -1 || !ain)
|
||||
return strdup("interface");
|
||||
return strdup(ain->structures[v->struc].name);
|
||||
case AIN_ENUM2:
|
||||
case AIN_ENUM3:
|
||||
if (v->struc == -1 || !ain)
|
||||
if (v->struc == -1 || !ain || v->struc >= ain->nr_enums)
|
||||
return strdup("enum");
|
||||
//return strdup(ain->enums[v->struc]);
|
||||
return type_sprintf("%s#%d", ain->enums[v->struc].name, v->data);
|
||||
case AIN_REF_ENUM:
|
||||
if (v->struc == -1 || !ain)
|
||||
if (v->struc == -1 || !ain || v->struc >= ain->nr_enums)
|
||||
return strdup("enum");
|
||||
return type_sprintf("ref %s", ain->enums[v->struc].name);
|
||||
case AIN_UNKNOWN_TYPE_95: return strdup("type_95");
|
||||
case AIN_UNKNOWN_TYPE_100: return strdup("type_100");
|
||||
default:
|
||||
WARNING("Unknown type: %d", v->data);
|
||||
return type_sprintf("unknown_type_%d", v->data);
|
||||
@@ -379,6 +364,7 @@ struct ain_reader {
|
||||
size_t size;
|
||||
size_t index;
|
||||
struct ain_section *section;
|
||||
struct ain *ain;
|
||||
};
|
||||
|
||||
static int32_t read_int32(struct ain_reader *r)
|
||||
@@ -458,25 +444,16 @@ static struct string **read_msg1_strings(struct ain_reader *r, int count)
|
||||
return strings;
|
||||
}
|
||||
|
||||
static struct ain_type *read_array_type(struct ain_reader *r)
|
||||
static void read_variable_type(struct ain_reader *r, struct ain_type *t);
|
||||
|
||||
static struct ain_type *read_array_type(struct ain_reader *r, int rank)
|
||||
{
|
||||
int32_t data_type = read_int32(r);
|
||||
int32_t struct_type = read_int32(r);
|
||||
int32_t array_rank = read_int32(r);
|
||||
if (rank < 0)
|
||||
ERROR("Invalid array rank: %d", rank);
|
||||
|
||||
if (array_rank < 0)
|
||||
ERROR("Invalid array rank: %d", array_rank);
|
||||
|
||||
struct ain_type *type = xcalloc(array_rank+1, sizeof(struct ain_type));
|
||||
type[0].data = data_type;
|
||||
type[0].struc = struct_type;
|
||||
type[0].rank = array_rank;
|
||||
|
||||
for (int i = 0; i < array_rank; i++) {
|
||||
type[i+1].data = read_int32(r);
|
||||
type[i+1].struc = read_int32(r);
|
||||
type[i+1].rank = read_int32(r);
|
||||
type[i].array_type = type + i + 1;
|
||||
struct ain_type *type = xcalloc(rank, sizeof(struct ain_type));
|
||||
for (int i = 0; i < rank; i++) {
|
||||
read_variable_type(r, type+i);
|
||||
}
|
||||
|
||||
return type;
|
||||
@@ -506,8 +483,8 @@ static void read_variable_type(struct ain_reader *r, struct ain_type *t)
|
||||
t->struc = read_int32(r);
|
||||
t->rank = read_int32(r);
|
||||
|
||||
if (t->data == AIN_ARRAY || t->data == AIN_REF_ARRAY || t->data == AIN_ITERATOR || t->data == AIN_ENUM1)
|
||||
t->array_type = read_array_type(r);
|
||||
if (ain_array_data_type(t->data))
|
||||
t->array_type = read_array_type(r, t->rank);
|
||||
}
|
||||
|
||||
static struct ain_variable *read_variables(struct ain_reader *r, int count, struct ain *ain, enum ain_variable_type var_type)
|
||||
@@ -626,7 +603,13 @@ static struct ain_hll_argument *read_hll_arguments(struct ain_reader *r, int cou
|
||||
struct ain_hll_argument *arguments = calloc(count, sizeof(struct ain_hll_argument));
|
||||
for (int i = 0; i < count; i++) {
|
||||
arguments[i].name = read_string(r);
|
||||
arguments[i].data_type = read_int32(r);
|
||||
if (r->ain->version >= 14) {
|
||||
read_variable_type(r, &arguments[i].type);
|
||||
} else {
|
||||
arguments[i].type.data = read_int32(r);
|
||||
arguments[i].type.struc = -1;
|
||||
arguments[i].type.rank = 0;
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
@@ -636,8 +619,16 @@ static struct ain_hll_function *read_hll_functions(struct ain_reader *r, int cou
|
||||
struct ain_hll_function *functions = calloc(count, sizeof(struct ain_hll_function));
|
||||
for (int i = 0; i < count; i++) {
|
||||
functions[i].name = read_string(r);
|
||||
functions[i].data_type = read_int32(r);
|
||||
if (r->ain->version >= 14) {
|
||||
read_variable_type(r, &functions[i].return_type);
|
||||
} else {
|
||||
functions[i].return_type.data = read_int32(r);
|
||||
functions[i].return_type.struc = -1;
|
||||
functions[i].return_type.rank = 0;
|
||||
}
|
||||
functions[i].nr_arguments = read_int32(r);
|
||||
if (functions[i].nr_arguments > 100 || functions[i].nr_arguments < 0)
|
||||
ERROR("TOO MANY ARGUMENTS (AT 0x%x)", r->index);
|
||||
functions[i].arguments = read_hll_arguments(r, functions[i].nr_arguments);
|
||||
}
|
||||
return functions;
|
||||
@@ -710,8 +701,10 @@ struct ain_enum *read_enums(struct ain_reader *r, int count, struct ain *ain)
|
||||
struct ain_enum *enums = xcalloc(count, sizeof(struct ain_enum));
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
enums[i].name = names[i];
|
||||
|
||||
char buf[1024] = { [1023] = '\0' };
|
||||
snprintf(buf, 1023, "%s@String", names[i]);
|
||||
snprintf(buf, 1023, ain->version < 14 ? "%s@String" : "%s::ToString", names[i]);
|
||||
|
||||
struct func_list *funs = get_function(ain, buf);
|
||||
if (!funs || funs->nr_slots != 1) {
|
||||
@@ -739,7 +732,6 @@ struct ain_enum *read_enums(struct ain_reader *r, int count, struct ain *ain)
|
||||
enums[i].nr_symbols = j + 1;
|
||||
j++;
|
||||
});
|
||||
enums[i].name = names[i];
|
||||
}
|
||||
|
||||
free(names);
|
||||
@@ -1027,14 +1019,13 @@ struct ain *ain_open(const char *path, int *error)
|
||||
goto err;
|
||||
|
||||
// read data into ain struct
|
||||
ain = calloc(1, sizeof(struct ain));
|
||||
struct ain_reader r = {
|
||||
.buf = buf,
|
||||
.index = 0,
|
||||
.size = len
|
||||
.size = len,
|
||||
.ain = ain
|
||||
};
|
||||
ain = calloc(1, sizeof(struct ain));
|
||||
ain->_func_ht = kh_init(func_ht);
|
||||
ain->_struct_ht = kh_init(struct_ht);
|
||||
while (read_tag(&r, ain));
|
||||
if (!ain->version) {
|
||||
*error = AIN_INVALID;
|
||||
@@ -1052,12 +1043,23 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ain_free_type(struct ain_type *type)
|
||||
{
|
||||
if (!type->array_type)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < type->rank; i++) {
|
||||
ain_free_type(&type->array_type[i]);
|
||||
}
|
||||
free(type->array_type);
|
||||
}
|
||||
|
||||
static void ain_free_variables(struct ain_variable *vars, int nr_vars)
|
||||
{
|
||||
for (int i = 0; i < nr_vars; i++) {
|
||||
free(vars[i].name);
|
||||
free(vars[i].name2);
|
||||
free(vars[i].type.array_type);
|
||||
ain_free_type(&vars[i].type);
|
||||
if (vars[i].has_initval && vars[i].type.data == AIN_STRING)
|
||||
free(vars[i].initval.s);
|
||||
}
|
||||
@@ -1068,7 +1070,7 @@ static void _ain_free_function_types(struct ain_function_type *funs, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
free(funs[i].name);
|
||||
free(funs[i].return_type.array_type);
|
||||
ain_free_type(&funs[i].return_type);
|
||||
ain_free_variables(funs[i].variables, funs[i].nr_variables);
|
||||
}
|
||||
free(funs);
|
||||
@@ -1094,7 +1096,7 @@ void ain_free_functions(struct ain *ain)
|
||||
{
|
||||
for (int f = 0; f < ain->nr_functions; f++) {
|
||||
free(ain->functions[f].name);
|
||||
free(ain->functions[f].return_type.array_type);
|
||||
ain_free_type(&ain->functions[f].return_type);
|
||||
ain_free_variables(ain->functions[f].vars, ain->functions[f].nr_vars);
|
||||
}
|
||||
free(ain->functions);
|
||||
@@ -1141,8 +1143,10 @@ void ain_free_libraries(struct ain *ain)
|
||||
free(ain->libraries[lib].name);
|
||||
for (int f = 0; f < ain->libraries[lib].nr_functions; f++) {
|
||||
free(ain->libraries[lib].functions[f].name);
|
||||
ain_free_type(&ain->libraries[lib].functions[f].return_type);
|
||||
for (int a = 0; a < ain->libraries[lib].functions[f].nr_arguments; a++) {
|
||||
free(ain->libraries[lib].functions[f].arguments[a].name);
|
||||
ain_free_type(&ain->libraries[lib].functions[f].arguments[a].type);
|
||||
}
|
||||
free(ain->libraries[lib].functions[f].arguments);
|
||||
}
|
||||
@@ -1213,6 +1217,10 @@ void ain_free(struct ain *ain)
|
||||
{
|
||||
free(ain->code);
|
||||
|
||||
ht_foreach_value(ain->_func_ht, free);
|
||||
ht_free(ain->_func_ht);
|
||||
ht_free(ain->_struct_ht);
|
||||
|
||||
ain_free_functions(ain);
|
||||
ain_free_globals(ain);
|
||||
ain_free_initvals(ain);
|
||||
@@ -1227,10 +1235,5 @@ void ain_free(struct ain *ain)
|
||||
ain_free_global_groups(ain);
|
||||
ain_free_enums(ain);
|
||||
|
||||
struct func_list *list;
|
||||
kh_foreach_value(ain->_func_ht, list, free(list));
|
||||
kh_destroy(func_ht, ain->_func_ht);
|
||||
kh_destroy(struct_ht, ain->_struct_ht);
|
||||
|
||||
free(ain);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ void hll_call(int libno, int fno)
|
||||
void *args[HLL_MAX_ARGS];
|
||||
void *ptrs[HLL_MAX_ARGS];
|
||||
for (int i = f->nr_arguments - 1; i >= 0; i--) {
|
||||
switch (f->arguments[i].data_type) {
|
||||
switch (f->arguments[i].type.data) {
|
||||
case AIN_REF_INT:
|
||||
case AIN_REF_LONG_INT:
|
||||
case AIN_REF_BOOL:
|
||||
@@ -103,7 +103,7 @@ void hll_call(int libno, int fno)
|
||||
for (int i = 0, j = 0; i < f->nr_arguments; i++, j++) {
|
||||
// XXX: We don't increase the ref count when passing ref arguments to HLL
|
||||
// functions, so we need to avoid decreasing it via variable_fini
|
||||
switch (f->arguments[i].data_type) {
|
||||
switch (f->arguments[i].type.data) {
|
||||
case AIN_REF_INT:
|
||||
case AIN_REF_LONG_INT:
|
||||
case AIN_REF_BOOL:
|
||||
@@ -116,13 +116,13 @@ void hll_call(int libno, int fno)
|
||||
case AIN_REF_ARRAY_TYPE:
|
||||
break;
|
||||
default:
|
||||
variable_fini(stack[stack_ptr+j], f->arguments[i].data_type);
|
||||
variable_fini(stack[stack_ptr+j], f->arguments[i].type.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (f->data_type != AIN_VOID) {
|
||||
if (f->data_type == AIN_STRING) {
|
||||
if (f->return_type.data != AIN_VOID) {
|
||||
if (f->return_type.data == AIN_STRING) {
|
||||
int slot = heap_alloc_slot(VM_STRING);
|
||||
heap[slot].s = r.ref;
|
||||
} else {
|
||||
@@ -202,9 +202,9 @@ static void link_static_library_function(struct hll_function *dst, struct ain_hl
|
||||
dst->args = xcalloc(dst->nr_args, sizeof(ffi_type*));
|
||||
|
||||
for (unsigned int i = 0; i < dst->nr_args; i++) {
|
||||
dst->args[i] = ain_to_ffi_type(src->arguments[i].data_type);
|
||||
dst->args[i] = ain_to_ffi_type(src->arguments[i].type.data);
|
||||
}
|
||||
dst->return_type = ain_to_ffi_type(src->data_type);
|
||||
dst->return_type = ain_to_ffi_type(src->return_type.data);
|
||||
|
||||
if (ffi_prep_cif(&dst->cif, FFI_DEFAULT_ABI, dst->nr_args, dst->return_type, dst->args) != FFI_OK)
|
||||
ERROR("Failed to link HLL function");
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "system4.h"
|
||||
#include "system4/hashtable.h"
|
||||
|
||||
struct ht_bucket {
|
||||
size_t nr_slots;
|
||||
struct ht_slot slots[];
|
||||
};
|
||||
|
||||
struct hash_table {
|
||||
size_t nr_buckets;
|
||||
struct ht_bucket *buckets[];
|
||||
};
|
||||
|
||||
static unsigned long string_hash(const char *_str)
|
||||
{
|
||||
const unsigned char *str = (const unsigned char*)_str;
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++))
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
struct hash_table *ht_create(size_t nr_buckets)
|
||||
{
|
||||
struct hash_table *ht = xmalloc(sizeof(struct hash_table) + sizeof(struct ht_bucket*)*nr_buckets);
|
||||
ht->nr_buckets = nr_buckets;
|
||||
for (size_t i = 0; i < nr_buckets; i++) {
|
||||
ht->buckets[i] = NULL;
|
||||
}
|
||||
return ht;
|
||||
}
|
||||
|
||||
void *ht_get(struct hash_table *ht, const char *key)
|
||||
{
|
||||
unsigned long k = string_hash(key) & (ht->nr_buckets - 1);
|
||||
if (!ht->buckets[k])
|
||||
return NULL;
|
||||
for (size_t i = 0; i < ht->buckets[k]->nr_slots; i++) {
|
||||
if (!strcmp(ht->buckets[k]->slots[i].key, key))
|
||||
return ht->buckets[k]->slots[i].value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ht_slot *ht_put(struct hash_table *ht, const char *key)
|
||||
{
|
||||
unsigned long k = string_hash(key) & (ht->nr_buckets - 1);
|
||||
|
||||
// init new bucket
|
||||
if (!ht->buckets[k]) {
|
||||
ht->buckets[k] = xmalloc(sizeof(struct ht_bucket) + sizeof(struct ht_slot));
|
||||
ht->buckets[k]->nr_slots = 1;
|
||||
ht->buckets[k]->slots[0].key = key;
|
||||
ht->buckets[k]->slots[0].value = NULL;
|
||||
return &ht->buckets[k]->slots[0];
|
||||
}
|
||||
|
||||
// search for key in bucket
|
||||
for (size_t i = 0; i < ht->buckets[k]->nr_slots; i++) {
|
||||
if (!strcmp(ht->buckets[k]->slots[i].key, key))
|
||||
return &ht->buckets[k]->slots[i];
|
||||
}
|
||||
|
||||
// alloc new slot
|
||||
size_t i = ht->buckets[k]->nr_slots;
|
||||
ht->buckets[k] = xrealloc(ht->buckets[k], sizeof(struct ht_bucket) + sizeof(struct ht_slot)*(i+1));
|
||||
ht->buckets[k]->nr_slots = i+1;
|
||||
ht->buckets[k]->slots[i].key = key;
|
||||
ht->buckets[k]->slots[i].value = NULL;
|
||||
return &ht->buckets[k]->slots[i];
|
||||
}
|
||||
|
||||
void ht_foreach_value(struct hash_table *ht, void(*fun)(void*))
|
||||
{
|
||||
for (size_t i = 0; i < ht->nr_buckets; i++) {
|
||||
if (!ht->buckets[i])
|
||||
continue;
|
||||
for (size_t j = 0; j < ht->buckets[i]->nr_slots; j++) {
|
||||
fun(ht->buckets[i]->slots[j].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ht_free(struct hash_table *ht)
|
||||
{
|
||||
for (size_t i = 0; i < ht->nr_buckets; i++) {
|
||||
free(ht->buckets[i]);
|
||||
}
|
||||
free(ht);
|
||||
}
|
||||
@@ -377,6 +377,17 @@ struct instruction instructions[NR_OPCODES] = {
|
||||
TODO ( OP_0X103, 0 ),
|
||||
TODO ( OP_0X104, 0 ),
|
||||
TODO ( OP_0X105, 1, T_STRUCT ),
|
||||
TODO ( OP_0X106, 1, T_INT ),
|
||||
TODO ( OP_0X107, 0 ),
|
||||
TODO ( OP_0X108, 0 ),
|
||||
TODO ( OP_0X109, 0 ),
|
||||
TODO ( OP_0X10A, 1, T_INT ),
|
||||
TODO ( OP_0X10B, 2, T_INT, T_INT ),
|
||||
TODO ( OP_0X10C, 1, T_INT ),
|
||||
TODO ( OP_0X10D, 1, T_INT ),
|
||||
TODO ( OP_0X10E, 1, T_INT ),
|
||||
TODO ( OP_0X10F, 0 ),
|
||||
TODO ( OP_0X110, 1, T_INT ),
|
||||
};
|
||||
|
||||
void initialize_instructions(void)
|
||||
|
||||
@@ -9,6 +9,7 @@ system4 = ['afa.c',
|
||||
'ex.c',
|
||||
'file.c',
|
||||
'fnl.c',
|
||||
'hashtable.c',
|
||||
'instructions.c',
|
||||
'pms.c',
|
||||
'qnt.c',
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ used in AliceSoft games. The currently included tools are:
|
||||
* aindump - used to extract information from .ain files (code, text, etc.)
|
||||
* ainedit - used to reinsert information back into an .ain file
|
||||
* exdump - used to extract information from .ex files (static data)
|
||||
* exbuild - used to rebuild an .ex file dumpbed by exdump
|
||||
* exbuild - used to rebuild an .ex file dumped by exdump
|
||||
|
||||
More tools are planned for future releases.
|
||||
|
||||
|
||||
@@ -323,17 +323,17 @@ static void ain_dump_libraries(FILE *out, struct ain *ain)
|
||||
fprintf(out, " ---\n");
|
||||
for (int j = 0; j < ain->libraries[i].nr_functions; j++) {
|
||||
struct ain_hll_function *f = &ain->libraries[i].functions[j];
|
||||
print_sjis(out, ain_strtype(ain, f->data_type, -1));
|
||||
print_sjis(out, ain_strtype(ain, f->return_type.data, f->return_type.struc));
|
||||
fputc(' ', out);
|
||||
print_sjis(out, f->name);
|
||||
fputc('(', out);
|
||||
for (int k = 0; k < f->nr_arguments; k++) {
|
||||
struct ain_hll_argument *a = &f->arguments[k];
|
||||
if (a->data_type == AIN_VOID)
|
||||
if (a->type.data == AIN_VOID)
|
||||
continue;
|
||||
if (k > 0)
|
||||
fprintf(out, ", ");
|
||||
print_sjis(out, ain_strtype(ain, a->data_type, -1));
|
||||
print_sjis(out, ain_strtype(ain, a->type.data, a->type.struc));
|
||||
fputc(' ', out);
|
||||
print_sjis(out, a->name);
|
||||
}
|
||||
|
||||
@@ -141,13 +141,15 @@ static cJSON *ain_library_to_json(struct ain_library *lib)
|
||||
for (int i = 0; i < lib->nr_functions; i++) {
|
||||
cJSON *f = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(f, "name", lib->functions[i].name);
|
||||
cJSON_AddNumberToObject(f, "return-type", lib->functions[i].data_type);
|
||||
cJSON_AddNumberToObject(f, "return-type", lib->functions[i].return_type.data);
|
||||
// TODO: v14 has full variable type
|
||||
|
||||
cJSON *args = cJSON_CreateArray();
|
||||
for (int j = 0; j < lib->functions[i].nr_arguments; j++) {
|
||||
cJSON *arg = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(arg, "name", lib->functions[i].arguments[j].name);
|
||||
cJSON_AddNumberToObject(arg, "type", lib->functions[i].arguments[j].data_type);
|
||||
cJSON_AddNumberToObject(arg, "type", lib->functions[i].arguments[j].type.data);
|
||||
// TODO: v14 has full variable type
|
||||
cJSON_AddItemToArray(args, arg);
|
||||
}
|
||||
cJSON_AddItemToObject(f, "arguments", args);
|
||||
|
||||
@@ -272,14 +272,20 @@ static void read_library_declaration(cJSON *decl, struct ain_library *dst)
|
||||
struct ain_hll_function *funs = xcalloc(cJSON_GetArraySize(jfuns), sizeof(struct ain_hll_function));
|
||||
cJSON_ArrayForEachIndex(i, f, jfuns) {
|
||||
funs[i].name = cJSON_GetObjectString_NonNull(f, "name");
|
||||
funs[i].data_type = cJSON_GetObjectInteger_NonNull(f, "return-type");
|
||||
funs[i].return_type.data = cJSON_GetObjectInteger_NonNull(f, "return-type");
|
||||
// TODO: v14 has full variable type
|
||||
funs[i].return_type.struc = -1;
|
||||
funs[i].return_type.rank = 0;
|
||||
|
||||
int j;
|
||||
cJSON *arg, *jargs = cJSON_GetObjectArray_NonNull(f, "arguments");
|
||||
struct ain_hll_argument *args = xcalloc(cJSON_GetArraySize(jargs), sizeof(struct ain_hll_argument));
|
||||
cJSON_ArrayForEachIndex(j, arg, jargs) {
|
||||
args[j].name = cJSON_GetObjectString_NonNull(arg, "name");
|
||||
args[j].data_type = cJSON_GetObjectInteger_NonNull(arg, "type");
|
||||
args[j].type.data = cJSON_GetObjectInteger_NonNull(arg, "type");
|
||||
// TODO: v14 has full variable type
|
||||
args[j].type.struc = -1;
|
||||
args[j].type.rank = 0;
|
||||
}
|
||||
funs[i].nr_arguments = j;
|
||||
funs[i].arguments = args;
|
||||
|
||||
+16
-14
@@ -76,23 +76,17 @@ static void write_header(struct ain_buffer *out, const char *s)
|
||||
write_bytes(out, (const uint8_t*)s, 4);
|
||||
}
|
||||
|
||||
static void write_array_type(struct ain_buffer *out, possibly_unused struct ain *ain, struct ain_type *t)
|
||||
{
|
||||
for (int i = 0; i < t[0].rank+1; i++) {
|
||||
write_int32(out, t[i].data);
|
||||
write_int32(out, t[i].struc);
|
||||
write_int32(out, t[i].rank);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_variable_type(struct ain_buffer *out, struct ain *ain, struct ain_type *t)
|
||||
{
|
||||
write_int32(out, t->data);
|
||||
write_int32(out, t->struc);
|
||||
write_int32(out, t->rank);
|
||||
|
||||
if (t->data == AIN_ARRAY || t->data == AIN_REF_ARRAY || t->data == AIN_ITERATOR || t->data == AIN_ENUM1)
|
||||
write_array_type(out, ain, t->array_type);
|
||||
if (ain_array_data_type(t->data)) {
|
||||
for (int i = 0; i < t->rank; i++) {
|
||||
write_variable_type(out, ain, &t->array_type[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write_return_type(struct ain_buffer *out, struct ain *ain, struct ain_type *t)
|
||||
@@ -184,17 +178,25 @@ static void write_structure(struct ain_buffer *out, struct ain *ain, struct ain_
|
||||
}
|
||||
}
|
||||
|
||||
static void write_library(struct ain_buffer *out, possibly_unused struct ain *ain, struct ain_library *lib)
|
||||
static void write_library(struct ain_buffer *out, struct ain *ain, struct ain_library *lib)
|
||||
{
|
||||
write_string(out, lib->name);
|
||||
write_int32(out, lib->nr_functions);
|
||||
for (int i = 0; i < lib->nr_functions; i++) {
|
||||
write_string(out, lib->functions[i].name);
|
||||
write_int32(out, lib->functions[i].data_type);
|
||||
if (ain->version >= 14) {
|
||||
write_variable_type(out, ain, &lib->functions[i].return_type);
|
||||
} else {
|
||||
write_int32(out, lib->functions[i].return_type.data);
|
||||
}
|
||||
write_int32(out, lib->functions[i].nr_arguments);
|
||||
for (int j = 0; j < lib->functions[i].nr_arguments; j++) {
|
||||
write_string(out, lib->functions[i].arguments[j].name);
|
||||
write_int32(out, lib->functions[i].arguments[j].data_type);
|
||||
if (ain->version >= 14) {
|
||||
write_variable_type(out, ain, &lib->functions[i].arguments[j].type);
|
||||
} else {
|
||||
write_int32(out, lib->functions[i].arguments[j].type.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user