lua 编译器

lua 编译器

一、看看最简单的语句,lua是怎么编译的

lua和jvm不一样,采用的基于寄存器的虚拟机,jvm采用的基于栈的虚拟机。

1、LOADK,ADD,GETGLOBAL

可以直接查看lua文件的编译结果: luac -l -l test1.lua
也可以先编译,后查看: luac -o test1.luac test1.lua 
                     luac -l -l test1.luac

LOADK               0 -2  表示把常量表中的-2位置的常量放到寄存器0中。
GETGLOBAL       1 -3  表示把常量表中的-3位置的常量名称定义的全局变量的值,放到寄存器1中。
ADD                 0 0 1  表示把寄存器0和1加起来,放到0号位置
params表示入参个数 +表示有可变长度的参数
slots表示需要用多少个寄存器

test1.lua 文件内容
a=3
b=2
c=a+b

E:\Program Files\Lua\lua5.1\gf\2021.3.20>..\..\luac -l -l test1.lua
main <test1.lua:0,0> (9 instructions, 36 bytes at 00851A40)
0+ params, 2 slots, 0 upvalues, 0 locals, 5 constants, 0 functions
        1       [1]     LOADK           0 -2    ; 3
        2       [1]     SETGLOBAL       0 -1    ; a
        3       [2]     LOADK           0 -4    ; 2
        4       [2]     SETGLOBAL       0 -3    ; b
        5       [3]     GETGLOBAL       0 -1    ; a
        6       [3]     GETGLOBAL       1 -3    ; b
        7       [3]     ADD             0 0 1
        8       [3]     SETGLOBAL       0 -5    ; c
        9       [3]     RETURN          0 1
constants (5) for 00851A40:
        1       "a"
        2       3
        3       "b"
        4       2
        5       "c"
locals (0) for 00851A40:
upvalues (0) for 00851A40:

2、RETURN

下面的return指令比较特别
RETURN          2 4 表示返回 r[2],r[3], ... r[2+4-2] 
RETURN          0 1 表示返回  r[0+1-2] = r[-1] 即不返回
系统默认会加一个return 0 1语句。我们如果写了return,则会发现共有两个return语句。

test2.lua 文件内容
a=3
b=2
c=a+b
c=c+9
return a,b,c

E:\Program Files\Lua\lua5.1\gf\2021.3.20>..\..\luac -l -l test2.lua
main <test2.lua:0,0> (16 instructions, 64 bytes at 008D1A40)
0+ params, 3 slots, 0 upvalues, 0 locals, 6 constants, 0 functions
        1       [1]     LOADK           0 -2    ; 3
        2       [1]     SETGLOBAL       0 -1    ; a
        3       [2]     LOADK           0 -4    ; 2
        4       [2]     SETGLOBAL       0 -3    ; b
        5       [3]     GETGLOBAL       0 -1    ; a
        6       [3]     GETGLOBAL       1 -3    ; b
        7       [3]     ADD             0 0 1
        8       [3]     SETGLOBAL       0 -5    ; c
        9       [4]     GETGLOBAL       0 -5    ; c
        10      [4]     ADD             0 0 -6  ; - 9
        11      [4]     SETGLOBAL       0 -5    ; c
        12      [5]     GETGLOBAL       0 -1    ; a
        13      [5]     GETGLOBAL       1 -3    ; b
        14      [5]     GETGLOBAL       2 -5    ; c
        15      [5]     RETURN          0 4
        16      [5]     RETURN          0 1
constants (6) for 008D1A40:
        1       "a"
        2       3
        3       "b"
        4       2
        5       "c"
        6       9
locals (0) for 008D1A40:
upvalues (0) for 008D1A40:

3、CALL

CALL   0 3 2 表示从寄存器0开始,0,1,...(0+3-1)  是输入参数;寄存器0开始,0,1,...(0+2-1)  是输出参数
test3.lua的文件内容
function add(x,y)
  return x+y
end

a=3
b=2
c=a+b
c=add(a,c)
return a,b,c

