Theirsce specific text extraction, part 1

This commit is contained in:
Mc-muffin
2023-01-06 22:39:17 -05:00
committed by fortiersteven
parent fff640c439
commit 9da8a6104e
5 changed files with 1021 additions and 17 deletions

263
FileIO.py Normal file
View File

@@ -0,0 +1,263 @@
from io import BytesIO
import struct
class FileIO(object):
def __init__(self, path="", mode="r+b", endian="little"):
self.f = path
self.mode = mode
if type(path) is bytes:
self.path = None
self.is_memory_file = True
else:
self.path = path
self.is_memory_file = False
self.endian = "<" if endian == "little" or endian == "<" else ">"
def __enter__(self):
if self.is_memory_file:
self.f = BytesIO(self.f)
else:
self.f = open(self.path, self.mode)
self.f.seek(0)
return self
def __exit__(self, exc_type, exc_value, traceback):
self.f.close()
def close(self):
self.f.close()
def tell(self):
return self.f.tell()
def seek(self, pos, whence=0):
self.f.seek(pos, whence)
def read(self, n=-1):
return self.f.read(n)
def read_at(self, pos, n=-1):
current = self.tell()
self.seek(pos)
ret = self.read(n)
self.seek(current)
return ret
def write(self, data):
self.f.write(data)
def write_at(self, pos, data):
current = self.tell()
self.seek(pos)
self.write(data)
self.seek(current)
def peek(self, n):
pos = self.tell()
ret = self.read(n)
self.seek(pos)
return ret
def write_line(self, data):
self.f.write(data + "\n")
def set_endian(self, endian):
self.endian = "<" if endian == "little" or endian == "<" else ">"
def read_int8(self):
return struct.unpack("b", self.read(1))[0]
def read_int8_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_int8()
self.seek(current)
return ret
def read_uint8(self):
return struct.unpack("B", self.read(1))[0]
def read_uint8_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_uint8()
self.seek(current)
return ret
def read_int16(self):
return struct.unpack(self.endian + "h", self.read(2))[0]
def read_int16_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_int16()
self.seek(current)
return ret
def read_uint16(self):
return struct.unpack(self.endian + "H", self.read(2))[0]
def read_uint16_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_uint16()
self.seek(current)
return ret
def read_int32(self):
return struct.unpack(self.endian + "i", self.read(4))[0]
def read_int32_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_int32()
self.seek(current)
return ret
def read_uint32(self):
return struct.unpack(self.endian + "I", self.read(4))[0]
def read_uint32_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_uint32()
self.seek(current)
return ret
def read_int64(self):
return struct.unpack(self.endian + "q", self.read(8))[0]
def read_int64_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_int64()
self.seek(current)
return ret
def read_uint64(self):
return struct.unpack(self.endian + "Q", self.read(8))[0]
def read_uint64_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_uint64()
self.seek(current)
return ret
def read_single(self):
return struct.unpack(self.endian + "f", self.read(4))[0]
def read_single_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_single()
self.seek(current)
return ret
def read_double(self):
return struct.unpack(self.endian + "d", self.read(8))[0]
def read_double_at(self, pos):
current = self.tell()
self.seek(pos)
ret = self.read_double()
self.seek(current)
return ret
def skip_padding(self, alignment):
while self.tell() % alignment != 0:
self.read_uint8()
def write_int8(self, num):
self.f.write(struct.pack("b", num))
def write_int8_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_int8(num)
self.seek(current)
def write_uint8(self, num):
self.f.write(struct.pack("B", num))
def write_uint8_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_uint8(num)
self.seek(current)
def write_int16(self, num):
self.f.write(struct.pack(self.endian + "h", num))
def write_int16_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_int16(num)
self.seek(current)
def write_uint16(self, num):
self.f.write(struct.pack(self.endian + "H", num))
def write_uint16_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_uint16(num)
self.seek(current)
def write_int32(self, num):
self.f.write(struct.pack(self.endian + "i", num))
def write_int32_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_int32(num)
self.seek(current)
def write_uint32(self, num):
self.f.write(struct.pack(self.endian + "I", num))
def write_uint32_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_uint32(num)
self.seek(current)
def write_int64(self, num):
self.f.write(struct.pack(self.endian + "q", num))
def write_int64_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_int64(num)
self.seek(current)
def write_uint64(self, num):
self.f.write(struct.pack(self.endian + "Q", num))
def write_uint64_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_uint64(num)
self.seek(current)
def write_single(self, num):
self.f.write(struct.pack(self.endian + "f", num))
def write_single_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_single(num)
self.seek(current)
def write_double(self, num):
self.f.write(struct.pack(self.endian + "d", num))
def write_double_at(self, pos, num):
current = self.tell()
self.seek(pos)
self.write_double(num)
self.seek(current)
def write_padding(self, alignment, pad_byte=0x00):
while self.tell() % alignment != 0:
self.write_uint8(pad_byte)

