| What follows is the so-called 'disassembler'. This takes in pseudo-compiled Yazoo code (NOT real machine code) | and outputs a text version that is somewhat more readable. The two arguments are the compiled code string and | the position of the 'flag' (error flag) within that string. Index 1 = bytes 1-4, index 2 = 5th - 8th bytes, etc. | An flag position of 0 indicates no flag. The return value is the disassembly string. DisassemblePackage :: { Bytecode[*] :: slong FlagPosition :: NumberOfCompiledNames :: NumberOfWords :: DisasmStartPos :: ulong NameSpace :: Bytecode_string :: output :: string OutputDisAsm :: WriteVariableNames :: ExpandFunctions :: Boolean RunDisAsm :: { VarStart :: VarEnd :: CN_counter :: WordCounter :: args_error :: ulong rtrn :: * code WriteVariableNames = false OutputDisAsm = ExpandFunctions = true DisasmStartPos = FlagPosition = 0 args_error = trap( if trap(Bytecode_string = args[1]) /= passed { Bytecode_string, DisasmStartPos } = args[1] endif if trap(args[2]) == passed, OutputDisAsm = args[2], endif if trap(args[3]) == passed, NameSpace = args[3], WriteVariableNames = true, endif if trap(args[4]) == passed, ExpandFunctions = args[4], endif if trap(args[5]) == passed, FlagPosition = args[5], endif if top(args) > 5, throw(1), endif if ExpandFunctions > true or OutputDisAsm > true, throw(1), endif if size(Bytecode_string) mod word_size /= 0 or size(Bytecode_string) == 0 printl("disassemble() error: code size is not N*size(slong) > 0") throw(100) endif NumberOfWords = size(Bytecode_string)/word_size if DisasmStartPos > NumberOfWords printl("disassemble() error: start_pos > # of words") throw(100) endif ) if args_error /= passed if args_error /= 100 print("usage: [bytecode string = ] disassemble((string) compiled_code/{code, start_pos} [, (Boolean) ") printl("output disassembly [, (string) NameSpace [, (Boolean) ExpandFunctions [, (numeric) flag_position]]]])") endif return endif if WriteVariableNames == true NumberOfCompiledNames = find(NameSpace, "\00", 0) - find(extract(NameSpace, 1, word_size), "\00", 0) CompiledNamesArray[^NumberOfCompiledNames] VarStart = size(ulong)+1 for CN_counter in [1, NumberOfCompiledNames] VarEnd = find(NameSpace, "\00", 1, VarStart)-1 CompiledNamesArray[CN_counter] = extract(NameSpace, VarStart, VarEnd) VarStart = VarEnd+2 end for endif Bytecode[^NumberOfWords] Bytecode =! Bytecode_string output = "" if trap( if DisasmStartPos == 0 WordCounter = 1 RecursionPackage.WriteSentences(WordCounter) if WordCounter /= NumberOfWords+1, cat(output, "[Not the correct end-of-code]\n"), endif else WordCounter = DisasmStartPos RecursionPackage.WriteExpression(WordCounter) args[1][2] = WordCounter endif ) /= passed, printl("disassemble() error: problem with the bytecode"), return, endif if OutputDisAsm == true return ((rtrn =@ *) = @output) else return endif } RecursionPackage :: { IfWrite :: Boolean WriteSentences :: { WS_ExpressionTop :: * BottomLevel := false code WS_ExpressionTop = @args[1] while Bytecode[WS_ExpressionTop] /= 0 WriteExpression(WS_ExpressionTop) if Bytecode[WS_ExpressionTop] /= 0 and OutputDisAsm == true if BottomLevel == true, cat(output, "\n") elseif IfWrite == true, cat(output, ", ") endif endif end while WS_ExpressionTop = that + 1 | get past the null terminator if WS_ExpressionTop > FlagPosition and FlagPosition /= 0 and OutputDisAsm == true cat(output, "<-- ***** ") FlagPosition = 0 endif if BottomLevel == true and OutputDisAsm == true cat(output, "\n") endif WS_ExpressionTop =@ * } WriteExpression :: { DP_cat_fulloutput :: { code if IfWrite == false, return, endif cat(output, args) } DP_cat_linesonly :: { } DP_cat *:: * CurrentCommand :: ExtraSkip :: ulong ExpressionTop *:: * code if OutputDisAsm == true, DP_cat = @DP_cat_fulloutput else, DP_cat = @DP_cat_linesonly endif ExpressionTop = @args[1] CurrentCommand = Bytecode[ExpressionTop] if CurrentCommand > top(InstructionWords), DP_cat("? ") elseif CurrentCommand == 2 DP_cat("[", YazooRegisterWords[Bytecode[ExpressionTop+1]+1], "] ") ExtraSkip = 1 elseif CurrentCommand == 3 DP_cat("[", YazooFunctionWords[Bytecode[ExpressionTop+1]+1], "] ") ExtraSkip = 1 elseif CurrentCommand == 5 if Bytecode[ExpressionTop+1] == 1, DP_cat("f ") else, DP_cat("f.", Bytecode[ExpressionTop+1], " "), endif ExtraSkip = 1 elseif CurrentCommand /= 11 DP_cat(InstructionWords[CurrentCommand+1], " ") ExtraSkip = 0 end if if (CurrentCommand >= 7 and CurrentCommand <= 9) DP_cat((JumpIndex::slong) =! Bytecode[ExpressionTop+1], " ") ExtraSkip = 1 elseif CurrentCommand == 11 ExtraSkip = 1 if Bytecode[ExpressionTop+1] == 1, DP_cat("equ ") elseif Bytecode[ExpressionTop+1] == 46, DP_cat("def ") elseif Bytecode[ExpressionTop+1] == 44, DP_cat("vdf ") elseif Bytecode[ExpressionTop+1] == 6, DP_cat("mdf ") elseif Bytecode[ExpressionTop+1] == 22, DP_cat("dqa ") elseif Bytecode[ExpressionTop+1] == 16, DP_cat("eqa ") elseif Bytecode[ExpressionTop+1] == 47, DP_cat("deq ") elseif Bytecode[ExpressionTop+1] == 302, DP_cat("pxdef ") elseif Bytecode[ExpressionTop+1] == 148, DP_cat("dqa* ") elseif Bytecode[ExpressionTop+1] == 172, DP_cat("def* ") elseif Bytecode[ExpressionTop+1] == 173, DP_cat("deq* ") elseif Bytecode[ExpressionTop+1] == 236, DP_cat("def** ") elseif Bytecode[ExpressionTop+1] == 237, DP_cat("deq** ") elseif Bytecode[ExpressionTop+1] == 204, DP_cat("def-c** ") else, DP_cat("dg ", (DGFlags::ulong) = Bytecode[ExpressionTop+1], " ") end if elseif CurrentCommand == 17 (mID::slong) =! Bytecode[ExpressionTop+1] if WriteVariableNames == false, DP_cat(mID, " ") elseif mID < 0, DP_cat("$", -mID, " ") elseif mID > NumberOfCompiledNames, DP_cat("?? ") else, DP_cat("$", CompiledNamesArray[mID], " ") end if ExtraSkip = 1 elseif CurrentCommand == 50 (const_slong::slong) =! Bytecode[ExpressionTop+1], DP_cat(const_slong, " ") ExtraSkip = 1 elseif CurrentCommand == 51 (const_double::double) =! Bytecode[ExpressionTop+1, ExpressionTop+doublesize_in_longs] DP_cat(const_double, " ") ExtraSkip = doublesize_in_longs elseif CurrentCommand == 52 (NumberOfChars::ulong) = Bytecode[ExpressionTop+1] (const_string::string) =! Bytecode[ExpressionTop+2, round_up(NumberOfChars/word_size)+ExpressionTop+1] CharArray[NumberOfChars] :: ubyte if NumberOfChars > 0 CharArray =! extract(const_string, 1, NumberOfChars) endif for (counter::ulong) in [1, NumberOfChars] if CharArray[counter] < 32 or CharArray[counter] > 127 CharArray[counter] = 35 endif, endf const_string =! CharArray remove CharArray DP_cat("\"", const_string, "\" ") ExtraSkip = round_up(NumberOfChars/word_size)+1 endif ExpressionTop = that + ExtraSkip if ExpressionTop > FlagPosition and FlagPosition /= 0 cat(output, "<-- ***** ") FlagPosition = 0 endif ExpressionTop = that + 1 if InstructionArguments[CurrentCommand+1] > 0 SubExpression::RecursionPackage DP_cat("( ") for (ArgumentCounter::ulong) in [1, InstructionArguments[CurrentCommand+1]] if ArgumentCounter /= 1, DP_cat(", "), endif SubExpression.IfWrite = IfWrite SubExpression.WriteExpression(ExpressionTop) endf if CurrentCommand /= 18, DP_cat(") "), endif end if if CurrentCommand == 18 (mID :: slong) =! Bytecode[ExpressionTop] if WriteVariableNames == false, DP_cat(", ", mID, " ") elseif mID < 0, DP_cat(", $", -mID, " ") elseif mID > NumberOfCompiledNames, DP_cat(", ?? ") else, DP_cat(", $", CompiledNamesArray[mID], " ") end if ExpressionTop = that + 1 DP_cat(") ") elseif CurrentCommand == 53 SubWriteSentences::RecursionPackage if IfWrite == false or ExpandFunctions == false, SubWriteSentences.IfWrite = false else, SubWriteSentences.IfWrite = true, endif DP_cat("{ ") if SubWriteSentences.IfWrite == false and IfWrite == true, cat(output, "... "), endif SubWriteSentences.WriteSentences(ExpressionTop) DP_cat("} ") end if if ExpressionTop > FlagPosition and FlagPosition /= 0 cat(output, "<-- ***** ") FlagPosition = 0 endif ExpressionTop =@ * } } RecursionPackage.WriteSentences.BottomLevel = true } DisassemblePackage.CompiledNamesArray[0] :: string DisassemblePackage.RecursionPackage.IfWrite = true DisassemblePackage.InstructionWords :: { "", "ret", "reg", "?", "?", "f", "args", "j", "jt", "jf", "exit", "dg", "feq", "?", "csub", "app", "rem", "sm", "sID", "sti", "stis", "s*", "rsz", "iiu", "iid", "del", "?", "this", "that", "no", "eq", "ne", "gt", "ge", "lt", "le", "and", "or", "eor", "not", "eq@", "ne@", "add", "sub", "mul", "div", "pow", "mod", "?", "?", "csl", "cf", "cst", "scr", "ub", "sb", "us", "ss", "ul", "sl", "sp", "db", "bl", "str", "prx", "code" } DisassemblePackage.InstructionArguments :: { 0, 1, 0, 1, 0, 2, 0, 0, 1, 1, 0, 2, 2, 0, 2, 2, 1, 0, 1, 2, 3, 1, 2, 3, 3, 1, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } DisassemblePackage.YazooRegisterWords :: { "R_sl", "R_db", "R_st", "R_cmp", "R_EC", "R_EI", "R_ES", "R_WC", "R_WI", "R_WS" } DisassemblePackage.YazooFunctionWords :: { "call", "compile", "transform", "load", "save", "input", "print", "read_string", "print_string", "clip", "trap", "throw", "top", "size", "abs", "round_down", "round_up", "log", "cos", "sin", "tan", "acos", "asin", "atan", "random", "extract", "find", "variable_type", "variable_member_top", "variable_code_top", "member_type", "member_code_top", "member_indices", "member_ID", "if_member_targeted", "if_hidden_member", "variable_code", "member_code", "variable_code_ID", "member_code_ID", "variable_code_offset", "member_code_offset", "GetParentScriptInfo", "SpringCleaning" } disassemble := @DisassemblePackage.RunDisAsm