E:\Program Files\Lua\lua5.1\gf\2021.3.20>..\..\luac -l -l test3.lua
main <test3.lua:0,0> (20 instructions, 80 bytes at 001E1A40)
0+ params, 3 slots, 0 upvalues, 0 locals, 6 constants, 1 function
        1       [3]     CLOSURE         0 0     ; 001E8688
        2       [1]     SETGLOBAL       0 -1    ; add
        3       [5]     LOADK           0 -3    ; 3
        4       [5]     SETGLOBAL       0 -2    ; a
        5       [6]     LOADK           0 -5    ; 2
        6       [6]     SETGLOBAL       0 -4    ; b
        7       [7]     GETGLOBAL       0 -2    ; a
        8       [7]     GETGLOBAL       1 -4    ; b
        9       [7]     ADD             0 0 1
        10      [7]     SETGLOBAL       0 -6    ; c
        11      [8]     GETGLOBAL       0 -1    ; add
        12      [8]     GETGLOBAL       1 -2    ; a
        13      [8]     GETGLOBAL       2 -6    ; c
        14      [8]     CALL            0 3 2
        15      [8]     SETGLOBAL       0 -6    ; c
        16      [9]     GETGLOBAL       0 -2    ; a
        17      [9]     GETGLOBAL       1 -4    ; b
        18      [9]     GETGLOBAL       2 -6    ; c
        19      [9]     RETURN          0 4
        20      [9]     RETURN          0 1
constants (6) for 001E1A40:
        1       "add"
        2       "a"
        3       3
        4       "b"
        5       2
        6       "c"
locals (0) for 001E1A40:
upvalues (0) for 001E1A40:

function <test3.lua:1,3> (3 instructions, 12 bytes at 001E8688)
2 params, 3 slots, 0 upvalues, 2 locals, 0 constants, 0 functions
        1       [2]     ADD             2 0 1
        2       [2]     RETURN          2 2
        3       [3]     RETURN          0 1
constants (0) for 001E8688:
locals (2) for 001E8688:
        0       x       1       3
        1       y       1       3
upvalues (0) for 001E8688:

注意观察,现在的输出分为两大段,main函数和add函数,每个都有自己的代码,常量表,本地变量,upvalues表

再看一个例子

test3.lua的文件内容:
function add1(x,y)
  return x+y
end

function add2(x,y,z)
  return z+y
end

a=3
b=2
c=add1(a,b)
c=add2(a,b,c)

E:\Program Files\Lua\lua5.1\gf\2021.3.20>..\..\luac -l -l test3.lua
main <test3.lua:0,0> (20 instructions, 80 bytes at 007E1A40)
0+ params, 4 slots, 0 upvalues, 0 locals, 7 constants, 2 functions
        1       [3]     CLOSURE         0 0     ; 007E8688
        2       [1]     SETGLOBAL       0 -1    ; add1
        3       [7]     CLOSURE         0 1     ; 007E88F0
        4       [5]     SETGLOBAL       0 -2    ; add2
        5       [9]     LOADK           0 -4    ; 3
        6       [9]     SETGLOBAL       0 -3    ; a
        7       [10]    LOADK           0 -6    ; 2
        8       [10]    SETGLOBAL       0 -5    ; b
        9       [11]    GETGLOBAL       0 -1    ; add1
        10      [11]    GETGLOBAL       1 -3    ; a
        11      [11]    GETGLOBAL       2 -5    ; b
        12      [11]    CALL            0 3 2
        13      [11]    SETGLOBAL       0 -7    ; c
        14      [12]    GETGLOBAL       0 -2    ; add2
        15      [12]    GETGLOBAL       1 -3    ; a
        16      [12]    GETGLOBAL       2 -5    ; b
        17      [12]    GETGLOBAL       3 -7    ; c
        18      [12]    CALL            0 4 2
        19      [12]    SETGLOBAL       0 -7    ; c
        20      [12]    RETURN          0 1
constants (7) for 007E1A40:
        1       "add1"
        2       "add2"
        3       "a"
        4       3
        5       "b"
        6       2
        7       "c"
locals (0) for 007E1A40:
upvalues (0) for 007E1A40:

function <test3.lua:1,3> (3 instructions, 12 bytes at 007E8688)
2 params, 3 slots, 0 upvalues, 2 locals, 0 constants, 0 functions
        1       [2]     ADD             2 0 1
        2       [2]     RETURN          2 2
        3       [3]     RETURN          0 1
constants (0) for 007E8688:
locals (2) for 007E8688:
        0       x       1       3
        1       y       1       3
upvalues (0) for 007E8688:

function <test3.lua:5,7> (3 instructions, 12 bytes at 007E88F0)
3 params, 4 slots, 0 upvalues, 3 locals, 0 constants, 0 functions
        1       [6]     ADD             3 2 1
        2       [6]     RETURN          3 2
        3       [7]     RETURN          0 1