View File

@@ -15,6 +15,8 @@ from pathlib import Path
import string
import io
import pak2 as pak2lib
from theirsce import Theirsce
from theirsce_instructions import InstructionType, TheirsceStringInstruction
class ToolsTOR(ToolsTales):
@@ -56,6 +58,7 @@ class ToolsTOR(ToolsTales):
#byteCode
self.story_byte_code = b"\xF8"
self.string_opcode = InstructionType.STRING
self.list_status_insertion = ['Done', 'Proofreading']
self.mkdir('../Data/{}/DAT'.format(self.repo_name))
@@ -240,23 +243,10 @@ class ToolsTOR(ToolsTales):
#Create the XML file
root = etree.Element('SceneText')
etree.SubElement(root, "OriginalName").text = file_name
stringsNode = etree.SubElement(root, "Strings")
theirsce.seek(0)
#Validate the header
header = theirsce.read(8)
if header != b"THEIRSCE":
raise ValueError("No THEIRSCE header")
#Start of the pointer
pointer_block = struct.unpack("<L", theirsce.read(4))[0]
#Start of the text and baseOffset
strings_offset = struct.unpack("<L", theirsce.read(4))[0]
#File size
fsize = theirsce.getbuffer().nbytes
theirsce.seek(pointer_block, 0) #Go the the start of the pointer section
pointers_offset, texts_offset = self.extract_Story_Pointers(theirsce, strings_offset, fsize, self.story_byte_code)
stringsNode = etree.SubElement(root, "Strings")
rsce = Theirsce(path=theirsce)
pointers_offset, texts_offset = self.extract_Story_Pointers(rsce)
text_list = [self.bytes_to_text(theirsce, ele)[0] for ele in texts_offset]
@@ -281,6 +271,16 @@ class ToolsTOR(ToolsTales):
'../Data/{}/{}/XML/{}.xml'.format(self.repo_name, section, self.get_file_name(file_name))
)
def extract_Story_Pointers(self, theirsce: Theirsce):
pointers_offset = []; texts_offset = []
for opcode in theirsce.walk_code():
if opcode == self.string_opcode:
pointers_offset.append(theirsce.tell() - 2) # Maybe check this later
texts_offset.append(opcode.offset + theirsce.strings_offset)
return pointers_offset, texts_offset
#Convert a bytes object to text using TAGS and TBL in the json file
def bytes_to_text(self, fileRead, offset=-1, end_strings = b"\x00"):

189
theirsce.py Normal file
View File

