cbc/net/loveruby/cflat/compiler/JumpResolver.java

129 lines
3.9 KiB
Java

package net.loveruby.cflat.compiler;
import net.loveruby.cflat.ast.*;
import net.loveruby.cflat.asm.Label;
import net.loveruby.cflat.exception.*;
import java.util.*;
public class JumpResolver extends Visitor {
static public void resolve(AST ast, ErrorHandler h)
throws SemanticException {
new JumpResolver(h).resolve(ast);
}
protected ErrorHandler errorHandler;
protected LinkedList breakTargetStack;
protected LinkedList continueTargetStack;
protected DefinedFunction currentFunction;
public JumpResolver(ErrorHandler h) {
errorHandler = h;
}
public void resolve(AST ast) throws SemanticException {
breakTargetStack = new LinkedList();
continueTargetStack = new LinkedList();
Iterator funcs = ast.functions();
while (funcs.hasNext()) {
currentFunction = (DefinedFunction)funcs.next();
resolve(currentFunction.body());
currentFunction.checkJumpLinks(errorHandler);
}
if (errorHandler.errorOccured()) {
throw new SemanticException("compile failed.");
}
}
protected void resolve(Node n) {
visitNode(n);
}
private BreakableStmt currentBreakTarget()
throws SemanticException {
if (breakTargetStack.isEmpty()) {
throw new SemanticException("break from out of while/for/switch");
}
return (BreakableStmt)breakTargetStack.getLast();
}
private ContinueableStmt currentContinueTarget()
throws SemanticException {
if (continueTargetStack.isEmpty()) {
throw new SemanticException("continue from out of while/for");
}
return (ContinueableStmt)continueTargetStack.getLast();
}
public void visit(SwitchNode node) {
resolve(node.cond());
breakTargetStack.add(node);
visitNodeList(node.cases());
breakTargetStack.removeLast();
}
public void visit(WhileNode node) {
resolve(node.cond());
breakTargetStack.add(node);
continueTargetStack.add(node);
resolve(node.body());
continueTargetStack.removeLast();
breakTargetStack.removeLast();
}
public void visit(DoWhileNode node) {
breakTargetStack.add(node);
continueTargetStack.add(node);
resolve(node.body());
continueTargetStack.removeLast();
breakTargetStack.removeLast();
resolve(node.cond());
}
public void visit(ForNode node) {
resolve(node.init());
resolve(node.cond());
breakTargetStack.add(node);
continueTargetStack.add(node);
resolve(node.body());
resolve(node.incr());
continueTargetStack.removeLast();
breakTargetStack.removeLast();
}
public void visit(BreakNode node) {
try {
node.setTargetLabel(currentBreakTarget().endLabel());
}
catch (SemanticException ex) {
errorHandler.error(node.location(), ex.getMessage());
}
}
public void visit(ContinueNode node) {
try {
node.setTargetLabel(currentContinueTarget().continueLabel());
}
catch (SemanticException ex) {
errorHandler.error(node.location(), ex.getMessage());
}
}
public void visit(LabelNode node) {
try {
Label label = currentFunction.defineLabel(node.name(),
node.location());
node.setLabel(label);
}
catch (SemanticException ex) {
errorHandler.error(node.location(), ex.getMessage());
}
}
public void visit(GotoNode node) {
node.setTargetLabel(currentFunction.referLabel(node.target()));
}
public void visit(ReturnNode node) {
node.setFunction(currentFunction);
}
}