博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
手拉手教你实现一门编程语言 Enkel, 系列 13
阅读量:7079 次
发布时间:2019-06-28

本文共 6645 字,大约阅读时间需要 22 分钟。

本文系 翻译的第 13 篇。 原文中的代码和原文有不一致的地方均在新的中更正过,建议参考新的代码仓库。

源码

范围 for 循环

本节中我们来实现范围循环,在范围内迭代值,在 Java 中大概张这个样子: for (int i=0;i<=5;i++)

Enkel 的等价形式: for i from 0 to 5

我实现另外一个特性,循环会自动检测是递增还是递减:

for i from 0 to 5 //increment i from 0 to 5  - for (int i=0;i<=5;i++)for i from 5 to 0 //decremenet i from 5 to 0 - for (int i=5;i>=0;i--)复制代码

递增或者递减必须在运行时推断,因为范围的值可能是方法调用的返回值。

for while 循环或者容器迭代器都很相似,本节不做描述。

语法规则更改

statement : block           //other statement alternatives           | forStatement ;forStatement : 'for' ('(')? forConditions (')')? statement ;forConditions : iterator=varReference  'from' startExpr=expression range='to' endExpr=expression ;复制代码
  • forConditions 是迭代的条件表达式
  • = 提高可读性
  • 迭代器必须是变量的名字
  • startExpression 用来初始化迭代器
  • endExpressions 是迭代器的终止值

for (i from 0 to 5) print i 图形化的解析树如下所示:

匹配 Antlr 上下文对象

Antlr 根据语法规则会生成 ForStatementContext 对象,我们用它生成对编译器更加友好的类。可以解决迭代器变量未生明的问题。