@@ -0,0 +1,189 @@
from typing import Generator
from FileIO import FileIO
from dataclasses import dataclass, field
from enum import Enum
from theirsce_instructions import *
from theirsce_funcs import *
# I followed other project when making this class
# not sure how if it's the best approach
SECTION_AMOUNT = 6
@dataclass
class subsection:
unk1: int
unk2: int
off: int
class Theirsce(FileIO):
def __init__(self, path=""):
super().__init__(path, "r+b", "<")
super().__enter__()
self.magic = self.read(8)
if self.magic != b"THEIRSCE":
raise ValueError("Not a THEIRSCE file!")
self.code_offset = self.read_uint32()
self.strings_offset = self.read_uint32()
self.unk_field = self.read_uint32()
self.frame_offset = self.read_uint16()
self.entry_offset = self.read_uint16()
self.sections: list[subsection] = []
# section_stop = self.readUShort(); self.seek(-2, 1)
#section_amount = (section_stop - 0x18) // 2
for _ in range(SECTION_AMOUNT):
pos = self.tell() + 2
self.seek(self.read_uint16())
subsections = []
for _ in range(self.read_uint16()):
sub = subsection(self.read_uint16(), self.read_uint16(), self.read_uint16() + self.code_offset)
subsections.append(sub)
self.sections.append(subsections)
self.seek(pos)
def __enter__(self):
return super().__enter__()
def __exit__(self, exc_type, exc_value, traceback):
return super().__exit__(exc_type, exc_value, traceback)
def walk_code(self, start=None, end=None) -> Generator[None, TheirsceBaseInstruction, None]:
start = self.code_offset if start is None else start
end = self.strings_offset if end is None else end
self.seek(start)
while self.tell() < end:
pos = self.tell()
yield self.read_opcode()
self.seek(pos)
def read_opcode(self):
opcode = self.read_uint8()
# Reference Block
if opcode < 0x80:
var_type = (opcode >> 4) & 7
shift = 0
#id = mask
if var_type == 0: # bitfields
value = self.read_uint8()
if opcode & 8 == 0:
next_byte = opcode & 3
pass
else:
next_byte = self.read_uint8()
pass
shift = (value & 7) #<< 3
value = ((( value | (next_byte << 8)) >> 3) & 0xFF)
else:
value = self.read_uint8()
top = 1
if opcode & 8 != 0:
top = 2
next_byte = self.read_uint8()
value = ( ((next_byte & 0xFF) << 8) | (value & 0xFF))
value = ((opcode & 3) << (8 * top)) | value
# scope
if opcode & 4 == 0:
if value < 0x400:
scope = ReferenceScope.GLOBAL
else:
scope = ReferenceScope.FILE
value -= 0x400
else:
scope = ReferenceScope.LOCAL
return TheirsceReferenceInstruction(ref_type=VariableType(var_type), scope=scope, offset=value, shift=shift)
# ALU operations
elif opcode < 0xC0:
return TheirsceAluInstruction(operation = AluOperation(opcode & 0x3F))
# PUSH block, the amount of bytes depend on encoding
elif opcode < 0xE0:
size_mask = (opcode >> 3) & 3
signed = opcode & 4 != 0
top = opcode & 7
if size_mask == 0:
value = 0xFFFFFF00 | (top | 0xF8) if signed else top
if size_mask == 1:
value = top << 8 | self.read_uint8()
value = value | 0xFFFF0000 | 0xF800 if signed else value
elif size_mask == 2:
value = top << 16 | self.read_uint16()
value = value | 0xFF000000 | 0xF80000 if signed else value
elif size_mask == 3:
value = self.read_uint32()
# to signed
value = value | (-(value & 0x80000000))
return TheirscePushInstruction(value=value)
# CALL block, available commands are at 0x1e5300
# first entry is number of parameters then function
elif opcode < 0xF0:
index = ((opcode & 0xF) << 8) | self.read_uint8()
return TheirsceSyscallInstruction(function_index=index, function_name=SYSCALL_NAMES[index])
# Flow related block
elif opcode < 0xF8:
if opcode == 0xF0:
return TheirsceReturnInstruction(is_void=True)
elif opcode == 0xF1:
return TheirsceReturnInstruction(is_void=False)
# Need to be offsetted to start of code
elif opcode >= 0xF2 and opcode < 0xF5:
target = self.code_offset + self.read_uint16()
return TheirsceBranchInstruction(branch_type=BranchType(opcode - 0xF2), destination=target)
elif opcode == 0xF5:
target = self.code_offset + self.read_uint16()
reserve = self.read_uint16()
return TheirsceLocalCallInstruction(destination=target, reserve=reserve)
# ?
elif opcode == 0xF6:
variables = self.read_uint8()
params = []
for _ in range(variables):
if self.read_uint8() & 8 != 0:
params.append(self.read_uint16())
else:
params.append(self.read_uint8())
return TheirsceAcquireInstruction(params=params,variables=variables)
elif opcode == 0xF7:
param = self.read_uint16() # Type?
return TheirsceBreakInstruction(param=param)
# Get string
elif opcode < 0xFC:
value = ((opcode & 3) << 16) | self.read_uint16()
return TheirsceStringInstruction(offset=value,text="")
# ?
elif opcode == 0xFE:
return TheirsceSpecialReferenceInstruction()
# Impossible
else:
raise ValueError(f"INVALID OPCODE 0x{opcode:2X}")
# if __name__ == "__main__":
# with Theirsce("./10233d.theirsce") as f:
# for op in f.walk_code():
# if op.type == InstructionType.ACQUIRE:
# print(op)

