本文系 Creating JVM language 翻譯的第 13 篇捐凭。
原文中的代碼和原文有不一致的地方均在新的代碼倉(cāng)庫(kù)中更正過(guò),建議參考新的代碼倉(cāng)庫(kù)篮撑。
源碼
范圍 for 循環(huán)
本節(jié)中我們來(lái)實(shí)現(xiàn)范圍循環(huán)配猫,在范圍內(nèi)迭代值,在 Java 中大概張這個(gè)樣子:
for (int i=0;i<=5;i++)
Enkel 的等價(jià)形式:
for i from 0 to 5
我實(shí)現(xiàn)另外一個(gè)特性砂豌,循環(huán)會(huì)自動(dòng)檢測(cè)是遞增還是遞減:
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--)
遞增或者遞減必須在運(yùn)行時(shí)推斷,因?yàn)榉秶闹悼赡苁欠椒ㄕ{(diào)用的返回值光督。
for while 循環(huán)或者容器迭代器都很相似阳距,本節(jié)不做描述。
語(yǔ)法規(guī)則更改
statement : block
//other statement alternatives
| forStatement ;
forStatement : 'for' ('(')? forConditions (')')? statement ;
forConditions : iterator=varReference 'from' startExpr=expression range='to' endExpr=expression ;
- forConditions 是迭代的條件表達(dá)式
- = 提高可讀性
- 迭代器必須是變量的名字
- startExpression 用來(lái)初始化迭代器
- endExpressions 是迭代器的終止值
for (i from 0 to 5) print i
圖形化的解析樹(shù)如下所示:
匹配 Antlr 上下文對(duì)象
Antlr 根據(jù)語(yǔ)法規(guī)則會(huì)生成 ForStatementContext 對(duì)象结借,我們用它生成對(duì)編譯器更加友好的類筐摘。可以解決迭代器變量未生明的問(wèn)題船老。
public class ForStatementVisitor extends EnkelBaseVisitor<RangedForStatement> {
//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 = 0
for (iterator from 0 to 5) print iterator
迭代器已經(jīng)聲明過(guò),賦值給 startExpression努隙。
new AssignmentStatement(varName,startExpression);
for (iterator from 0 to 5) print iterator
迭代器沒(méi)有聲明球恤,首先聲明,然后賦值給 startExpression荸镊。
new VariableDeclarationStatement(varName,startExpression);
字節(jié)碼生成
RangedForStatement 生成后咽斧,下面我們開(kāi)始生成字節(jié)碼。
JVM 中沒(méi)有為 for 循環(huán)設(shè)計(jì)特殊的指令躬存。一種實(shí)現(xiàn)方式就是使用控制流指令张惹。
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);
}
這看起來(lái)有點(diǎn)復(fù)雜,因?yàn)檫f增遞減的推測(cè)邏輯是在運(yùn)行時(shí)決定的岭洲。
以 for (i from 0 to 5)
為例宛逗,我們來(lái)看一下整個(gè)流程:
- 聲明迭代器變量 i 并且賦予初始值 0
- 檢測(cè)迭代器的值 0 是否大于結(jié)束值 5
- 因?yàn)?0 < 5, 因此遞增,跳到遞增部分
- 執(zhí)行 for 循環(huán)體內(nèi)的語(yǔ)句
- 遞增 1
- 檢查迭代器的值是否大于 5
- 如果條件不成立盾剩,跳到 4
- 循環(huán)體執(zhí)行 5 次后雷激,跳到結(jié)束部分
示例
如下 Enkel 代碼:
Loops {
main(string[] args) {
for i from 1 to 5 {
print i
}
}
}
生成后的字節(jié)碼反編譯后的 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);
}
}
}
運(yùn)行結(jié)果:
$ java Loops
1
2
3
4
5