美文网首页toy_compiler
编译原理——流程控制

编译原理——流程控制

作者: madao756 | 来源:发表于2019-10-22 20:41 被阅读0次

前言:感觉之前的内容写的不好,很散很乱。因为之前强行把文章拆成两个部分:原理和代码实现,不应该这样,应该边写代码,写叙述原理。

0X00 if else 的原理与实现

首先我们得认识到 if else 是一个 statement,而不是一个 expression,借此我们写出 if else 的文法:

statement → exprStmt
          | ifStmt
          | printStmt
          | block ;

ifStmt    → "if" "(" expression ")" statement ( "else" statement )? ;

凭借文法我们写出 if else 的抽象语法树的格式:

static class If extends Stmt {
    If(Expr condition, Stmt thenBranch, Stmt elseBranch) {
        this.condition = condition;
        this.thenBranch = thenBranch;
        this.elseBranch = elseBranch;
    }

    <R> R accept(Visitor<R> visitor) {
        return visitor.visitIfStmt(this);
    }

    final Expr condition;
    final Stmt thenBranch;
    final Stmt elseBranch;
}

我们在 parser 中实现 if else 的抽象语法树的生成:

匹配 IF 关键字:

    private Stmt statement() {
        if (match(PRINT)) {
            return printStatement();
        }
        if (match(LEFT_BRACE)) {
            return new Stmt.Block(block());
        }
        if (match(IF)) {
            return ifStatement();
        }
        if (match(WHILE)) {
            return whileStatement();
        }
        // 将 for 转换成 while
        if (match(FOR)) {
            return forStatement();
        }
        return expressionStatement();
    }

    private Stmt ifStatement() {
        // 生成 ifStatement 的抽象语法树
        // ifStmt → "if" "(" expression ")" statement ( "else" statement )? ;
        consume(LEFT_PAREN, "Expect '(' after 'if'.");
        Expr condition = expression();
        consume(RIGHT_PAREN, "Expect ')' after if condition.");

        Stmt thenBranch = statement();
        Stmt elseBranch = null;

        if (match(ELSE)) {
            elseBranch = statement();
        }
        return new Stmt.If(condition, thenBranch, elseBranch);
    }

接下来我们要在「Interpreter」中执行 if else 的「抽象语法树」

    @Override
    public Void visitIfStmt(Stmt.If stmt) {
        Expr condition = stmt.condition;
        Stmt thenBranch = stmt.thenBranch;
        Stmt elseBranch = stmt.elseBranch;

        if (isTruthy(evaluate(condition))) {
            execute(thenBranch);
        } else {
            execute(elseBranch);
        }
        return null;
    }

在这里出现了一个问题,我们如何判断条件的真假?

A and B 与 A or B,不能把上述两个看做一个「简单的二元表达式」,比如 A or B 只要 A 正确后面的表达式就不用执行了,

所以我们要给逻辑运算定义新的「抽象语法树」格式:

    static class Logical extends Expr {
        Logical(Expr left, Token operator, Expr right) {
            this.left = left;
            this.operator = operator;
            this.right = right;
        }

        <R> R accept(Visitor<R> visitor) {
            return visitor.visitLogicalExpr(this);
        }

        final Expr left;
        final Token operator;
        final Expr right;
    }

我们先写出在逻辑运算的文法:(and 运算符的优先级比 or 高)

expression → assignment ;
assignment → identifier "=" assignment
           | logic_or ;
logic_or   → logic_and ( "or" logic_and )* ;
logic_and  → equality ( "and" equality )* ;

然后在 parser 中,生成逻辑运算的「抽象语法树」:

private Expr assignment() {
    // expression → assignment ;
    // assignment → identifier "=" assignment
    // | logic_or ;
    // logic_or → logic_and ( "or" logic_and )* ;
    // logic_and → equality ( "and" equality )* ;
    // 左值可能需要计算我们先跳过计算左值
    Expr expr = logic_or();

    if (match(EQUAL)) {
        Token equal = previous();
        Expr value = assignment();
        // expr 通过递归,应该得到是一个 Variable,不应该是其他的别的东西
        // 否则报错
        if (expr instanceof Expr.Variable) {
            Token name = ((Expr.Variable) expr).name;
            return new Expr.Assign(name, value);
        }

        error(equal, "Invalid assignment target.");

    }

    return expr;
}   
private Expr logic_and() {
    Expr left = equality();

    while (match(AND)) {
        Token operator = previous();
        Expr right = equality();
        return new Expr.Logical(left, operator, right);
    }
    return left;
}

