Lua基本语法
前言:推荐一个工具Luadec,此工具有个功能可以反编译Lua代码生成Lua字节码,这篇博客使用了-dis 命令。
D:\luadec>luadec.exe luadec.exe: no input files given LuaDec by Hisham Muhammad Ongoing port to Lua 5.1 by Zsolt Sz. Sztupak (http://winmo.sztupy.hu) usage: luadec.exe [options] [filename]. Available options are: - process stdin -d output information for debugging the decompiler -dis don't decompile, just disassemble -f num decompile only num-th function (0=main block) -l LDS declare locals as defined by LDS -l2 LDS2 declare locals as defined by LDS2 -dg disable built-in local guessing -pg don't run just print out the LDS2 string used -a always declare all register as locals -- stop handling options
1.赋值语句
Lua有一个奇葩的赋值方式,先把值读入寄存器,再赋值给变量,这使得 a,b=b,a;这种脚本可以交换a和b 的值。我们看下下面的代码:
a=10; b=5; a,b=b,a; print(a); print(b); x,y= 0; print(x); print(y); --[[ D:\luadec>luadec.exe -dis test_exec.lua ; This file has been disassembled using luadec 2.0 standard by sztupy (http://l adec51.luaforge.net) ; Command line was: -dis test_exec.lua ; Name: ; Defined at line: 0 ; #Upvalues: 0 ; #Parameters: 0 ; Is_vararg: 2 ; Max Stack Size: 2 1 [-]: LOADK R0 K1 ; R0 := 10 2 [-]: SETGLOBAL R0 K0 ; a := R0 3 [-]: LOADK R0 K3 ; R0 := 5 4 [-]: SETGLOBAL R0 K2 ; b := R0 5 [-]: GETGLOBAL R0 K2 ; R0 := b 6 [-]: GETGLOBAL R1 K0 ; R1 := a 7 [-]: SETGLOBAL R1 K2 ; b := R1 8 [-]: SETGLOBAL R0 K0 ; a := R0 9 [-]: GETGLOBAL R0 K4 ; R0 := print 10 [-]: GETGLOBAL R1 K0 ; R1 := a 11 [-]: CALL R0 2 1 ; R0(R1) 12 [-]: GETGLOBAL R0 K4 ; R0 := print 13 [-]: GETGLOBAL R1 K2 ; R1 := b 14 [-]: CALL R0 2 1 ; R0(R1) 15 [-]: RETURN R0 1 ; return ]]--
注释中是lua生成的字节码,从字节码的1~2行可以看出:给a赋值的操作,是通过一个R0的存储区来操作的,可能是一个寄存器,也可能是其他的,5~8行字节码可以看出,a和b的值,分别赋值给了R1和R0,然后R1和R0再分别赋值给b和a,以达到交换的目的。
2.Local变量
这个比较好理解,java代码中有int a;这种定义语句,但是lua中不需要,这就导致一个问题,代码块中,如何申明一个临时变量呢?lua是通过local这个关键字来做的。
i=20; x=10; if i < 20 then local x = 5; print(x) end if i < 20 then x = 5; print(x) end --[[ D:\luadec>luadec.exe -dis test_local.lua ; This file has been disassembled using luadec 2.0 standard by sztupy (http://lu adec51.luaforge.net) ; Command line was: -dis test_local.lua ; Name: ; Defined at line: 0 ; #Upvalues: 0 ; #Parameters: 0 ; Is_vararg: 2 ; Max Stack Size: 3 1 [-]: LOADK R0 K1 ; R0 := 20 2 [-]: SETGLOBAL R0 K0 ; i := R0 3 [-]: LOADK R0 K3 ; R0 := 10 4 [-]: SETGLOBAL R0 K2 ; x := R0 5 [-]: GETGLOBAL R0 K0 ; R0 := i 6 [-]: LT 0 R0 K1 ; if R0 >= 20 then PC := 12 7 [-]: JMP 12 ; PC := 12 8 [-]: LOADK R0 K4 ; R0 := 5 9 [-]: GETGLOBAL R1 K5 ; R1 := print 10 [-]: MOVE R2 R0 ; R2 := R0 11 [-]: CALL R1 2 1 ; R1(R2) 12 [-]: GETGLOBAL R0 K0 ; R0 := i 13 [-]: LT 0 R0 K1 ; if R0 >= 20 then PC := 20 14 [-]: JMP 20 ; PC := 20 15 [-]: LOADK R0 K4 ; R0 := 5 16 [-]: SETGLOBAL R0 K2 ; x := R0 17 [-]: GETGLOBAL R0 K5 ; R0 := print 18 [-]: GETGLOBAL R1 K2 ; R1 := x 19 [-]: CALL R0 2 1 ; R0(R1) 20 [-]: RETURN R0 1 ; return ]]--
可以在字节码第8行和16行的区别看出,8行local语句使编译器选择了一个新的临时变量,而在16行则使用了SETGLOBAL语句。不过这个和C语言系列的没啥区别,不算是陷阱。