371
theirsce_funcs.py Normal file
View File

@@ -0,0 +1,371 @@
SYSCALL_NAMES = (
"printf", # 0x0
None, # 0x1
None, # 0x2
None, # 0x3
None, # 0x4
"set_person", # 0x5
"set_person_3d", # 0x6
"set_position", # 0x7
"set_position_3d", # 0x8
"delete_person", # 0x9
"animate_person", # 0xA
"set_balloon", # 0xB
"get_param", # 0xC
"set_param", # 0xD
"move_position", # 0xE
"move_position_3d", # 0xF
"na_move_position", # 0x10
"na_move_position_3d", # 0x11
"move_check", # 0x12
"sky_init", # 0x13
"cloud_init", # 0x14
"cloud_inc_alpha", # 0x15
"cloud_dec_alpha", # 0x16
"delete_cloud_dec_alpha", # 0x17
"trap_line", # 0x18
"trap_box", # 0x19
"trap_box_stoptimer", # 0x1A
"trap_box_stoptimer_pop", # 0x1B
"trap_poly4", # 0x1C
"trap_poly4_stoptimer", # 0x1D
"trap_poly4_stoptimer_pop", # 0x1E
"trap_line_3d", # 0x1F
"trap_box_3d", # 0x20
"trap_box_stoptimer_3d", # 0x21
"trap_box_stoptimer_pop_3d", # 0x22
"trap_poly4_3d", # 0x23
"trap_poly4_stoptimer_3d", # 0x24
"trap_poly4_stoptimer_pop_3d",# 0x25
"trap_contact_chr", # 0x26
"delete_trap", # 0x27
"is_trap", # 0x28
"event_line", # 0x29
"event_box", # 0x2A
"event_poly4", # 0x2B
"event_line_3d", # 0x2C
"event_box_3d", # 0x2D
"event_poly4_3d", # 0x2E
"delete_event", # 0x2F
"is_event", # 0x30
"line_hit", # 0x31
"line_hit_ply", # 0x32
"line_hit_npc", # 0x33
"line_hit_3d", # 0x34
"line_hit_ply_3d", # 0x35
"line_hit_npc_3d", # 0x36
"delete_line_hit", # 0x37
"is_line_hit", # 0x38
"scope", # 0x39
"scope_3d", # 0x3A
"delete_scope", # 0x3B
"is_scope", # 0x3C
"scroll_direct", # 0x3D
"scroll", # 0x3E
"zoom_scroll", # 0x3F
"is_scroll", # 0x40
"scroll_four", # 0x41
None, # 0x42
"fst_load", # 0x43
"gradation_palet", # 0x44
None, # 0x45
None, # 0x46
None, # 0x47
None, # 0x48
None, # 0x49
None, # 0x4A
None, # 0x4B
None, # 0x4C
None, # 0x4D
None, # 0x4E
None, # 0x4F
None, # 0x50
None, # 0x51
None, # 0x52
None, # 0x53
None, # 0x54
None, # 0x55
None, # 0x56
None, # 0x57
None, # 0x58
None, # 0x59
None, # 0x5A
None, # 0x5B
None, # 0x5C
None, # 0x5D
None, # 0x5E
None, # 0x5F
None, # 0x60
None, # 0x61
None, # 0x62
None, # 0x63
None, # 0x64
"event_line_inf", # 0x65
"event_box_inf", # 0x66
"event_poly4_inf", # 0x67
"event_line_3d_inf", # 0x68
"event_box_3d_inf", # 0x69
"event_poly4_3d_inf", # 0x6A
None, # 0x6B
None, # 0x6C
None, # 0x6D
None, # 0x6E
None, # 0x6F
"scroll_cnt", # 0x70
"zoom_scroll_cnt", # 0x71
"map_bright", # 0x72
"change_bg_anime", # 0x73
"get_bg_anime_param", # 0x74
"scope_msg", # 0x75
"scope_msg_3d", # 0x76
None, # 0x77
None, # 0x78
None, # 0x79
None, # 0x7A
None, # 0x7B
None, # 0x7C
"is_sideview", # 0x7D
"get_map_no", # 0x7E
"bg_alpha", # 0x7F
None, # 0x80
None, # 0x81
None, # 0x82
None, # 0x83
None, # 0x84
None, # 0x85
None, # 0x86
None, # 0x87
None, # 0x88
None, # 0x89
None, # 0x8A
None, # 0x8B
None, # 0x8C
None, # 0x8D
None, # 0x8E
"get_sys_map_rate", # 0x8F
None, # 0x90
None, # 0x91
None, # 0x92
None, # 0x93
None, # 0x94
None, # 0x95
None, # 0x96
None, # 0x97
None, # 0x98
None, # 0x99
"get_int_no", # 0x9A
None, # 0x9B
None, # 0x9C
None, # 0x9D
"special_person", # 0x9E
"special_person_3d", # 0x9F
None, # 0xA0
None, # 0xA1
None, # 0xA2
None, # 0xA3
"walk_se", # 0xA4
"get_mapsize_x", # 0xA5
"get_mapsize_y", # 0xA6
"set_3d_zoom_rate", # 0xA7
None, # 0xA8
None, # 0xA9
"set_cloud_h", # 0xAA
"move_stop", # 0xAB
None, # 0xAC
"set_child_chr", # 0xAD
"del_child_chr", # 0xAE
"get_child_pos", # 0xAF
"get_parent_chr", # 0xB0
"is_bg_atari", # 0xB1
None, # 0xB2
"set_gradation_chr", # 0xB3
"set_rot_chr_color", # 0xB4
"scroll_offset", # 0xB5
None, # 0xB6
None, # 0xB7
"set_bg_pal_anime", # 0xB8
None, # 0xB9
"get_pl_move_spd", # 0xBA
"get_pl_move_dir", # 0xBB
None, # 0xBC
None, # 0xBD
None, # 0xBE
None, # 0xBF
None, # 0xC0
None, # 0xC1
None, # 0xC2
None, # 0xC3
None, # 0xC4
None, # 0xC5
"set_force_mode", # 0xC6
"trap_force_line", # 0xC7
"trap_force_box", # 0xC8
"trap_force_poly4", # 0xC9
"trap_force_line_3d", # 0xCA
"trap_force_box_3d", # 0xCB
"trap_force_poly4_3d", # 0xCC
"trap_force_rain_point", # 0xCD
"trap_force_chr", # 0xCE
"line_hit_force", # 0xCF
"line_hit_force_3d", # 0xD0
"get_force_pow", # 0xD1
"get_force_lever", # 0xD2
"set_csp_param", # 0xD3
"get_csp_param", # 0xD4
"calc_csp_param", # 0xD5
None, # 0xD6
None, # 0xD7
None, # 0xD8
None, # 0xD9
"set_move_pass", # 0xDA
"move_pass", # 0xDB
None, # 0xDC
"scroll_limit", # 0xDD
None, # 0xDE
None, # 0xDF
None, # 0xE0
None, # 0xE1
"demo_stop_move_pass", # 0xE2
None, # 0xE3
None, # 0xE4
"trap_force_rain_point_3d", # 0xE5
"trap_force_rain_chr", # 0xE6
"get_force_rain_trap_count", # 0xE7
"get_force_rain_trap_no", # 0xE8
None, # 0xE9
"get_prev_crate", # 0xEA
None, # 0xEB
None, # 0xEC
None, # 0xED
None, # 0xEE
None, # 0xEF
None, # 0xF0
"force_obj_delete", # 0xF1
"get_force_action", # 0xF2
None, # 0xF3
None, # 0xF4
None, # 0xF5
"set_chr_bright", # 0xF6
None, # 0xF7
"set_fade_chr_color", # 0xF8
None, # 0xF9
None, # 0xFA
"set_line_hit_mode", # 0xFB
None, # 0xFC
None, # 0xFD
None, # 0xFE
"trap_force_box_ivy_up", # 0xFF
"trap_force_box_ivy_dn", # 0x100
"trap_force_poly4_ivy_up", # 0x101
"trap_force_poly4_ivy_dn", # 0x102
None, # 0x103
"set_ladder", # 0x104
None, # 0x105
None, # 0x106
None, # 0x107
"print_screen", # 0x108
"cross_fade", # 0x109
None, # 0x10A
None, # 0x10B
None, # 0x10C
None, # 0x10D
None, # 0x10E
None, # 0x10F
"define_texture", # 0x110
"get_ce_arg", # 0x111
"set_ce_arg", # 0x112
"set4_ce_arg", # 0x113
None, # 0x114
None, # 0x115
None, # 0x116
None, # 0x117
None, # 0x118
None, # 0x119
None, # 0x11A
None, # 0x11B
"set_weather_disp", # 0x11C
None, # 0x11D
None, # 0x11E
"set_keyframe", # 0x11F
"set_keyframe_arg", # 0x120
"delete_keyframe", # 0x121
None, # 0x122
None, # 0x123
None, # 0x124
None, # 0x125
None, # 0x126
"debug_bp", # 0x127
None, # 0x128
None, # 0x129
None, # 0x12A
None, # 0x12B
None, # 0x12C
None, # 0x12D
None, # 0x12E
None, # 0x12F
None, # 0x130
None, # 0x131
None, # 0x132
None, # 0x133
None, # 0x134
None, # 0x135
None, # 0x136
None, # 0x137
None, # 0x138
None, # 0x139
None, # 0x13A
None, # 0x13B
None, # 0x13C
None, # 0x13D
None, # 0x13E
None, # 0x13F
None, # 0x140
None, # 0x141
# PSP only
None, # 0x142
None, # 0x143
None, # 0x144
None, # 0x145
None, # 0x146
None, # 0x147
None, # 0x148
None, # 0x149
None, # 0x14A
None, # 0x14B
None, # 0x14C
None, # 0x14D
None, # 0x14E
None, # 0x14F
None, # 0x150
None, # 0x151
None, # 0x152
None, # 0x153
)
SYSCALL_ARGUMENT_COUNT = (
0x02,0x02,0x01,0x01,0x00,0x06,0x07,0x03,0x04,0x01,0x03,0x05,0x02,0x03,0x04,
0x05,0x04,0x05,0x01,0x02,0x06,0x00,0x00,0x00,0x06,0x06,0x07,0x08,0x0A,0x0B,
0x0C,0x08,0x08,0x09,0x0A,0x0E,0x0F,0x10,0x02,0x01,0x01,0x06,0x06,0x0A,0x08,
0x08,0x0E,0x01,0x01,0x06,0x06,0x06,0x08,0x08,0x08,0x01,0x01,0x05,0x06,0x01,
0x01,0x02,0x03,0x04,0x00,0x03,0x06,0x02,0x03,0x08,0x01,0x04,0x02,0x01,0x01,
0x01,0x00,0x01,0x01,0x07,0x05,0x01,0x02,0x00,0x00,0x00,0x00,0x02,0x03,0x01,
0x01,0x01,0x04,0x00,0x02,0x01,0x02,0x01,0x02,0x01,0x01,0x07,0x07,0x0B,0x09,
0x09,0x0F,0x01,0x01,0x01,0x01,0x01,0x03,0x04,0x03,0x05,0x03,0x07,0x08,0x03,
0x04,0x07,0x01,0x03,0x02,0x00,0x00,0x02,0x02,0x04,0x09,0x04,0x01,0x01,0x02,
0x02,0x05,0x01,0x02,0x02,0x03,0x03,0x02,0x00,0x02,0x01,0x01,0x03,0x03,0x02,
0x01,0x01,0x01,0x09,0x00,0x01,0x00,0x01,0x0F,0x10,0x04,0x01,0x04,0x02,0x02,
0x01,0x01,0x01,0x01,0x08,0x01,0x01,0x02,0x03,0x01,0x01,0x01,0x04,0x01,0x06,
0x08,0x03,0x03,0x00,0x04,0x02,0x00,0x00,0x03,0x00,0x02,0x04,0x03,0x02,0x02,
0x01,0x02,0x03,0x01,0x06,0x06,0x0A,0x08,0x08,0x0E,0x04,0x02,0x06,0x08,0x00,
0x00,0x05,0x03,0x09,0x00,0x03,0x02,0x04,0x06,0x03,0x02,0x04,0x00,0x01,0x04,
0x01,0x03,0x01,0x02,0x05,0x02,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0x01,0x01,
0x01,0x00,0x00,0x08,0x01,0x00,0x04,0x04,0x07,0x08,0x02,0x01,0x00,0x00,0x02,
0x06,0x06,0x0A,0x0A,0x01,0x09,0x01,0x04,0x02,0x00,0x01,0x00,0x01,0x07,0x00,
0x01,0x02,0x09,0x04,0x05,0x08,0x01,0x00,0x01,0x03,0x03,0x0A,0x03,0x01,0x01,
0x02,0x01,0x09,0x02,0x03,0x01,0x02,0x01,0x06,0x03,0x01,0x00,0x05,0x01,0x00,
0x01,0x01,0x02,0x00,0x01,0x04,0x01,0x01,0x01,0x08,0x01,0x01,0x02,0x00,0x04,
0x06,0x00,0x00,0x05,0x02,0x02,0x01,
# PSP
0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x01,0x01,0x02,0x01,0x02,0x02,0x01,0x01,
0x01,0x01,0x04
)

