mirror of https://github.com/CPunch/LuaDecompy.git
lp: support FORPREP && FORLOOP
This commit is contained in:
parent
5d91dbbc64
commit
9da0d0ffbd
58
README.md
58
README.md
|
@ -12,47 +12,51 @@ Lua has a relatively small instruction set (only 38 different opcodes!). This ma
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
> cat example.lua && luac5.1 -o example.luac example.lua
|
> cat example.lua && luac5.1 -o example.luac example.lua
|
||||||
local i, x = 10, 2
|
local total = 0
|
||||||
|
|
||||||
repeat
|
for i = 0, 9, 1 do
|
||||||
print(i + x)
|
total = total + i
|
||||||
i = i - 1
|
print(total)
|
||||||
until i < 0
|
end
|
||||||
> python main.py example.luac
|
> python main.py example.luac
|
||||||
example.luac
|
example.luac
|
||||||
|
|
||||||
==== [[example.lua's constants]] ====
|
==== [[example.lua's constants]] ====
|
||||||
|
|
||||||
0: [NUMBER] 10.0
|
0: [NUMBER] 0.0
|
||||||
1: [NUMBER] 2.0
|
1: [NUMBER] 9.0
|
||||||
2: [STRING] print
|
2: [NUMBER] 1.0
|
||||||
3: [NUMBER] 1.0
|
3: [STRING] print
|
||||||
4: [NUMBER] 0.0
|
|
||||||
|
|
||||||
==== [[example.lua's locals]] ====
|
==== [[example.lua's locals]] ====
|
||||||
|
|
||||||
R[0]: i
|
R[0]: total
|
||||||
R[1]: x
|
R[1]: (for index)
|
||||||
|
R[2]: (for limit)
|
||||||
|
R[3]: (for step)
|
||||||
|
R[4]: i
|
||||||
|
|
||||||
==== [[example.lua's dissassembly]] ====
|
==== [[example.lua's dissassembly]] ====
|
||||||
|
|
||||||
[ 0] LOADK : R[0] K[0] ; load 10.0 into R[0]
|
[ 0] LOADK : R[0] K[0] ; load 0.0 into R[0]
|
||||||
[ 1] LOADK : R[1] K[1] ; load 2.0 into R[1]
|
[ 1] LOADK : R[1] K[0] ; load 0.0 into R[1]
|
||||||
[ 2] GETGLOBAL : R[2] K[2] ; move _G["print"] into R[2]
|
[ 2] LOADK : R[2] K[1] ; load 9.0 into R[2]
|
||||||
[ 3] ADD : R[3] R[0] R[1] ; add R[1] to R[0], place into R[3]
|
[ 3] LOADK : R[3] K[2] ; load 1.0 into R[3]
|
||||||
[ 4] CALL : 2 2 1 ;
|
[ 4] FORPREP : R[1] 4 ;
|
||||||
[ 5] SUB : R[0] R[0] K[3] ; sub K[3] from R[0], place into R[0]
|
[ 5] ADD : R[0] R[0] R[4] ; add R[4] to R[0], place into R[0]
|
||||||
[ 6] LT : R[0] R[0] K[4] ;
|
[ 6] GETGLOBAL : R[5] K[3] ; move _G["print"] into R[5]
|
||||||
[ 7] JMP : R[0] -6 ;
|
[ 7] MOVE : 6 0 0 ; move R[0] into R[6]
|
||||||
[ 8] RETURN : 0 1 0 ;
|
[ 8] CALL : 5 2 1 ;
|
||||||
|
[ 9] FORLOOP : R[1] -5 ;
|
||||||
|
[ 10] RETURN : 0 1 0 ;
|
||||||
|
|
||||||
==== [[example.lua's decompiled source]] ====
|
==== [[example.lua's decompiled source]] ====
|
||||||
|
|
||||||
local i = 10.0
|
local total = 0.0
|
||||||
local x = 2.0
|
for i = 0.0, 9.0, 1.0 do
|
||||||
repeat
|
total = (total + i)
|
||||||
print((i + x))
|
print(total)
|
||||||
i = (i - 1.0)
|
end
|
||||||
until i < 0.0
|
|
||||||
|
|
||||||
```
|
```
|
23
lparser.py
23
lparser.py
|
@ -29,6 +29,13 @@ class _Line:
|
||||||
self.src = src
|
self.src = src
|
||||||
self.scope = scope
|
self.scope = scope
|
||||||
|
|
||||||
|
def isValidLocal(ident: str) -> bool:
|
||||||
|
for c in ident:
|
||||||
|
if c not in "abcdefghijklmnopqrstuvwxyz1234567890_":
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
class LuaDecomp:
|
class LuaDecomp:
|
||||||
def __init__(self, chunk: Chunk):
|
def __init__(self, chunk: Chunk):
|
||||||
self.chunk = chunk
|
self.chunk = chunk
|
||||||
|
@ -124,11 +131,16 @@ class LuaDecomp:
|
||||||
|
|
||||||
def __loadLocals(self):
|
def __loadLocals(self):
|
||||||
for i in range(len(self.chunk.locals)):
|
for i in range(len(self.chunk.locals)):
|
||||||
if not self.chunk.locals[i].name == "":
|
name = self.chunk.locals[i].name
|
||||||
self.locals[i] = self.chunk.locals[i].name
|
if isValidLocal(name):
|
||||||
else:
|
self.locals[i] = name
|
||||||
|
elif "(for " not in name: # if it's a for loop register, ignore
|
||||||
self.__makeLocalIdentifier(i)
|
self.__makeLocalIdentifier(i)
|
||||||
|
|
||||||
|
# when you *know* the register *has* to be a local (for loops, etc.)
|
||||||
|
def __getLocal(self, indx: int) -> str:
|
||||||
|
return self.locals[indx] if indx in self.locals else self.__makeLocalIdentifier(indx)
|
||||||
|
|
||||||
def __getReg(self, indx: int) -> str:
|
def __getReg(self, indx: int) -> str:
|
||||||
self.__addUseTraceback(indx)
|
self.__addUseTraceback(indx)
|
||||||
|
|
||||||
|
@ -336,5 +348,10 @@ class LuaDecomp:
|
||||||
elif instr.opcode == Opcodes.RETURN:
|
elif instr.opcode == Opcodes.RETURN:
|
||||||
self.__endStatement()
|
self.__endStatement()
|
||||||
pass # no-op for now
|
pass # no-op for now
|
||||||
|
elif instr.opcode == Opcodes.FORLOOP:
|
||||||
|
pass # no-op for now
|
||||||
|
elif instr.opcode == Opcodes.FORPREP:
|
||||||
|
self.__addExpr("for %s = %s, %s, %s " % (self.__getLocal(instr.A+3), self.__getReg(instr.A), self.__getReg(instr.A + 1), self.__getReg(instr.A + 2)))
|
||||||
|
self.__startScope("do", self.pc, instr.B)
|
||||||
else:
|
else:
|
||||||
raise Exception("unsupported instruction: %s" % instr.toString())
|
raise Exception("unsupported instruction: %s" % instr.toString())
|
|
@ -400,7 +400,7 @@ class LuaUndump:
|
||||||
# locals
|
# locals
|
||||||
num = self.get_int()
|
num = self.get_int()
|
||||||
for i in range(num):
|
for i in range(num):
|
||||||
name = self.get_string(None) # local name
|
name = self.get_string(None)[:-1] # local name ([:-1] to remove the NULL terminator)
|
||||||
start = self.get_int() # local start PC
|
start = self.get_int() # local start PC
|
||||||
end = self.get_int() # local end PC
|
end = self.get_int() # local end PC
|
||||||
chunk.appendLocal(Local(name, start, end))
|
chunk.appendLocal(Local(name, start, end))
|
||||||
|
|
Loading…
Reference in New Issue