constants (0) for 007E88F0:
locals (3) for 007E88F0:
        0       x       1       3
        1       y       1       3
        2       z       1       3
upvalues (0) for 007E88F0:
注意CLOSURE语句,还有function中的本地变量次序。add 3 2 1 表示z+y

4、LOADNIL,MOVE

LOADNIL 0 2 初始化寄存器0,1,2
MOVE 5 1 拷贝寄存器1的内容到寄存器5
GETGLOBAL  3 -1 把常量表中-1这个位置的值放到寄存器3中

test4.lua的文件内容
function add1(x,y)
  return x+y
end

function add2(x,y,z)
  return z+y
end

local a,b,c
a=3
b=2
c=add1(a,b)
c=add2(a,b,c)

E:\Program Files\Lua\lua5.1\gf\2021.3.20>..\..\luac -l -l test4.lua
main <test4.lua:0,0> (19 instructions, 76 bytes at 00591A40)
0+ params, 7 slots, 0 upvalues, 3 locals, 4 constants, 2 functions
        1       [3]     CLOSURE         0 0     ; 00598688
        2       [1]     SETGLOBAL       0 -1    ; add1
        3       [7]     CLOSURE         0 1     ; 005988F0
        4       [5]     SETGLOBAL       0 -2    ; add2
        5       [9]     LOADNIL         0 2
        6       [10]    LOADK           0 -3    ; 3
        7       [11]    LOADK           1 -4    ; 2
        8       [12]    GETGLOBAL       3 -1    ; add1
        9       [12]    MOVE            4 0
        10      [12]    MOVE            5 1
        11      [12]    CALL            3 3 2
        12      [12]    MOVE            2 3
        13      [13]    GETGLOBAL       3 -2    ; add2
        14      [13]    MOVE            4 0
        15      [13]    MOVE            5 1
        16      [13]    MOVE            6 2
        17      [13]    CALL            3 4 2
        18      [13]    MOVE            2 3
        19      [13]    RETURN          0 1
constants (4) for 00591A40:
        1       "add1"
        2       "add2"
        3       3
        4       2
locals (3) for 00591A40:
        0       a       6       19
        1       b       6       19
        2       c       6       19
upvalues (0) for 00591A40:

function <test4.lua:1,3> (3 instructions, 12 bytes at 00598688)
2 params, 3 slots, 0 upvalues, 2 locals, 0 constants, 0 functions
        1       [2]     ADD             2 0 1
        2       [2]     RETURN          2 2
        3       [3]     RETURN          0 1
constants (0) for 00598688:
locals (2) for 00598688:
        0       x       1       3
        1       y       1       3
upvalues (0) for 00598688:

function <test4.lua:5,7> (3 instructions, 12 bytes at 005988F0)
3 params, 4 slots, 0 upvalues, 3 locals, 0 constants, 0 functions
        1       [6]     ADD             3 2 1
        2       [6]     RETURN          3 2
        3       [7]     RETURN          0 1
constants (0) for 005988F0:
locals (3) for 005988F0:
        0       x       1       3
        1       y       1       3
        2       z       1       3
upvalues (0) for 005988F0:

二、语法分析

词法分析,输出一个token列表

语法分析,需要构建一个抽象语法树。

代码都是由下面这些语句嵌套组成的,通过识别前几个单词,就能判别出当时是什么语句,从而构建对应的子树。

1、空语句   ;
2、全局变量的赋值语句  varlist '=' explist
3、本地变量的赋值语句  local namelist  ['='  explist] 
4、函数调用  functioncall
5、函数定义  function funcname funcbody
6、本地函数定义 local function funcname funcbody
7、break语句    break
8、do语句  do block end
9、while语句  while exp do block end
10、for name '=' exp ',' exp [',' exp] do block end
11、for namelist in explist do block end

代码示例:
do
  print('ddd')
end

local i=0

while i<3 do
  print('ppp-'..i)
  i=i+1
end

repeat
 print('repeat'..i)
 i=i+1
until i>5

for a=20, 30, 2 do
  print('for-'..a)
end

for a=20, 30, 2 do
  print('for-'..a)
  if a<25 then
     print('<25')
  elseif a<27 then
     print('<27') 
  else
     print('else')
     if a>29 then 
         print('break');
         break
     end
   end
end

--打印数组a的所有值  
a = {"one", "two", "three"}
for i, v in ipairs(a) do
    print(i, v)
end 

local a,b,c=9,7  --a=9,b=7,c=nil
b=nil
print(c)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值