181
theirsce_instructions.py Normal file
View File

@@ -0,0 +1,181 @@
from dataclasses import dataclass, field
from enum import Enum
class VariableType(Enum):
BIT = 0
BYTE = 1
SHORT = 2
INT = 3
PTR = 4
class ReferenceScope(Enum):
LOCAL = 0
FILE = 1
GLOBAL = 2
class BranchType(Enum):
UNCONDITIONAL = 0
NOT_EQUALS = 1
EQUALS = 2
class InstructionType(Enum):
ALU = 0
PUSH = 1
SYSCALL = 2
BRANCH = 3
LOCAL_CALL = 4
RETURN = 5
ACQUIRE = 6
BREAK = 7
STRING = 8
REFERENCE = 9
SP_REF = 10
class AluOperation(Enum):
# UNARY
SWITCH_POP = 0
POST_INCREMENT = 1
POST_DECREMENT = 2
PRE_INCREMENT = 3
PRE_DECREMENT = 4
ARITHMETIC_NEGATION = 5
BITWISE_NOT = 6
LOGICAL_NOT = 7
# BINARY
INDEX_ARRAY = 8
SUBSCRIPT = 8
MULTIPLICATION = 9
DIVISION = 10
MODULO = 11
ADDITION = 12
SUBTRACTION = 13
BITWISE_LEFT_SHIFT = 14
BITWISE_RIGHT_SHIFT = 15
GREATER_THAN = 16
LESS_THAN = 17
GREATER_THAN_OR_EQUALS = 18
LESS_THAN_OR_EQUALS = 19
EQUALS = 20
NOT_EQUALS = 21
BITWISE_AND = 22
BITWISE_XOR = 23
BITWISE_OR = 24
LOGICAL_AND = 25
LOGICAL_OR = 26
ASSIGNMENT = 27
MULTIPLICATION_ASSIGNMENT = 28
DIVISION_ASSIGNMENT = 29
MODULO_ASSIGNMENT = 30
ADDITION_ASSIGNMENT = 31
SUBTRACTION_ASSIGNMENT = 32
BITWISE_LEFT_SHIFT_ASSIGNMENT = 33
BITWISE_RIGHT_SHIFT_ASSIGNMENT = 34
BITWISE_AND_ASSIGNMENT = 35
BITWISE_XOR_ASSIGNMENT = 36
BITWISE_OR_ASSIGNMENT = 37
@dataclass
class TheirsceBaseInstruction:
mnemonic: str = field(default=False, init=False)
type: InstructionType = field(default=False, init=False)
#size: int
@dataclass
class TheirsceAluInstruction(TheirsceBaseInstruction):
operation: AluOperation
mnemonic = "ALU"
type = InstructionType.ALU
def __post_init__(self):
self.mnemonic = self.operation.name
@dataclass
class TheirscePushInstruction(TheirsceBaseInstruction):
value: int
mnemonic = "PUSH"
type = InstructionType.PUSH
@dataclass
class TheirsceSyscallInstruction(TheirsceBaseInstruction):
function_index: int
function_name: str
mnemonic = "SYSCALL"
type = InstructionType.SYSCALL
@dataclass
class TheirsceLocalCallInstruction(TheirsceBaseInstruction):
destination: int
reserve: int
mnemonic = "CALL"
type = InstructionType.LOCAL_CALL
@dataclass
class TheirsceAcquireInstruction(TheirsceBaseInstruction):
params: list[int]
variables: int
mnemonic = "ACQUIRE"
type = InstructionType.ACQUIRE
@dataclass
class TheirsceBreakInstruction(TheirsceBaseInstruction):
param: int
mnemonic = "BREAK"
type = InstructionType.BREAK
@dataclass
class TheirsceBranchInstruction(TheirsceBaseInstruction):
destination: int
branch_type: BranchType
mnemonic = ""
type = InstructionType.BRANCH
def __post_init__(self):
self.mnemonic = self.branch_type.name
@dataclass
class TheirsceReturnInstruction(TheirsceBaseInstruction):
is_void: bool
mnemonic = "RETURN"
type = InstructionType.RETURN
def __post_init__(self):
if self.is_void:
self.mnemonic += "_VOID"
@dataclass
class TheirsceStringInstruction(TheirsceBaseInstruction):
text: str
offset: int
mnemonic = "STRING"
type = InstructionType.STRING
@dataclass
class TheirsceReferenceInstruction(TheirsceBaseInstruction):
ref_type: VariableType
scope: ReferenceScope
offset: int
shift: int
mnemonic = "REF"
type = InstructionType.REFERENCE
@dataclass
class TheirsceSpecialReferenceInstruction(TheirsceBaseInstruction):
mnemonic = "SP_REF"
type = InstructionType.SP_REF