private Expr logic_or() {
    Expr left = logic_and();

    while (match(OR)) {
        Token operator = previous();
        Expr right = logic_and();
        return new Expr.Logical(left, operator, right);
    }
    return left;
}

在 Interpreter 中执行语法树:

    @Override
    public Object visitLogicalExpr(Expr.Logical expr) {
        Object left = evaluate(expr.left);
        if (isTruthy(left)) {
            // 如果是 or 直接返回 left
            // 如果是 and 返回 right
            // 由返回式的真假判断真假
            if (expr.operator.type == TokenType.OR) {
                return left;
            } else {
                return evaluate(expr.right);
            }
        }
        // 左值为假
        // 如果是 or 返回右值
        if (expr.operator.type == TokenType.OR) {
            return evaluate(expr.right);
        }

        // 如果是 and
        // 返回假的左值
        return left;
    }

0X01 while for 的原理与实现

while 的实现真的很简单。

按照常理,我们得写出 while 的文法:

statement → exprStmt
          | ifStmt
          | printStmt
          | whileStmt
          | block ;

whileStmt → "while" "(" expression ")" statement ;

然后写出 while 抽象语法树的格式:

    static class While extends Stmt {
        While(Expr condition, Stmt body) {
            this.condition = condition;
            this.body = body;
        }

        <R> R accept(Visitor<R> visitor) {
            return visitor.visitWhileStmt(this);
        }

        final Expr condition;
        final Stmt body;
    }

在 Parse 中生成 while 的抽象语法树:

    private Stmt whileStatement() {
        consume(LEFT_PAREN, "Expect '(' after 'while'.");
        Expr condition = expression();
        consume(RIGHT_PAREN, "Expect ')' after while condition.");
        Stmt body = statement();
        return new Stmt.While(condition, body);
    }

最后在 Interpreter 中执行抽象语法树:

    @Override
    public Void visitWhileStmt(Stmt.While stmt) {
        Expr condition = stmt.condition;
        Stmt body = stmt.body;

        while(isTruthy(evaluate(condition))) {
            execute(body);
        }
        return null;
    }

for 相对难一些,但是 for 本质上是 while 的语法糖,比如:

for (var i = 0; i < 10; i = i + 1) print i;

// 等价于

{
  var i = 0;
  while (i < 10) {
    print i;
    i = i + 1;
  }
}

所以我们使用 while 代替 for ,首先我们将 for 写成如下格式:

for (initializer; condition; increment) body

// 转换成
{
    initializer;
    while(condition) {
        increment;
        body;
    }
}

所以在 parser 中写出:

    private Stmt forStatement() {
        consume(LEFT_PAREN, "Expect '(' after 'for'.");
        Stmt initializer;
        if (match(SEMICOLON)) {
            initializer = null;
        } else if (match(VAR)) {
            initializer = varDeclaration();
        } else {
            initializer = expressionStatement();
        }
        Expr condition = null;
        if (!check(SEMICOLON)) {
            condition = expression();
        }
        consume(SEMICOLON, "Expect ';' after loop condition.");

        Expr increment = null;
        if (!check(RIGHT_PAREN)) {
            increment = expression();
        }
        consume(RIGHT_PAREN, "Expect ')' after for clauses.");
        Stmt body = statement();
        if (increment != null) {
            body = new Stmt.Block(Arrays.asList(body, new Stmt.Expression(increment)));
        }

        if (condition == null)
            condition = new Expr.Literal(true);
        body = new Stmt.While(condition, body);

        if (initializer != null) {
            body = new Stmt.Block(Arrays.asList(initializer, body));
        }

        return body; 
    }

相关文章

网友评论

    本文标题:编译原理——流程控制

    本文链接:https://www.haomeiwen.com/subject/jkycvctx.html