Lox语言控制流结构实现解析
控制流基础
解释器需支持动态执行流程控制,突破线性计算限制。控制流分为两类:
- 条件分支:选择性跳过代码区域
- 循环结构:重复执行代码块直至终止条件满足
条件语句实现
Lox语言支持标准if-else结构:
if_stmt → "if" "(" cond_expr ")" stmt_block ("else" stmt_block)?
语法树节点定义:
class IfStmt extends Stmt {
final Expr condExpr;
final Stmt trueBranch;
final Stmt falseBranch;
}
解析逻辑:
private Stmt parseConditional() {
consume(LEFT_PAREN, "需左括号");
Expr cond = parseExpression();
consume(RIGHT_PAREN, "需右括号");
Stmt truePath = parseStatement();
Stmt falsePath = null;
if (check(ELSE)) {
advance();
falsePath = parseStatement();
}
return new IfStmt(cond, truePath, falsePath);
}
执行逻辑处理悬空else问题:
public Void executeIf(IfStmt node) {
Object condVal = evaluate(node.condExpr);
if (isTrue(condVal)) {
execute(node.truePath);
} else if (node.falsePath != null) {
execute(node.falsePath);
}
return null;
}
逻辑运算符实现
支持短路求值的逻辑运算符:
expr → logic_or
logic_or → logic_and ( "or" logic_and )*
logic_and → equality ( "and" equality )*
语法树扩展:
class LogicalExpr extends Expr {
final Expr leftOperand;
final Token operator;
final Expr rightOperand;
}
短路求值逻辑:
public Object evalLogical(LogicalExpr expr) {
Object leftVal = evaluate(expr.leftOperand);
if (expr.operator.type == OR) {
if (isTruthy(leftVal)) return leftVal;
} else {
if (!isTruthy(leftVal)) return leftVal;
}
return evaluate(expr.rightOperand);
}
循环结构实现
While循环语法:
while_stmt → "while" "(" cond_expr ")" stmt_block
执行逻辑:
public Void runWhile(WhileStmt node) {
while (isTrue(evaluate(node.loopCond))) {
execute(node.loopBody);
}
return null;
}
For循环语法糖转换:
for (init; cond; update) { body }
// 等价于
{
init;
while (cond) {
body;
update;
}
}
解析器转换实现:
private Stmt desugarFor() {
consume(LEFT_PAREN, "需左括号");
Stmt initStmt = parseInitializer();
Expr condExpr = parseCondition() ?: new Literal(true);
consume(SEMICOLON, "需分号");
Expr updateExpr = parseUpdateExpr();
consume(RIGHT_PAREN, "需右括号");
Stmt bodyStmt = parseBlock();
if (updateExpr != null) {
bodyStmt = new BlockStmt(Arrays.asList(
bodyStmt,
new ExprStmt(updateExpr)
));
}
Stmt whileLoop = new WhileStmt(condExpr, bodyStmt);
return initStmt != null ?
new BlockStmt(Arrays.asList(initStmt, whileLoop)) :
whileLoop;
}