mirror of https://github.com/aamine/cbc
129 lines
3.9 KiB
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);
|
|
}
|
|
}
|