从零开始实现 Lua 解释器之语法分析2

警告⚠️:这将是一个又臭又长的数不胜数教程,教程结束之时段,你以有所一个除了性能差劲、扩展性差、标准库不完美之外,其他方都跟官方相差无几的
Lua
语言解释器。说白了,这个系列之课实现的凡一个玩具语言,仅供就学,无实用性。请小心
Follow,请小心 Follow,请谨慎 Follow。

就是比照系列教程的第六篇,如果您无扣了之前的稿子,请从头观看。

前言

语法分析算是 SLua
解释器中相对复杂的一个模块了,为了避免篇幅过长,我们以分为基本上篇来教学,本文是第二有的。

及一致节省说到了 parseStatement 的贯彻,现在我们便来分析一下 SLua
中究竟发生几乎种植档次的 Statement:

  • Do Statament,这个讲话的意向是以一个 Block
    封装成一个独门的语句。类似于 C
    语言中拿同样段子代码放在同等针对大括哀号被,主要用于控制局部变量的作用域。
  • While Statement
  • If Statement
  • Local Statement,局部变量声明语句。
  • Other Statement,全局变量声明和变量赋值语句,没错,SLua
    中之全局变量声明语句和变量赋值语句之样式是同等的。

解析 Do Statement

Do Statement 的解析代码如下:

func (p *Parser) parseDoStatement() syntax.SyntaxTree {
    p.nextToken()
    assert(p.currentToken.Category == scanner.TokenDo, "not a do statement")
    block := p.parseBlock()
    if p.nextToken().Category != scanner.TokenEnd {
        panic(&Error{
            module: p.module,
            token:  p.currentToken,
            str:    "expect 'end' for 'do' statement",
        })
    }
    return &syntax.DoStatement{Block: block}
}

第一,我们运用 assert 函数来保证当前 Token 的档次为 TokenDo;然后调用
parseBlock 函数来分析 Do Statement 内部的
Block;紧接着,在解析完成后,我们检查下一个 Token 的门类是否也
TokenEnd,如果非是,则抛来荒谬。

安,很简单吧。其他的言辞的解析为跟这个近乎,就比如流水线一样,一步接一步,直到解析完成,将诸组成部分的结果组装起,得到我们要之事物。

解析 While Statement

于条分缕析之前,我们事先来拘禁一下之前以介绍抽象语法树时涉嫌了之 WhileStatement
的概念:

type WhileStatement struct {
    Exp   SyntaxTree
    Block SyntaxTree
}

好看来,While Statement 包含两有的,Exp
为用于判断循环是否延续的表达式,Block 则是循环体。解析代码如下:

func (p *Parser) parseWhileStatement() syntax.SyntaxTree {
    p.nextToken()
    assert(p.currentToken.Category == scanner.TokenWhile,
        "not a while statement")
    exp := p.parseExp()
    if p.nextToken().Category != scanner.TokenDo {
        panic(&Error{
            module: p.module,
            token:  p.currentToken,
            str:    "expect 'do' for 'while' statement",
        })
    }
    block := p.parseBlock()
    if p.nextToken().Category != scanner.TokenEnd {
        panic(&Error{
            module: p.module,
            token:  p.currentToken,
            str:    "expect 'end' for 'while' statement",
        })
    }
    return &syntax.WhileStatement {
        Exp:   exp,
        Block: block,
    }
}

第一,与析 Do Statement 相同,首先我们通过调用 assert 保证当前 Token
的种也 TokenWhile;然后调用 parseExp 解析紧接着 TokenWhile
后面的循环表达式;正常情况下,表达式后面会就
TokenDo,所以,如果无是的话,我们尽管需要报告语法错误然后退出程序;紧跟以
TokenDo 之后的凡一个开为函数体的 Block,我们调用之前定义好的 parseBlock
函数来分析其;最后,我们用判定紧跟以 Block 之后的是否为
TokenEnd,如果不是,则需报语法错误。

parseExp
函数的实现是一体语法分析最复杂的片段,我会在背后的稿子中详尽地执教它,目前独自待理解她用来解析表达式就执行了。

解析 If Statement

对待于地方介绍的 Do Statement 和 While Statement,If Statement
的布局较复杂,它可涵盖零交大半只 Elseif 分支和零或一个 Else
分支,所以将通解析过程在一个函数中确会大大加复杂度,所以我们拿分析函数拆分成了差不多单函数。

