hugh 的个人博客

Everyday is a new day

支持If语句- 一步步实现JS语言编译执行

上几节中,还都是对语句的解析执行, 本节加入if语句的支持,同时引入二义性的概念

目标
支持If语句

了解If语句

一般我们的if语句是这样的

 if(a >2) {
    a = 3;
   }else {
    a=4;
   }

if关键字 + 判断表达式 + 语句块
对应的文法:

if ( Expression ) Statement else Statement (文法语句1)
if ( Expression ) Statement  (文法语句2)

我们来看下下面几个if语句

if(a >2) 
    if(a<4)
     a=3;
else 
   a=4;

该语句解析成ast应该是什么样的?

  1. 解法一
  2. 解法二

文法二义性, 即只我们根据这个文法可以得到两颗不同的语法树。 如果我们先匹配文法语句2, 即上面的解法一、二

高级语言中通常都是else和最近的一个if匹配, 我们的实现也将基于此!

如何实现

前置条件

  1. if语句块有个test部分,返回一个boolean类型的值, 所以我们至少需要支持关系表达式的计算了(这部分和前几节一致,不展开)
  2. if 和 else本身会更一个代码块block, 所以语句块的解析需要支持
/**
     * v0.0.4
     *
     * 代码块 以{开始, 以}结束
     * Block :
     *   { StatementList(opt) }
     *
     */
    block() {
        let node = null;
        let nextToken = this.lexerLevel.tokenPeek()
        if(nextToken && nextToken.type === this.lexerLevel.DfaState.LeftBrace) {
            node = new BlockAstNode("Block", "")
            this.lexerLevel.tokenRead();
            nextToken = this.lexerLevel.tokenPeek()
            // todo 异常判断
            while(nextToken && nextToken.type !== this.lexerLevel.DfaState.RightBrace){
                let child = this.statement();
                if(child) {
                    // 构建子级ast
                    node.addChild(child)
                }
                nextToken = this.lexerLevel.tokenPeek()
            }
            if(nextToken && nextToken.type === this.lexerLevel.DfaState.RightBrace) {
                this.lexerLevel.tokenRead();
            }
        }

        return node
    }

实现if语句

/**
     * v0.0.4
     * 
     * 语法如下
     * IfStatement :
     *     if ( Expression ) Statement else Statement 
     *     if ( Expression ) Statement
     *
     */
    ifStatement() {
        let node = null;
        
        let nextToken = this.lexerLevel.tokenPeek()
        // 预判进入If语句
        if(nextToken && nextToken.type === this.lexerLevel.DfaState.If) {
            this.lexerLevel.tokenRead();
            // 构建一个if Ast
            node = new IfStatementAstNode('ifStatement', 'if')
            nextToken = this.lexerLevel.tokenPeek()
            if(nextToken && nextToken.type === this.lexerLevel.DfaState.LeftParen) {
                this.lexerLevel.tokenRead();
                // test语句检查 TODO 暂时使用该 Expression
                let childTest = this.relational();
                if(childTest) {
                    node.addTest(childTest)
                    // 判断 )
                    nextToken = this.lexerLevel.tokenPeek()
                    if(nextToken && nextToken.type === this.lexerLevel.DfaState.RightParen) {
                        this.lexerLevel.tokenRead();
                        // 开始进入 statement区域判断
                        let child1 = this.statement();
                        if(child1) {
                            node.addConsequent(child1)
                        }else {
                            throw Error("lost consequent block in if statement")
                        }
                        // 判断else语句
                        nextToken = this.lexerLevel.tokenPeek()
                        if(nextToken && nextToken.type === this.lexerLevel.DfaState.Else) {
                            this.lexerLevel.tokenRead();
                            // 构建一个else代码块
                            let child2 = this.statement();
                            if(child2) {
                                node.addAlternate(child2)
                            }else {
                                throw Error("lost alternate block in if statement")
                            }
                        }
                    } else {
                        throw Error("lost rightParen in if test")
                    }
                } else {
                    throw Error("lost test expression in if statement")
                }

            } else {
                throw Error("lost leftParen in if test")
            }
        }
        return node;
    }

执行计算

if语句的计算比较简单, 我们只需要对语句块的test部分判断Boolean值,true则走if块, false走else块即可

 getValue(){
        // console.log("=====if value", this.test.getValue())
        let testVal = !!(this.test.getValue()) // 转换成boolean
        if(testVal) {
           return this.consequent.getValue();
        } else if(this.alternate) {
            return this.alternate.getValue();
        }
    }

测试

  1. 简单if语句
let syntaxLevel = new SyntaxLevel1(`
   if(a >2) {
    a = 3;
   }
   `)
   console.log("test1----", syntaxLevel.astParse())

结果:

AstNode {
  type: 'Program',
  value: '',
  children: 
   [ IfStatementAstNode {
       type: 'ifStatement',
       value: 'if',
       children: [Array],
       parent: [Circular],
       test: [BinaryAstNode],
       consequent: [BlockAstNode],
       alternate: null } ],
  parent: null }
  1. 测试if else
 let syntaxLevel2 = new SyntaxLevel1(`
   if(a >2) {
    a = 3;
   }else {
    a=4;
   }
   `)
    console.log("test2----", syntaxLevel2.astParse())

结果:

AstNode {
  type: 'Program',
  value: '',
  children: 
   [ IfStatementAstNode {
       type: 'ifStatement',
       value: 'if',
       children: [Array],
       parent: [Circular],
       test: [BinaryAstNode],
       consequent: [BlockAstNode],
       alternate: [BlockAstNode] } ],
  parent: null }
  1. 测试上述有二义性的语句
 let syntaxLevel3 = new SyntaxLevel1(`
   if(a >2) 
    if(a<4)
     a=3;
   else 
    a=4;
   
   `)
    console.log("test3----", syntaxLevel3.astParse())

结果:

AstNode {
  type: 'Program',
  value: '',
  children: 
   [ IfStatementAstNode {
       type: 'ifStatement',
       value: 'if',
       children: [Array],
       parent: [Circular],
       test: [BinaryAstNode],
       consequent: [IfStatementAstNode],
       alternate: null } ],
  parent: null }
  1. 测试运算
// 测试运行计算
    let syntaxLevel4 = new SyntaxLevel1(`
   var a = 5;
   if(a >2) 
    if(a<4)
     a=3;
   else 
    a=4;
   
   a= a+1;
   `)
    console.log("test4----", syntaxLevel4.exe())

结果
5


标题:支持If语句- 一步步实现JS语言编译执行
作者:hugh0524
地址:https://blog.uproject.cn/articles/2020/02/27/1582816225074.html

0 浏览