解释型语言的解释过程一般经过下面的步骤
go 语法脚本语言
就是利用 go 源代码种的这些工具,简化了他们的实现难度。下面依次介绍上面的一些步骤,本文旨在一篇文章写清楚大概流程,具体的细节将会忽略,实际的实现也会尽可能的简化,本文主要参考 自己动手实现 lua,和 gopher-lua
这个其实在 goyacc 实战 里面已经给出了不少例子了。这步其实比较简单,重要的时了解 lua 中的 token,lua 语法。bnf 语法参考这里.
stat ::= varlist1 `=´ explist1 | 【赋值语句 AssignStmt{Lhs, Rhs Exprs}】
functioncall | 【函数调用语句 FuncCallStmt{Expr}】
do block end | 【do 语句,DoBlockStmt{Stmts}】
while exp do block end |【 while 语句, WhileStmt{Expr, Stmts}】
repeat block until exp |【 repeat 语句,RepeatStmt{Expr, Stmts}】
if exp then block {elseif exp then block} [else block] end |【if 语句 IfStmt{Condition Expr, Then, Else Stmts}】
for Name `=´ exp `,´ exp [`,´ exp] do block end |【数值 for 语句】
for namelist in explist1 do block end |【通用 for 语句, GenericForStmt{Names, Exprs, Stmts}】
function funcname funcbody |【函数定义语句 FuncDefStmt{FuncName{Func,Receiver,Method},FunctionExpr{ParList,Stmts}}】
local function Name funcbody |【LocalAssignStmt{Names, Exprs}】
local namelist [`=´ explist1]【LocalAssignStmt{Names, Exprs}】
exp ::= nil | 【NilExpr】
false | 【FalseExpr】
true | 【TrueExpr】
Number | 【ConstExpr】
String | 【StringExpr】
`...´ | 【Comma3Expr】
function | 【FunctionExpr】
prefixexp | 【包括 FuncCallExpr】
tableconstructor | 【TableExpr】
exp binop exp | 【算数/比较表达式 RelationalOpExpr,ArithmeticOpExpr,StringConcatOpExpr】
unop exp 【UnaryMinusOpExpr,UnaryNotOpExpr,UnaryLenOpExpr】
// 《自己动手实现 lua》
type opcode struct {
testFlag byte // operator is a test (next instruction must be a jump)
setAFlag byte // instruction set register A
argBMode byte // B arg mode
argCMode byte // C arg mode
opMode byte // op mode
name string
action func(i Instruction, vm api.LuaVM)
}
/* OpMode */
/* basic instruction format */
const (
IABC = iota // [ B:9 ][ C:9 ][ A:8 ][OP:6]
IABx // [ Bx:18 ][ A:8 ][OP:6]
IAsBx // [ sBx:18 ][ A:8 ][OP:6]
IAx // [ Ax:26 ][OP:6]
)
/* OpArgMask */
const (
OpArgN = iota // argument is not used
OpArgU // argument is used
OpArgR // argument is a register or a jump offset
OpArgK // argument is a constant or register/constant
)
var opcodes = []opcode{
/* T A B C mode name action */
opcode{0, 1, OpArgR, OpArgN, IABC /* */, "MOVE ", move}, // R(A) := R(B)
opcode{0, 1, OpArgK, OpArgN, IABx /* */, "LOADK ", loadK}, // R(A) := Kst(Bx)
opcode{0, 1, OpArgN, OpArgN, IABx /* */, "LOADKX ", loadKx}, // R(A) := Kst(extra arg)
...
}
type LuaStack interface{
Push(value)
Pop() value
Get(index) value
}
__init__
, __call__
, __get__
之类的函数,这类函数有特殊的意义,元函数放在类型的 元表【表有自己元表,其他类型共享元表】里面。比如 __add
函数 用于加法操作,用户可以对 元表进行扩展,达到对 lua 语言进行扩展的目的。lua 中的 meta 方法调用在 内置方法不匹配之后。UpValue[B][RK(C)]
和 UpValue[A][RK(B)] := RK(C)
用于 upvalue 是 table 的情况。// R(A) := R(B)
func move(i Instruction, vm LuaVM) {
a, b, _ := i.ABC()
a += 1
b += 1
vm.Copy(b, a)
}
/*
______________
/ false? jmp |
/ |
while exp do block end <-'
^ \
|___________/
jmp
*/
func cgWhileStat(fi *funcInfo, node *WhileStat) {
pcBeforeExp := fi.pc() // pc
oldRegs := fi.usedRegs // 保存使用的 reg 个数
a, _ := expToOpArg(fi, node.Exp, ARG_REG) // 编译 exp
fi.usedRegs = oldRegs // 恢复
line := lastLineOf(node.Exp)
fi.emitTest(line, a, 0) // 输出测试指令
pcJmpToEnd := fi.emitJmp(line, 0, 0) // jump
fi.enterScope(true) // 进入 scope
cgBlock(fi, node.Block) // 编译 block
fi.closeOpenUpvals(node.Block.LastLine) // 关闭 upvals
fi.emitJmp(node.Block.LastLine, 0, pcBeforeExp-fi.pc()-1) // jump to while 的开头
fi.exitScope(fi.pc()) // 退出 scope
fi.fixSbx(pcJmpToEnd, fi.pc()-pcJmpToEnd) // fix jump
}
type luaStack struct {
/* virtual stack 值结构 */
slots []luaValue
top int
/* call info 增加调用信息 */
closure *closure
varargs []luaValue
pc int
/* linked list 调用栈的体现 */
prev *luaStack
}
// callLuaClosure 简化流程
1. funcAndArgs := oldStack.pop(nArgs+1)
2. newStack.pushN(funcAndArgs[1:], nParams)
3. self.pushLuaStack(newStack)
4. self.runLuaClosure(newStack)
5. self.popLuaStack()
6. results := newStack.popN(newStack.pop - nRegs)
7. self.stack.pushN(results, nResults)
func (self *luaState) runLuaClosure() {
for {
inst := vm.Instruction(self.Fetch())
inst.Execute(self)
if inst.Opcode() == vm.OP_RETURN {
break
}
}
}
以上是实现 lua 虚拟机的主要步骤,主体完成之后还可以对表达式做优化、增加标准库、支持更多寄生语言已经支持的特性等等。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。