我们在季篇稿子中介绍过 If
Statement 的组织:

IfStatement AST

出于达到图可以见到,If Statement 包含三独组成部分:Exp、True Branch、False
Branch,其中 True Branch 为表达式求值为实在时候实施之 Block,而
FalseBranch 可以是 Elseif Statement 或 Else Statement 或 nil。Elseif
Statement 的组成及 If Statement 相同,Else Statement 则仅含一个
Block。

下先来拘禁一下 If Statement 的落实:

func (p *Parser) parseIfStatement() syntax.SyntaxTree {
    p.nextToken()
    assert(p.currentToken.Category == scanner.TokenIf, "not a if statement")
    exp := p.parseExp()
    if p.nextToken().Category != scanner.TokenThen {
        panic(&Error{
            module: p.module,
            token:  p.currentToken,
            str:    "expect 'then' for 'if' statement",
        })
    }
    trueBranch := p.parseBlock()
    falseBranch := p.parseFalseBranchStatement()
    return &syntax.IfStatement{
        Exp:         exp,
        TrueBranch:  trueBranch,
        FalseBranch: falseBranch,
    }
}

第一,自然是判时底 Token 类型是否为 TokenIf;然后调用 parseExp
解析紧随其后的表达式;然后判断下一个 Token 的种类是否也
TokenThen,如果未是,则告诉语法错误;然后我们调用 parseBlock 来分析 True
Branch,调用 parseFalseBranchStatement 解析 False Branch。

方说过,False Branch 有三种情景,容易想到,parseFalseBranchStatement
方法会根据下一个 Token 的类是 TokenElseif、TokenElse 还是 TokenEnd
来执行不同的动作,下面就来拘禁一下有血有肉的兑现:

func (p *Parser) parseFalseBranchStatement() syntax.SyntaxTree {
    if p.lookAhead().Category == scanner.TokenElseif {
        return p.parseElseifStatement()
    } else if p.lookAhead().Category == scanner.TokenElse {
        return p.parseElseStatement()
    } else if p.lookAhead().Category == scanner.TokenEnd {
        p.nextToken()
    } else {
        panic(&Error{
            module: p.module,
            token:  p.lookAheadToken,
            str:    "expect 'end' for 'if' statement",
        })
    }
    return nil
}

parseFalseBranchStatement 方法的实现好易理解,这里就不再详细分解了。因为
Elseif Statement 与 If Statement
的花样完全相同,所以解析其的不二法门的兑现啊基本相同,而 Else Statement
则只是简单地调用一个 parseBlocC语言k
方法就是足以了,也不再细说,这简单独艺术的落实以底下:

func (p *Parser) parseElseifStatement() syntax.SyntaxTree {
    p.nextToken()
    assert(p.currentToken.Category == scanner.TokenElseif,
        "not a 'elseif' statement")
    exp := p.parseExp()
    if p.nextToken().Category != scanner.TokenThen {
        panic(&Error{
            module: p.module,
            token:  p.currentToken,
            str:    "expect 'then' for 'elseif' statement",
        })
    }
    trueBranch := p.parseBlock()
    falseBranch := p.parseFalseBranchStatement()
    return &syntax.ElseifStatement{
        Exp:         exp,
        TrueBranch:  trueBranch,
        FalseBranch: falseBranch,
    }
}

func (p *Parser) parseElseStatement() syntax.SyntaxTree {
    p.nextToken()
    assert(p.currentToken.Category == scanner.TokenElse,
        "not a 'else' statement")
    block := p.parseBlock()
    if p.nextToken().Category != scanner.TokenEnd {
        panic(&Error{
            module: p.module,
            token:  p.currentToken,
            str:    "expect 'end' for 'else' statement",
        })
    }
    return &syntax.ElseStatement{Block: block}
}

本节即使先说到这边,在生一样节中,我们将继承教授解析 Local Statement 和
Other Statement 的道实现。

得到源代码


代码已经托管到 GitHub
上:SLua,每一个等级的代码我都见面创一个
release,你可直接下充斥作为参考。虽然提供了自代码,但并无建议直接复制粘贴,因为这样效仿到之知识会很易忘。

若是你看就篇教程有帮扶,请不要吝啬给文章点个爱慕,我会更加有动力将是系列写下来。关注一下简书和
GitHub 可以以第一时间获得创新提醒哦。