public class ForStatementVisitor extends EnkelBaseVisitor
{ //other stuff @Override public RangedForStatement visitForStatement(@NotNull ForStatementContext ctx) { EnkelParser.ForConditionsContext forExpressionContext = ctx.forConditions(); Expression startExpression = forExpressionContext.startExpr.accept(expressionVisitor); Expression endExpression = forExpressionContext.endExpr.accept(expressionVisitor); VarReferenceContext iterator = forExpressionContext.iterator; String varName = iterator.getText(); //If variable referenced by iterator already exists in the scope if(scope.localVariableExists(varName)) { //register new variable value Statement iteratorVariable = new AssignmentStatement(varName, startExpression); //get the statement (usually block)) Statement statement = ctx.statement().accept(statementVisitor); return new RangedForStatement(iteratorVariable, startExpression, endExpression,statement, varName, scope); //Variable has not been declared in the scope } else { //create new local variable and add to the scope scope.addLocalVariable(new LocalVariable(varName,startExpression.getType())); //register variable declaration statement Statement iteratorVariable = new VariableDeclarationStatement(varName,startExpression); Statement statement = ctx.statement().accept(statementVisitor); return new RangedForStatement(iteratorVariable, startExpression, endExpression,statement, varName,scope); } }}复制代码

迭代器变量可能在作用中存在或者未生明,这两种情况都需要被妥善处理:

var iterator = 0for (iterator from 0 to 5) print iterator复制代码

迭代器已经声明过,赋值给 startExpression。 new AssignmentStatement(varName,startExpression);

for (iterator from 0 to 5) print iterator复制代码

迭代器没有声明,首先声明,然后赋值给 startExpression。 new VariableDeclarationStatement(varName,startExpression);

字节码生成

RangedForStatement 生成后,下面我们开始生成字节码。

JVM 中没有为 for 循环设计特殊的指令。一种实现方式就是使用控制流指令。

public void generate(RangedForStatement rangedForStatement) {    Scope newScope = rangedForStatement.getScope();    StatementGenerator scopeGeneratorWithNewScope = new StatementGenerator(methodVisitor, newScope);    ExpressionGenrator exprGeneratorWithNewScope = new ExpressionGenrator(methodVisitor, newScope);    Statement iterator = rangedForStatement.getIteratorVariableStatement();    Label incrementationSection = new Label();    Label decrementationSection = new Label();    Label endLoopSection = new Label();    String iteratorVarName = rangedForStatement.getIteratorVarName();    Expression endExpression = rangedForStatement.getEndExpression();    Expression iteratorVariable = new VarReference(iteratorVarName, rangedForStatement.getType());    ConditionalExpression iteratorGreaterThanEndConditional = new ConditionalExpression(iteratorVariable, endExpression, CompareSign.GREATER);    ConditionalExpression iteratorLessThanEndConditional = new ConditionalExpression(iteratorVariable, endExpression, CompareSign.LESS);    //generates varaible declaration or variable reference (istore)    iterator.accept(scopeGeneratorWithNewScope);    //Section below checks whether the loop should be iterating or decrementing    //If the range start is smaller than range end (i from 0 to 5)  then iterate (++)    //If the range start is greater than range end (i from 5 to 0) then decrement (--)    //Pushes 0 or 1 onto the stack     iteratorLessThanEndConditional.accept(exprGeneratorWithNewScope);    //IFNE - is value on the stack (result of conditional) different than 0 (success)?    methodVisitor.visitJumpInsn(Opcodes.IFNE,incrementationSection);    iteratorGreaterThanEndConditional.accept(exprGeneratorWithNewScope);    methodVisitor.visitJumpInsn(Opcodes.IFNE,decrementationSection);    //Incrementation section    methodVisitor.visitLabel(incrementationSection);    rangedForStatement.getStatement().accept(scopeGeneratorWithNewScope); //execute the body    methodVisitor.visitIincInsn(newScope.getLocalVariableIndex(iteratorVarName),1); //increment iterator    iteratorGreaterThanEndConditional.accept(exprGeneratorWithNewScope); //is iterator greater than range end?    methodVisitor.visitJumpInsn(Opcodes.IFEQ,incrementationSection); //if it is not go back loop again     //the iterator is greater than end range. Break out of the loop, skipping decrementation section    methodVisitor.visitJumpInsn(Opcodes.GOTO,endLoopSection);     //Decrementation section    methodVisitor.visitLabel(decrementationSection);    rangedForStatement.getStatement().accept(scopeGeneratorWithNewScope);    methodVisitor.visitIincInsn(newScope.getLocalVariableIndex(iteratorVarName),-1); //decrement iterator    iteratorLessThanEndConditional.accept(exprGeneratorWithNewScope);    methodVisitor.visitJumpInsn(Opcodes.IFEQ,decrementationSection);    methodVisitor.visitLabel(endLoopSection);}复制代码

这看起来有点复杂,因为递增递减的推测逻辑是在运行时决定的。

for (i from 0 to 5) 为例,我们来看一下整个流程:

  1. 声明迭代器变量 i 并且赋予初始值 0
  2. 检测迭代器的值 0 是否大于结束值 5
  3. 因为 0 < 5, 因此递增,跳到递增部分
  4. 执行 for 循环体内的语句
  5. 递增 1
  6. 检查迭代器的值是否大于 5
  7. 如果条件不成立,跳到 4
  8. 循环体执行 5 次后,跳到结束部分

示例

如下 Enkel 代码:

Loops {    main(string[] args) {        for i from 1 to 5 {            print i        }    }}复制代码

生成后的字节码反编译后的 Java 代码:

public class Loops {    public static void main(String[] var0) {        int var1 = 1;        if(var1 >= 5 ) { //should it be decremented?            do {                System.out.println(var1);                --var1;            } while(var1 >= 5);        } else { //should it be incremented?            do {                System.out.println(var1);                ++var1;            } while(var1 <= 5);        }    }}复制代码

运行结果:

$ java Loops 12345复制代码

转载于:https://juejin.im/post/5b914c23e51d450e8825dc89

你可能感兴趣的文章
华为13年机试题
查看>>
JSP 生命周期
查看>>
CentOS 7安装配置Redis数据库
查看>>
Javascript基础 错误调试
查看>>
Java实现定时任务的三种方法
查看>>
又见日志-从日志中的思考
查看>>
maven dependency
查看>>
Navicat 快捷键总结
查看>>
Windows Server 2012 之NIC组合(NIC Teaming)介绍
查看>>
电脑无需设置DNS网关该如何上网
查看>>
系统负载能力浅析
查看>>
各种mysql视频的学习笔记
查看>>
OC高效率52之以“自动释放池块”降低内存峰值
查看>>
Linux初学者笔记01
查看>>
Android ListView或GridView中含有CheckBox时,获取选中的id
查看>>
Struts2 - 配置备忘
查看>>
Linux集群简介以及lvs-dr部署(二)
查看>>
eclipse创建maven
查看>>
layer ui使用多层弹框时,各个页面交互问题
查看>>
linux基本命令2 创建文件/文件夹/复制文件/文件夹
查看>>