前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自己动手写编译器:实现else语句块的中间代码生成

自己动手写编译器:实现else语句块的中间代码生成

作者头像
望月从良
发布2022-06-21 16:09:50
3950
发布2022-06-21 16:09:50
举报
文章被收录于专栏:Coding迪斯尼Coding迪斯尼

前面几节我们完成了if语句以及判断条件成立时代码对应的中间代码生成,这次我们完成最后一笔,那就是针对else部分代码完成相应的中间代码生成。本质上这一步比较简单,它会在原来if语句中间代码的基础上稍作修改即可,我们先看看这次我们要编译的代码内容:

代码语言:javascript
复制
`{int a; int b; int c; int d;
                int e;
                a = 1;
                b = 2;
                c = 3;
                d = 4;
                if (b == a && c != d) {
                    e = 2;
                } else {
                    e = 3;
                }

    }`

我们在代码中增加了else语句块,我们看看完成本节代码后的执行结果:

从结果看,e=2对应if大括号里面的代码,e=3对应else部分代码,与前面不同的是,编译器在实现if里面代码后,在末尾添加一个goto语句直接越过else部分代码,进入到else之后的代码,从输出看,逻辑应该没有问题。

下面我们看看代码实现,首先为else语句部分增加一个节点,因此添加else.go文件,然后编写代码如下:

代码语言:javascript
复制
package inter

import (
    "errors"
    "strconv"
)

type Else struct {
    stmt  *Stmt
    expr  ExprInterface
    stmt1 StmtInterface
    stmt2 StmtInterface
}

func NewElse(line uint32, expr ExprInterface, stmt1 StmtInterface, stmt2 StmtInterface) *Else {
    if expr.Type().Lexeme != "bool" {
        err := errors.New("bool type required in if")
        panic(err)
    }
    return &Else{
        stmt:  NewStmt(line),
        expr:  expr,
        stmt1: stmt1,
        stmt2: stmt2,
    }
}

func (e *Else) Errors(str string) error {
    return e.stmt.Errors(str)
}

func (e *Else) NewLabel() uint32 {
    return e.stmt.NewLabel()
}

func (e *Else) EmitLabel(i uint32) {
    e.stmt.EmitLabel(i)
}

func (e *Else) Emit(code string) {
    e.stmt.Emit(code)
}

func (e *Else) Gen(_ uint32, end uint32) {
    label1 := e.NewLabel()
    label2 := e.NewLabel()

    e.expr.Jumping(0, label2)
    e.EmitLabel(label1) //生成if条件判断中代码
    e.stmt1.Gen(label1, end) //生成if成立后大括号里面代码的中间代码
    e.Emit("goto L" + strconv.Itoa(int(end))) //增加goto语句跳过else部分代码
    e.EmitLabel(label2) 
    e.stmt2.Gen(label2, end) //生成else里面代码对应中间代码
}

上面代码跟我们前面实现的if节点类似,它的创建需要输入三部分,首先在构造函数中,第一个参数expr对应if里面的条件判断表达式,stmt1对应if成立时大括号里面的语句集合,stmt2对应else部分的语句集合,值得关注的地方在它的gen函数,它首先执行s.xpr.Jumping, e.stmt1.Gen生成条件判断语句和if成立时语句块的中间代码,最重要的是它在if语句块里面的代码完成生成后加入一条goto语句,这个goto语句的作用是越过else部分的代码。很显然当if语句判断成立后,我们执行了if内部代码就肯定不能再执行else部分代码,所以在if内部语句块的后面加上goto越过else部分指令是合理的。

接下来我们看看语法解析部分的修改:

代码语言:javascript
复制
func (s *SimpleParser) stmt() inter.StmtInterface {
    /*
        if "(" bool ")"
        if -> "(" bool ")" ELSE stmt

        bool -> bool "||"" join | join
        join -> join "&&" equality | equality
        equality -> equality "==" rel | equality != rel | rel
        rel -> expr < expr | expr <= expr | expr >= expr | expr > expr | expr
        rel : a > b , a < b, a <= b
        a < b && c > d || e < f
    */
    switch s.cur_tok.Tag {
    case lexer.IF:
        s.move_forward()
        err := s.matchLexeme("(")
        if err != nil {
            panic(err)
        }
        s.move_forward()
        x := s.bool()
        err = s.matchLexeme(")")
        if err != nil {
            panic(err)
        }
        s.move_forward() //越过 )
        s.move_forward() //越过{
        s1 := s.stmt()
        err = s.matchLexeme("}")
        if err != nil {
            panic(err)
        }
        s.move_forward() //越过}

        //判断if 后面是否跟着else
        if s.cur_tok.Tag != lexer.ELSE {
            return inter.NewIf(s.lexer.Line, x, s1)
        } else {
            s.move_forward() //越过else关键字
            err = s.matchLexeme("{")
            if err != nil {
                panic(err)
            }
            s.move_forward() //越过{
            s2 := s.stmt()   //else 里面包含的代码块
            err = s.matchLexeme("}")
            if err != nil {
                panic(err)
            }
            return inter.NewElse(s.lexer.Line, x, s1, s2)
        }

    default:
        return s.expression()
    }

}

在代码中我们增加了对else关键字的解析,我们解析完if部分后,接着判断是否有else关键字跟随其后,如果有我们则对else内部代码调用stmt来进行解析,完成上面代码后运行起来就能得到相应结果。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coding迪斯尼 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档