implemented arrays, split antlr file into grammar and lexer

This commit is contained in:
User 2017-07-30 14:53:53 +02:00
parent 5a48e93674
commit f6cabe0ccb
15 changed files with 770 additions and 322 deletions

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -311,15 +311,15 @@ public class Simulator {
break;
case halt:
this.vm.setInterrupt(c.reg(0));
System.err.printf(
"Program halted with code %d at line %d.%n",
c.num(0), o.getLine());
if (DEBUG)
System.err.printf("Program halted with code %d at line %d.", c.reg(0), o.getLine());
break;
case haltI:
this.vm.setInterrupt(c.num(0));
System.err.printf(
"Program halted with code %d at line %d.%n",
c.num(0), o.getLine());
if (DEBUG)
System.err.printf("Program halted with code %d at line %d.", c.num(0), o.getLine());
break;
default:
System.err.printf(

View File

@ -168,6 +168,11 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
return ctx.singleExpr().stream().map(this::visit).reduce((__, snd) -> snd).get();
}
@Override
public Type visitGetVariable(GetVariableContext ctx) {
return visit(ctx.variable());
}
@Override
public Type visitIf(IfContext ctx) {
return an.symbols.withScope(() -> {
@ -287,6 +292,19 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
}
}
@Override
public Type visitTypeArray(TypeArrayContext ctx) {
int size = 0;
try {
size = Integer.parseInt(ctx.LITERAL10().getText());
}catch (NumberFormatException e) {
log.severe(getError(ctx, "Error parsing number '%s'", ctx.LITERAL10().getText()));
}
return new ArrayType(size, visit(ctx.type()));
}
@Override
public Type visitTypeFunction(TypeFunctionContext ctx) {
return new FunctionType(visit(ctx.type(1)), visit(ctx.type(0)));
@ -308,7 +326,42 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
}
@Override
public Type visitVariable(VariableContext ctx) {
public Type visitVariableArray(VariableArrayContext ctx) {
Type t = visit(ctx.variable());
checkConstraint(visit(ctx.expr()), SimpleType.INT, ctx);
if (t instanceof ArrayType) {
ArrayType arrayType = (ArrayType) t;
return arrayType.getType();
} else {
log.severe(getError(ctx, "Expected array type but got %s", t));
return SimpleType.VOID;
}
}
@Override
public Type visitVariableProperty(VariablePropertyContext ctx) {
Type varType = visit(ctx.variable());
String prop = ctx.IDENTIFIER().getText();
if (varType instanceof ArrayType) {
if (prop.equals("length")) {
return SimpleType.INT;
}
else {
log.severe(getError(ctx, "Unknown array property '%s'.", prop));
return SimpleType.VOID;
}
}
else {
log.severe(getError(ctx, "Record types not implemented."));
return SimpleType.VOID;
}
}
@Override
public Type visitVariableSimple(VariableSimpleContext ctx) {
try {
Variable<Type> var = an.symbols.get(ctx.getText());
@ -322,14 +375,8 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
return var.getType();
} catch (SymbolTableException e) {
log.severe(getError(ctx, e.getMessage()));
}
return SimpleType.VOID;
}
@Override
public Type visitVariableExpr(VariableExprContext ctx) {
return visit(ctx.variable());
}
@Override

View File

@ -22,12 +22,12 @@ import pp.s1184725.boppi.util.RegisterPool;
* @author Frank Wibbelink
*/
public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
private static final int ARBASESIZE = 16, FUNCREF_SIZE = 12;
private static final int ARBASESIZE = 16;
private static final Num ZERO = new Num(0);
private static final Reg ZERO_REG = new Reg("zero");
private static final Num OFFSET_ARP = new Num(-4), OFFSET_RETURN_ADDR = new Num(-8),
OFFSET_RETURN_VAL = new Num(-12), OFFSET_AL = new Num(-16), OFFSET_FUNCREF_ADDR = ZERO,
OFFSET_FUNCREF_ARP = new Num(4), OFFSET_FUNCREF_ARSIZE = new Num(8);
OFFSET_FUNCREF_ARP = new Num(4), OFFSET_FUNCREF_ARSIZE = new Num(8), OFFSET_REF_COUNT = new Num(-8),
OFFSET_REF_SIZE = new Num(-4);
private Program prog;
private Annotations an;
@ -89,21 +89,6 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
this.logger = logger;
}
private Reg getVar(VariableContext node) {
Variable<Type> var = an.variables.get(node);
int functionDepth = an.function.get(node).getFunctionDepth();
if (var.getDepth() < functionDepth) {
emit("travelling ALs", OpCode.i2i, arp, tempArp);
for (int i = var.getDepth(); i < functionDepth; i++)
emit(StringUtils.repeat(' ', i) + "\\", OpCode.loadAI, tempArp, OFFSET_AL, tempArp);
return tempArp;
} else
return arp;
}
/**
* Constructs an operation from the parameters and adds it to the program
* under construction.
@ -135,7 +120,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
String comment = "AR incRef";
Label loop = makeLabel("aril"), done = makeLabel("arid");
emit(comment, OpCode.i2i, ar, tempArp);
emit(comment, OpCode.cmp_NE, tempArp, ZERO_REG, temp);
emit(comment, OpCode.cmp_NE, tempArp, RegisterPool.ZERO, temp);
emit(comment, OpCode.cbr, temp, loop, done);
emit(comment, loop, OpCode.loadI, new Num(prog.size() + 5), temp);
emit(comment, OpCode.push, temp);
@ -144,7 +129,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit(comment, OpCode.jumpI, new Label("memaddref"));
emit(comment, OpCode.loadAI, tempArp, OFFSET_AL, tempArp);
emit(comment, OpCode.cmp_NE, tempArp, ZERO_REG, temp);
emit(comment, OpCode.cmp_NE, tempArp, RegisterPool.ZERO, temp);
emit(comment, OpCode.cbr, temp, loop, done);
emit(comment, done, OpCode.nop);
}
@ -161,7 +146,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
String comment = "AR decRef";
Label loop = makeLabel("ardl"), done = makeLabel("ardd");
emit(comment, OpCode.i2i, ar, tempArp);
emit(comment, OpCode.cmp_NE, tempArp, ZERO_REG, temp);
emit(comment, OpCode.cmp_NE, tempArp, RegisterPool.ZERO, temp);
emit(comment, OpCode.cbr, temp, loop, done);
emit(comment, loop, OpCode.loadI, new Num(prog.size() + 5), temp);
emit(comment, OpCode.push, temp);
@ -170,7 +155,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit(comment, OpCode.jumpI, new Label("memfree"));
emit(comment, OpCode.loadAI, tempArp, OFFSET_AL, tempArp);
emit(comment, OpCode.cmp_NE, tempArp, ZERO_REG, temp);
emit(comment, OpCode.cmp_NE, tempArp, RegisterPool.ZERO, temp);
emit(comment, OpCode.cbr, temp, loop, done);
emit(comment, done, OpCode.nop);
}
@ -256,30 +241,64 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
return String.format("Line %d:%d - %s", line, column, String.format(message, args));
}
/**
* Constructs a new unique label with the given prefix to make it
* recognisable in ILOC.
*
* @param prefix
* a short prefix for the label
* @return the label
*/
private Label makeLabel(String prefix) {
return new Label(prefix + (labels++));
}
/**
* Increments the reference count to a type if it is a reference type. For
* function types this includes all access links. Assumes registers are
* reserved.
*
* @param type
* the type of this reference
* @param addr
* the address of the reference object
*/
private void incrementReference(Type type, Reg addr) {
regPool.withReg((temp) -> {
if (!(type instanceof ReferenceType))
logger.severe(String.format("INTERNAL: trying to increment reference for '%s'", type));
regPool.withReg((temp, ar) -> {
String comment = "add new reference";
incRef(temp, addr);
if (type instanceof FunctionType) {
emit(comment, OpCode.loadAI, addr, OFFSET_FUNCREF_ARP, addr);
emit(comment, OpCode.loadAI, addr, OFFSET_FUNCREF_ARP, ar);
incARReferences(temp, addr);
incARReferences(temp, ar);
}
});
}
/**
* Decrements the reference count to a type if it is a reference type. For
* function types this includes all access links. Assumes registers are
* reserved.
*
* @param type
* the type of this reference
* @param addr
* the address of the reference object
*/
private void decrementReference(Type type, Reg addr) {
if (!(type instanceof ReferenceType))
logger.severe(String.format("INTERNAL: trying to increment reference for '%s'", type));
regPool.withReg((temp) -> {
Label isNull = makeLabel("ynul"), notNull = makeLabel("nnul");
String comment = "remove old reference";
emit(comment, OpCode.cmp_EQ, addr, ZERO_REG, temp);
emit(comment, OpCode.cmp_EQ, addr, RegisterPool.ZERO, temp);
emit(comment, OpCode.cbr, temp, isNull, notNull);
emit(comment, notNull, OpCode.nop);
@ -296,7 +315,14 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
});
}
private void cleanScope(FunctionScope<Type> scope) {
/**
* Decrements all reference-type variables of a function. Must be called at
* the end of a function declaration. Assumes registers are reserved.
*
* @param scope
* the function scope with all relevant variables
*/
private void dereferenceLocalVariables(FunctionScope<Type> scope) {
regPool.withReg((addr, ft) -> {
for (Variable<Type> var : scope.getVars()) {
Type type = var.getType();
@ -306,7 +332,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
String comment = "remove reference";
emit(comment + " get var", OpCode.loadAI, arp, new Num(var.getOffset()), addr);
emit(comment, OpCode.cmp_EQ, addr, ZERO_REG, ft);
emit(comment, OpCode.cmp_EQ, addr, RegisterPool.ZERO, ft);
emit(comment, OpCode.cbr, ft, isNull, notNull);
emit(comment, notNull, OpCode.nop);
@ -326,13 +352,41 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
});
}
/**
* {@inheritDoc}
* <p>
* This override only aggregates {@link ParserRuleContext}s.
*/
@Override
public Reg visitChildren(RuleNode node) {
Reg result = defaultResult();
int n = node.getChildCount();
for (int i = 0; i < n; i++) {
if (!shouldVisitNextChild(node, result)) {
break;
}
ParseTree c = node.getChild(i);
Reg childResult = c.accept(this);
if (c instanceof ParserRuleContext)
result = aggregateResult(result, childResult);
}
return result;
}
/**
* {@inheritDoc}
* <p>
* This override logs any exceptions to the {@link Logger} attached to this
* generator.
*/
@Override
public Reg visit(ParseTree tree) {
try {
return super.visit(tree);
} catch (Exception e) {
e.printStackTrace();
System.out.println(prog.prettyPrint());
if (tree instanceof ParserRuleContext)
logger.severe(getError((ParserRuleContext) tree, "%s: %s", e.getClass().getName(), e.getMessage()));
else
@ -343,33 +397,31 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
@Override
public Reg visitAssign(AssignContext ctx) {
Reg result = visit(ctx.singleExpr());
regPool.blockReg(result, () -> {
Type type = an.types.get(ctx);
Reg addr = visit(ctx.variable());
if (type instanceof ReferenceType) {
regPool.withReg((addr) -> {
emit("remove old ref for " + ctx.variable().getText(), OpCode.loadAI, getVar(ctx.variable()),
new Num(an.variables.get(ctx.variable()).getOffset()), addr);
decrementReference(an.types.get(ctx), addr);
regPool.blockReg(addr, () -> {
regPool.withReg((temp) -> {
emit("load reference", OpCode.load, addr, temp);
decrementReference(an.types.get(ctx), temp);
});
});
}
if (SimpleType.CHAR.equals(type))
emit("to " + ctx.variable().getText(), OpCode.cstoreAI, result, getVar(ctx.variable()),
new Num(an.variables.get(ctx.variable()).getOffset()));
else
emit("to " + ctx.variable().getText(), OpCode.storeAI, result, getVar(ctx.variable()),
new Num(an.variables.get(ctx.variable()).getOffset()));
OpCode op = (SimpleType.CHAR.equals(type)) ? OpCode.cstore : OpCode.store;
emit("to " + ctx.variable().getText(), op, result, addr);
if (type instanceof ReferenceType) {
regPool.withReg((addr) -> {
emit("add new ref for " + ctx.variable().getText(), OpCode.loadAI, getVar(ctx.variable()),
new Num(an.variables.get(ctx.variable()).getOffset()), addr);
incrementReference(an.types.get(ctx), addr);
regPool.blockReg(addr, () -> {
regPool.withReg((temp) -> {
emit("load reference", OpCode.load, addr, temp);
incrementReference(an.types.get(ctx), temp);
});
});
}
});
@ -377,49 +429,43 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
return result;
}
@Override
public Reg visitBlock(BlockContext ctx) {
return visit(ctx.expr());
}
@Override
public Reg visitCall(CallContext ctx) {
String base = "call " + ctx.variable().getText() + " - ";
Variable<Type> function = an.variables.get(ctx.variable());
TupleType parameters = (TupleType) ((FunctionType) function.getType()).getParameter();
visit(ctx.variable());
Reg result = regPool.withReg((ar) -> {
Reg ar = regPool.withReg((tempAR) -> {
regPool.withReg((rt) -> {
emit(base + "load function reference", OpCode.loadAI, getVar(ctx.variable()),
new Num(an.variables.get(ctx.variable()).getOffset()), rt);
Reg addr = visit(ctx.variable());
emit(base + "load function reference", OpCode.load, addr, rt);
emit(base + "load AR size", OpCode.loadAI, rt, OFFSET_FUNCREF_ARSIZE, rt);
malloc(ar, rt);
malloc(tempAR, rt);
});
emit(base + "shift AR", OpCode.addI, ar, new Num(ARBASESIZE), ar);
emit(base + "shift AR", OpCode.addI, tempAR, new Num(ARBASESIZE), tempAR);
for (int i = 0; i < ctx.expr().size(); i++) {
Reg exprReg = visit(ctx.expr(i));
if (SimpleType.CHAR.equals(parameters.get(i)))
emit(base + "store param " + i, OpCode.cstoreAI, exprReg, ar, new Num(parameters.getOffset(i)));
emit(base + "store param " + i, OpCode.cstoreAI, exprReg, tempAR, new Num(parameters.getOffset(i)));
else
emit(base + "store param " + i, OpCode.storeAI, exprReg, ar, new Num(parameters.getOffset(i)));
emit(base + "store param " + i, OpCode.storeAI, exprReg, tempAR, new Num(parameters.getOffset(i)));
}
;
});
Stack<Reg> inUse = new Stack<>();
for (Reg reg : regPool.getInUse()) {
if (!reg.equals(ar)) {
inUse.push(reg);
emit(base + "register save " + reg.getName(), OpCode.push, reg);
}
}
Reg res = regPool.withReg((r1, r2) -> {
emit(base + "load function reference", OpCode.loadAI, getVar(ctx.variable()),
new Num(an.variables.get(ctx.variable()).getOffset()), r2);
regPool.blockReg(ar, () -> {
regPool.withReg((r1, r2) -> {
Reg addr = visit(ctx.variable());
emit(base + "load function reference", OpCode.load, addr, r2);
emit(base + "link caller ARP", OpCode.storeAI, arp, ar, OFFSET_ARP);
emit(base + "load AL", OpCode.loadAI, r2, OFFSET_FUNCREF_ARP, r1);
emit(base + "link AL", OpCode.storeAI, r1, ar, OFFSET_AL);
@ -433,8 +479,11 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit(base + "load target address", OpCode.loadAI, r2, OFFSET_FUNCREF_ADDR, r1);
emit(base + "execute", OpCode.jump, r1);
});
});
emit(base + "load result", OpCode.loadAI, arp, OFFSET_RETURN_VAL, r2);
regPool.withReg((temp) -> {
decARReferences(temp, arp);
});
while (!inUse.isEmpty()) {
@ -442,17 +491,33 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit(base + "register unsave " + reg.getName(), OpCode.pop, reg);
}
return res;
});
regPool.withReg(result, (temp) -> {
decARReferences(temp, arp);
});
return regPool.withReg((res) -> {
emit(base + "load result", OpCode.loadAI, arp, OFFSET_RETURN_VAL, res);
emit(base + "reset ARP", OpCode.loadAI, arp, OFFSET_ARP, arp);
});
}
return result;
@Override
public Reg visitDeclare(DeclareContext ctx) {
Variable<Type> var = an.variables.get(ctx);
Type t = var.getType();
if (t instanceof ReferenceType) {
regPool.withReg((addr) -> {
emit("load var address", OpCode.addI, arp, new Num(var.getOffset()), addr);
if (t instanceof ArrayType) {
ArrayType type = (ArrayType) t;
regPool.withReg((temp) -> {
malloc(temp, type.getReferenceSize());
emit("link array", OpCode.store, temp, addr);
});
}
});
}
return null;
}
/**
@ -469,24 +534,28 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
*/
@Override
public Reg visitDeclareFunction(DeclareFunctionContext ctx) {
ReferenceType type = (ReferenceType) an.variables.get(ctx).getType();
String base = "define " + ctx.IDENTIFIER(0).getText() + " - ";
Label skip = makeLabel("s");
emit(base + "jump over body", OpCode.jumpI, skip);
int targetAddress = emit(base + "entry point", OpCode.nop).getLine();
int callAddress = emit(base + "entry point", OpCode.nop).getLine();
Reg result = visit(ctx.body);
emit(base + "move result", OpCode.storeAI, result, arp, OFFSET_RETURN_VAL);
cleanScope(an.function.get(ctx));
dereferenceLocalVariables(an.function.get(ctx));
regPool.withReg((r1, r2) -> {
regPool.withReg((r1) -> {
emit(base + "load return address", OpCode.loadAI, arp, OFFSET_RETURN_ADDR, r1);
emit(base + "go to return address", OpCode.jump, r1);
});
emit(base + "skip target", skip, OpCode.nop);
malloc(r2, FUNCREF_SIZE);
emit(base + "load target address", OpCode.loadI, new Num(targetAddress), r1);
regPool.withReg((r1, r2) -> {
malloc(r2, type.getReferenceSize());
emit(base + "load target address", OpCode.loadI, new Num(callAddress), r1);
emit(base + "set target address", OpCode.storeAI, r1, r2, OFFSET_FUNCREF_ADDR);
emit(base + "copy ARP", OpCode.storeAI, arp, r2, OFFSET_FUNCREF_ARP);
emit(base + "load AR size", OpCode.loadI, new Num(ARBASESIZE + an.function.get(ctx).getLocalDataSize()),
@ -520,6 +589,22 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
return visit(last);
}
@Override
public Reg visitGetVariable(GetVariableContext ctx) {
Type type = an.types.get(ctx);
Reg result = visit(ctx.variable());
OpCode op = SimpleType.CHAR.equals(an.types.get(ctx)) ? OpCode.cload : OpCode.load;
emit("load address", op, result, result);
if (type instanceof ReferenceType)
regPool.blockReg(result, () -> {
incrementReference(type, result);
});
return result;
}
@Override
public Reg visitIf(IfContext ctx) {
Label toTrue = makeLabel("if_t");
@ -527,7 +612,27 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
Label toEnd = makeLabel("if_e");
Reg cond = visit(ctx.cond);
if (an.types.get(ctx) != SimpleType.VOID) {
if (ctx.onFalse == null) {
emit("", OpCode.cbr, cond, toTrue, toEnd);
emit("", toTrue, OpCode.nop);
visit(ctx.onTrue);
emit("end target", toEnd, OpCode.nop);
return null;
} else if (an.types.get(ctx) == SimpleType.VOID) {
emit("", OpCode.cbr, cond, toTrue, toFalse);
emit("", toTrue, OpCode.nop);
visit(ctx.onTrue);
emit("", OpCode.jumpI, toEnd);
emit("", toFalse, OpCode.nop);
visit(ctx.onFalse);
emit("end target", toEnd, OpCode.nop);
return null;
} else {
return regPool.withReg((target) -> {
emit("", OpCode.cbr, cond, toTrue, toFalse);
@ -537,27 +642,10 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit("", toFalse, OpCode.nop);
emit("result", OpCode.i2i, visit(ctx.onFalse), target);
emit("end target", toEnd, OpCode.nop);
});
}
if (ctx.onFalse == null) {
emit("", OpCode.cbr, cond, toTrue, toEnd);
emit("", toTrue, OpCode.nop);
visit(ctx.onTrue);
emit("end target", toEnd, OpCode.nop);
} else {
emit("", OpCode.cbr, cond, toTrue, toFalse);
emit("", toTrue, OpCode.nop);
visit(ctx.onTrue);
emit("", OpCode.jumpI, toEnd);
emit("", toFalse, OpCode.nop);
visit(ctx.onFalse);
emit("end target", toEnd, OpCode.nop);
}
return null;
}
@Override
@ -582,7 +670,37 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
public Reg visitInfix3(Infix3Context ctx) {
Reg lhs = visit(ctx.lhs);
Reg rhs = regPool.blockReg(lhs, () -> visit(ctx.rhs));
Type type = an.types.get(ctx.lhs);
if (type instanceof SimpleType)
emit(ctx.getChild(1).getText(), ops.get(ctx.op.getType()), lhs, rhs, lhs);
else if (type instanceof ArrayType) {
return regPool.blockReg(lhs, rhs, () -> {
ArrayType arr = (ArrayType) type;
Num elementSize = new Num(arr.getType().getSize());
return regPool.withReg((i, temp1) -> {
regPool.withReg((temp2) -> {
Label cond = makeLabel("aeqc"), loop = makeLabel("aeql"), end = makeLabel("aeqe");
emit("iterate from 0", OpCode.loadI, ZERO, i);
emit("equality true", OpCode.loadI, new Num(1), temp1);
emit("load arr size", cond, OpCode.loadAI, lhs, OFFSET_REF_SIZE, temp2);
emit("check i in bounds", OpCode.cmp_LT, i, temp2, temp2);
emit("loop", OpCode.cbr, temp2, loop, end);
emit("load left", loop, OpCode.loadAO, lhs, i, temp1);
emit("load right", OpCode.loadAO, rhs, i, temp2);
emit("increment i", OpCode.addI, i, elementSize, i);
emit("compare elements", OpCode.cmp_EQ, temp1, temp2, temp1);
emit("loop or break", OpCode.cbr, temp1, cond, end);
emit("end equality check", end, OpCode.nop);
});
});
});
}
return lhs;
}
@ -623,13 +741,15 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
@Override
public Reg visitLiteralInteger(LiteralIntegerContext ctx) {
return regPool.withReg((reg) -> {
emit(ctx.getText(), OpCode.loadI, new Num(Integer.parseInt(ctx.LITERAL10().getText())), reg);
});
int val = 0;
try {
val = Integer.parseInt(ctx.LITERAL10().getText());
} catch (NumberFormatException e) {
logger.severe(getError(ctx, "Error parsing number '%s'", ctx.LITERAL10().getText()));
}
@Override
public Reg visitParens(ParensContext ctx) {
return visit(ctx.expr());
emit(ctx.getText(), OpCode.loadI, new Num(val), reg);
});
}
@Override
@ -650,13 +770,13 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
@Override
public Reg visitProgram(ProgramContext ctx) {
emit("initialise zero register", OpCode.loadI, ZERO, ZERO_REG);
emit("initialise zero register", OpCode.loadI, ZERO, RegisterPool.ZERO);
malloc(arp, an.function.get(ctx).getLocalDataSize() + ARBASESIZE);
emit("construct main AR", OpCode.addI, arp, new Num(ARBASESIZE), arp);
visitChildren(ctx);
cleanScope(an.function.get(ctx));
dereferenceLocalVariables(an.function.get(ctx));
emit("deconstruct main AR", OpCode.subI, arp, new Num(ARBASESIZE), arp);
regPool.withReg((temp) -> {
@ -671,11 +791,12 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
if (ctx.variable().size() > 1) {
for (VariableContext expr : ctx.variable()) {
visit(expr);
if (SimpleType.BOOL.equals(an.types.get(expr)) || SimpleType.INT.equals(an.types.get(expr))) {
regPool.withReg((temp) -> {
emit("", OpCode.in, new Str(""), temp);
emit("var " + expr.getText(), OpCode.storeAI, temp, getVar(expr),
new Num(an.variables.get(expr).getOffset()));
Reg addr = visit(expr);
emit("save to var " + expr.getText(), OpCode.store, temp, addr);
});
} else if (SimpleType.CHAR.equals(an.types.get(expr))) {
// Get input until at least 1 character
@ -689,8 +810,8 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
// Get character
emit("pop whole string", continueTarget, OpCode.cpop, temp);
emit("var " + expr.getText(), OpCode.cstoreAI, temp, getVar(expr),
new Num(an.variables.get(expr).getOffset()));
Reg addr = visit(expr);
emit("save to var " + expr.getText(), OpCode.cstore, temp, addr);
// Pop all remaining characters
Label loopTarget = makeLabel("lcpop_l");
@ -703,19 +824,19 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit("pop remaining", stopTarget, OpCode.nop);
});
} else {
emit("reading unknown type", OpCode.haltI, new Num(1));
emit("reading unknown type", OpCode.haltI, new Num(0x72656164));
}
}
return null;
} else {
VariableContext expr = ctx.variable(0);
visit(expr);
if (SimpleType.BOOL.equals(an.types.get(expr)) || SimpleType.INT.equals(an.types.get(expr))) {
return regPool.withReg((result) -> {
emit("", OpCode.in, new Str(""), result);
emit("var " + expr.getText(), OpCode.storeAI, result, getVar(expr),
new Num(an.variables.get(expr).getOffset()));
Reg addr = visit(expr);
emit("save to var " + expr.getText(), OpCode.store, result, addr);
});
} else if (SimpleType.CHAR.equals(an.types.get(expr))) {
return regPool.withReg((count, result) -> {
@ -729,8 +850,8 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
// Get character
emit("pop whole string", continueTarget, OpCode.cpop, result);
emit("var " + expr.getText(), OpCode.cstoreAI, result, getVar(expr),
new Num(an.variables.get(expr).getOffset()));
Reg addr = visit(expr);
emit("save to var " + expr.getText(), OpCode.cstore, result, addr);
// Pop all remaining characters
Label loopTarget = makeLabel("lcpop_l");
@ -745,37 +866,73 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
});
});
} else {
emit("reading unknown type", OpCode.haltI, new Num(1));
emit("reading unknown type", OpCode.haltI, new Num(0x72656164));
return null;
}
}
}
@Override
public Reg visitVariableExpr(VariableExprContext ctx) {
Type type = an.types.get(ctx);
Num offset = new Num(an.variables.get(ctx.variable()).getOffset());
public Reg visitVariableArray(VariableArrayContext ctx) {
ArrayType type = (ArrayType) an.types.get(ctx.variable());
Reg addr = visit(ctx.variable());
return regPool.withReg((result) -> {
if (SimpleType.CHAR.equals(type))
emit("get " + ctx.variable().getText(), OpCode.cloadAI, getVar(ctx.variable()), offset, result);
else
emit("get " + ctx.variable().getText(), OpCode.loadAI, getVar(ctx.variable()), offset, result);
emit("get array object", OpCode.load, addr, addr);
if (type instanceof ReferenceType) {
regPool.blockReg(addr, () -> {
Reg offset = visit(ctx.expr());
regPool.blockReg(offset, () -> {
regPool.withReg((r1, r2) -> {
String comment = "add new ref for " + ctx.variable().getText();
Label outOfBounds = makeLabel("oob"), inBounds = makeLabel("nob");
incRef(r2, result);
emit("check array index", OpCode.loadAI, addr, OFFSET_REF_SIZE, r1);
emit("check array index", OpCode.divI, r1, new Num(type.getType().getSize()), r1);
emit("check array index", OpCode.cmp_LT, offset, r1, r1);
emit("check array index", OpCode.cmp_GE, offset, RegisterPool.ZERO, r2);
emit("check array index", OpCode.and, r1, r2, r2);
emit("check array index", OpCode.cbr, r2, inBounds, outOfBounds);
emit("array index out of bounds", outOfBounds, OpCode.haltI, new Num(0x616f6f62));
if (type instanceof FunctionType) {
emit(comment, OpCode.loadAI, result, OFFSET_FUNCREF_ARP, r1);
incARReferences(r2, r1);
}
emit("multiply index by size", inBounds, OpCode.multI, offset, new Num(type.getType().getSize()),
offset);
emit("get array index address", OpCode.add, addr, offset, addr);
});
});
});
return addr;
}
@Override
public Reg visitVariableProperty(VariablePropertyContext ctx) {
Type innerType = an.types.get(ctx.variable());
Reg addr = visit(ctx.variable());
if (innerType instanceof ArrayType) {
emit("get size", OpCode.loadAI, addr, OFFSET_REF_SIZE, addr);
return addr;
} else {
return addr;
}
}
@Override
public Reg visitVariableSimple(VariableSimpleContext ctx) {
return regPool.withReg((result) -> {
Variable<Type> var = an.variables.get(ctx);
Reg ar = arp;
int functionDepth = an.function.get(ctx).getFunctionDepth();
if (var.getDepth() < functionDepth) {
emit("travelling ALs", OpCode.i2i, ar, tempArp);
for (int i = var.getDepth(); i < functionDepth; i++)
emit(StringUtils.repeat(' ', i) + "\\", OpCode.loadAI, tempArp, OFFSET_AL, tempArp);
ar = tempArp;
}
emit("add offset", OpCode.addI, ar, new Num(var.getOffset()), result);
});
}
@ -815,7 +972,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit("print character", OpCode.cout, new Str(""));
});
} else {
emit("writing unknown type", OpCode.haltI, new Num(1));
emit("writing unknown type", OpCode.haltI, new Num(0x77726974));
}
if (!expr.equals(ctx.expr(ctx.expr().size() - 1)))
@ -835,7 +992,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit("", OpCode.out, new Str(""), result);
return result;
} else if (SimpleType.CHAR.equals(type)) {
regPool.withReg(result, (temp) -> {
regPool.withReg((temp) -> {
emit("push character", OpCode.cpush, result);
emit("load 1", OpCode.loadI, new Num(1), temp);
emit("push 1", OpCode.push, temp);
@ -843,7 +1000,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
});
return result;
} else {
emit("writing unknown type", OpCode.haltI, new Num(1));
emit("writing unknown type", OpCode.haltI, new Num(0x77726974));
return null;
}
});

View File

@ -3,4 +3,7 @@
/BoppiLexer.java
/BoppiLexer.tokens
/BoppiParser.java
/BoppiTokens.java
/BoppiTokens.tokens
/BoppiVisitor.java
/BoppiTokens.g4

View File

@ -1,4 +1,5 @@
grammar Boppi;
import BoppiTokens;
program: expr EOF;
@ -21,7 +22,7 @@ singleExpr
| lhs=singleExpr OR rhs=singleExpr #infix5
| DECLARE type IDENTIFIER #declare
| <assoc=right> variable ASSIGN singleExpr #assign
| variable #variableExpr
| variable #getVariable
| LITERAL10 #literalInteger
| CHAR #literalCharacter
| (TRUE|FALSE) #literalBoolean
@ -30,58 +31,15 @@ singleExpr
;
type
: type ARROW type #typeFunction
: ARROPEN LITERAL10 ARRCLOSE type #typeArray
| type ARROW type #typeFunction
| staticType=(INTTYPE | BOOLTYPE | CHARTYPE) #typeSimple
| PAROPEN (type (LISTDELIM type )*)? PARCLOSE #typeTuple
| PAROPEN (type (LISTDELIM type)*)? PARCLOSE #typeTuple
| variable #typeVariable
;
variable: IDENTIFIER;
PAROPEN: '(';
PARCLOSE: ')';
BRAOPEN: '{';
BRACLOSE: '}';
IN: 'read';
OUT: 'print';
IFOPEN: 'if';
IFTRUE: 'then';
IFFALSE: 'else';
IFCLOSE: 'fi';
WHILEOPEN: 'while';
WHILETRUE: 'do';
WHILECLOSE: 'od';
PLUS: '+';
MINUS: '-';
NOT: '!';
MULTIPLY: '*';
DIVIDE: '/';
LEQ: '<=';
GTE: '>=';
NEQ: '<>';
EQ: '==';
LT: '<';
GT: '>';
AND: '&&';
OR: '||';
DECLARE: 'var';
FUNCTION: 'function';
INTTYPE: 'int';
BOOLTYPE: 'bool';
CHARTYPE: 'char';
ARROW: '->';
ASSIGN: ':=';
COMPOUND: ';';
LISTDELIM: ',';
CHAR: '\'' . '\'';
TRUE: 'true';
FALSE: 'false';
IDENTIFIER: [A-Za-z_][A-Za-z0-9_]*;
LITERAL10: ('0' | [1-9] [0-9]*);
WHITESPACE: [\t\r\n ] -> skip;
LINECOMMENT: '//' ~[\r\n]* -> skip;
BLOCKCOMMENT: '/*' .*? '*/' -> skip;
variable
: variable ARROPEN expr ARRCLOSE #variableArray
| variable PROP IDENTIFIER #variableProperty
| IDENTIFIER #variableSimple
;

View File

@ -0,0 +1,95 @@
package pp.s1184725.boppi.test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import org.junit.Test;
/**
* Test cases for fixed-size arrays.
*
* @author Frank Wibbelink
*/
public class ArrayTest {
/**
* Correct array parsing
*/
@Test
public void correctArrayParsing() {
BoppiTests.parseFile("simpleArray.boppi");
BoppiTests.log.forEach((l)->System.out.println(l.getMessage()));
assertThat(BoppiTests.log, empty());
}
/**
* Arrays with syntax errors
*/
@Test
public void wrongArrayParsing() {
BoppiTests.parseString("var []int arr; 0");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.parseString("var int a; a := 5; var [5][a]int arr; 0");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.parseString("var [4]int arr; (arr)[5]");
assertThat(BoppiTests.log, hasSize(1));
}
/**
* Correct array checking
*/
@Test
public void correctArrayChecking() {
BoppiTests.checkFile("simpleArray.boppi");
assertThat(BoppiTests.log, is(empty()));
}
/**
* Arrays with type errors
*/
@Test
public void wrongArrayChecking() {
BoppiTests.checkString("var int a; a[5]");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var [5]int arr; arr := 5");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var [5]int arr; arr[4][2] := 5");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var int a; var int[5] arr; a := arr");
assertThat(BoppiTests.log, not(empty()));
}
/**
* Correct array generation
*/
@Test
public void correctArrayGeneration() {
BoppiTests.compileAndRunFile("simpleArray.boppi");
assertThat(BoppiTests.vm.getInterrupt(), is(0));
assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("9", "H", "a", "Y")));
BoppiTests.compileAndRunFile("complexArray.boppi");
assertThat(BoppiTests.vm.getInterrupt(), is(0));
assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("1337", "13", "2", "15")));
}
/**
* Out of bounds checking
*/
@Test
public void wrongArrayGeneration() {
BoppiTests.compileAndRunString("var [10]int arr; arr[10] := 5");
assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
BoppiTests.compileAndRunString("var [10]int arr; arr[-1]");
assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
}
}

View File

@ -11,6 +11,7 @@ import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import pp.iloc.Simulator;
import pp.iloc.eval.Machine;
import pp.iloc.model.Program;
import pp.s1184725.boppi.*;
@ -22,7 +23,8 @@ import pp.s1184725.boppi.*;
* @author Frank Wibbelink
*/
@RunWith(Suite.class)
@SuiteClasses({ ExpressionTest.class, SimpleVariableTest.class, ConditionalTest.class, SimpleFunctionTest.class, ClosureTest.class })
@SuiteClasses({ ExpressionTest.class, SimpleVariableTest.class, ConditionalTest.class, SimpleFunctionTest.class,
ClosureTest.class, ArrayTest.class })
public class BoppiTests {
/**
* The path for test programs
@ -41,10 +43,15 @@ public class BoppiTests {
public static List<LogRecord> log;
/**
* Output of last program split by line breaks
* Output of last {@link #compileAndRun} call split by line breaks
*/
public static String[] out;
/**
* Machine used for the last {@link #compileAndRun} call.
*/
public static Machine vm;
/**
* The level of error reporting to use for the tests. Can be changed to
* include finer tests.
@ -158,6 +165,35 @@ public class BoppiTests {
System.out.println(program.prettyPrint());
out = ToolChain.execute(program, logger, input).split("\n");
vm = ToolChain.machine;
}
/**
* Compiles and runs a program in debug mode. This writes the ILOC code, the
* simulation, program output and all logged messages to the standard
* output.
*
* @param code
* the code to run
* @param input
* lines of input for the program
*/
public static void debugRunString(String code, String... input) {
debugRun(ToolChain.getCharStream(code), String.join("\n", input) + "\n");
}
/**
* Compiles and runs a program in debug mode. This writes the ILOC code, the
* simulation, program output and all logged messages to the standard
* output.
*
* @param file
* the file name
* @param input
* lines of input for the program
*/
public static void debugRunFile(String file, String... input) {
debugRun(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)), String.join("\n", input) + "\n");
}
/**
@ -183,6 +219,10 @@ public class BoppiTests {
System.out.println(program.prettyPrint());
out = ToolChain.execute(program, logger, in).split("\n");
vm = ToolChain.machine;
for (String line : out)
System.out.println(">>> "+line);
log.forEach((entry) -> System.out.println(entry.getMessage()));
Simulator.DEBUG = false;

View File

@ -4,8 +4,6 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import org.junit.Test;
import pp.s1184725.boppi.ToolChain;
/**
* Tests for function closures, mostly testing runtime correctness and garbage collection.
*
@ -43,17 +41,17 @@ public class ClosureTest {
@Test
public void correctClosureGeneration() {
BoppiTests.compileAndRunFile("closure1.boppi");
assertThat(ToolChain.machine.getInterrupt(), is(0));
assertThat(BoppiTests.vm.getInterrupt(), is(0));
assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("8", "9")));
BoppiTests.compileAndRunFile("closure2.boppi");
assertThat(ToolChain.machine.getInterrupt(), is(0));
assertThat(BoppiTests.vm.getInterrupt(), is(0));
assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("8", "7", "15", "2")));
BoppiTests.compileAndRunFile("closure3.boppi");
assertThat(ToolChain.machine.getInterrupt(), is(0));
assertThat(BoppiTests.vm.getInterrupt(), is(0));
assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("7", "15", "2")));
}
@ -64,13 +62,13 @@ public class ClosureTest {
@Test
public void correctClosureCleanup() {
BoppiTests.compileAndRunFile("closure1.boppi");
assertThat(ToolChain.machine.load(0), is(4));
assertThat(BoppiTests.vm.load(0), is(4));
BoppiTests.compileAndRunFile("closure2.boppi");
assertThat(ToolChain.machine.load(0), is(4));
assertThat(BoppiTests.vm.load(0), is(4));
BoppiTests.compileAndRunFile("closure3.boppi");
assertThat(ToolChain.machine.load(0), is(4));
assertThat(BoppiTests.vm.load(0), is(4));
}

View File

@ -0,0 +1,84 @@
var int i;
// multi-dimensional array
// like multi-dimensional arrays in most languages, they are arrays of (n-1)-dimensional array references, so they won't be initialised by default
var [2]int arr1_1;
var arr1_1 arr1_2;
var [8][2]int arr2_1;
var arr2_1 arr2_2;
var [3][8][2]int arr3;
arr3[0] := arr2_1;
arr2_1[0] := arr1_1;
arr3[2] := arr2_2;
arr2_2[7] := arr1_2;
arr3[0][0][0] := arr3[2][7][1] := 1337;
print(arr3[2][7][1]);
// array passing
var [2][4]int target;
function [4]int populate(int start) {
var [4]int arr;
var int i; i := 0;
while i < 4 do
arr[i] := start+i;
i := i+1;
od;
arr
};
i := 0;
while i < 2 do
target[i] := populate(10*i);
i := i+1;
od;
print(target[1][3]);
var target target2;
target2 := target;
var [4]int firstRow;
firstRow := target2[0];
print(firstRow[2]);
// function array
var [10]int arr10;
function arr10 mapArray((int)->int f, arr10 array) {
var arr10 newArr;
var int i; i := 0;
while i < 10 do
newArr[i] := f(array[i]);
i := i+1;
od;
newArr
};
function int increment(int a) a+1;
var arr10 myArray;
i := 0;
while i < 10 do
myArray[i] := i*i+10;
i := i+1;
od;
myArray := mapArray(increment, myArray);
print(myArray[2]);

View File

@ -0,0 +1,28 @@
var [5]int arr;
var int i; i := 0;
while (i < 5) do
arr[i] := i*i;
i := i+1;
od;
print(arr[3]);
var [2]char arr2;
arr2[0] := 'H';
arr2[1] := 'a';
print(arr2[0], arr2[1]);
var [2]char arr3;
arr3[1] := 'a';
arr3[0] := 'H';
if arr2 == arr3 then
print('Y')
else
print('N')
fi;

View File

@ -0,0 +1,60 @@
package pp.s1184725.boppi.type;
import pp.iloc.eval.Machine;
/**
* A vector type of fixed size. Takes a length and a type parameter.
*
* @author Frank Wibbelink
*/
public class ArrayType implements ReferenceType {
private int count;
private Type elType;
/**
* Creates a new array type with the given number of elements and their
* type.
*
* @param count
* the number of elements
* @param type
* the type of elements
*/
public ArrayType(int count, Type type) {
this.count = count;
this.elType = type;
}
@Override
public int getReferenceSize() {
return count * elType.getSize();
}
@Override
public int getSize() {
return Machine.INT_SIZE;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ArrayType))
return false;
ArrayType other = (ArrayType) obj;
return count == other.count && elType.equals(other.elType);
}
@Override
public String toString() {
return elType.toString()+"["+count+"]";
}
/**
* Returns the type of the elements in this array.
*
* @return the type of the elements
*/
public Type getType() {
return elType;
}
}

View File

@ -28,6 +28,11 @@ public class FunctionType implements ReferenceType {
return Machine.INT_SIZE;
}
@Override
public int getReferenceSize() {
return 3*Machine.INT_SIZE;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof FunctionType))

View File

@ -7,4 +7,9 @@ package pp.s1184725.boppi.type;
*/
public interface ReferenceType extends Type {
/**
* Returns the size of the object this type references.
* @return the size (in bytes) of the referenced object
*/
public int getReferenceSize();
}

View File

@ -1,6 +1,5 @@
package pp.s1184725.boppi.util;
import java.util.ArrayList;
import java.util.*;
import java.util.function.*;
import java.util.logging.Logger;
@ -16,38 +15,23 @@ public class RegisterPool {
*/
public static int RECOMMENDED_REGISTER_COUNT = 10;
/**
* Register that must have a value of 0.
*/
public static final Reg ZERO = new Reg("r_nul");
private Logger logger;
private List<Reg> regFree, regInUse;
/**
* Creates a new register pool
*
* @param logger
* the logger to use
*/
public RegisterPool(Logger logger) {
regFree = new ArrayList<>();
regInUse = new ArrayList<>();
this.logger = logger;
}
private Reg makeReg() {
return makeRegThatIsNot(null);
}
private Reg makeRegThatIsNot(Reg r1) {
Reg reg = regFree.stream().filter((r2) -> !r2.equals(r1)).findAny().orElseGet(() -> {
if (regInUse.size() == RECOMMENDED_REGISTER_COUNT + 1)
logger.warning(String.format("Using more than %d registers. Consider rebalancing your expressions.",
RECOMMENDED_REGISTER_COUNT));
return new Reg("__" + (regInUse.size() + 1));
});
private void blockReg(Reg reg) {
if (reg == null)
logger.severe("INTERNAL: cannot reserve null register.");
else if (!regFree.contains(reg)) {
logger.severe(String.format("INTERNAL: cannot reserve register %s because it is in use.", reg.getName()));
} else {
regFree.remove(reg);
regInUse.add(reg);
return reg;
}
}
private void freeReg(Reg reg) {
@ -61,15 +45,35 @@ public class RegisterPool {
}
}
private void blockReg(Reg reg) {
if (reg == null)
logger.severe("INTERNAL: cannot reserve null register.");
else if (!regFree.contains(reg)) {
logger.severe(String.format("INTERNAL: cannot reserve register %s because it is in use.", reg.getName()));
} else {
private Reg makeReg() {
return makeRegThatIsNot(null);
}
private Reg makeRegThatIsNot(Reg r1) {
Reg reg = regFree.parallelStream().filter((r2) -> !r2.equals(r1)).findAny().orElseGet(() -> {
if (regInUse.size() == RECOMMENDED_REGISTER_COUNT + 1)
logger.warning(String.format("Using more than %d registers. Consider rebalancing your expressions.",
RECOMMENDED_REGISTER_COUNT));
return new Reg("__" + (regInUse.size() + 1));
});
regFree.remove(reg);
regInUse.add(reg);
return reg;
}
/**
* Creates a new register pool
*
* @param logger
* the logger to use
*/
public RegisterPool(Logger logger) {
regFree = new ArrayList<>();
regInUse = new ArrayList<>();
this.logger = logger;
}
/**
@ -81,22 +85,6 @@ public class RegisterPool {
return regInUse;
}
/**
* Runs some code with a single register allocated.
*
* @param <T>
* the return type of the code
* @param code
* the code to run
* @return the return value of the code
*/
public <T> T withReg(Function<Reg, T> code) {
Reg r = makeReg();
T result = code.apply(r);
freeReg(r);
return result;
}
/**
* Runs some code with a single register allocated.
*
@ -119,46 +107,7 @@ public class RegisterPool {
* @return the second register used in the code
*/
public Reg withReg(BiConsumer<Reg, Reg> code) {
Reg r1 = makeReg();
Reg r2 = makeReg();
code.accept(r1, r2);
freeReg(r1);
freeReg(r2);
return r2;
}
/**
* Runs some code with one register given and one allocated.
*
* @param r1
* the first register to use
* @param code
* the code to run
* @return the register used in the code
*/
public Reg withReg(Reg r1, Consumer<Reg> code) {
Reg r = makeRegThatIsNot(r1);
code.accept(r);
freeReg(r);
return r;
}
/**
* Runs some code with one register given and two allocated.
*
* @param r1
* the first register to use
* @param code
* the code to run
* @return the second register used in the code
*/
public Reg withReg(Reg r1, BiConsumer<Reg, Reg> code) {
Reg r2 = makeRegThatIsNot(r1);
Reg r3 = makeRegThatIsNot(r1);
code.accept(r2, r3);
freeReg(r2);
freeReg(r3);
return r3;
return withReg((r2) -> withReg((r1) -> code.accept(r1, r2)));
}
/**
@ -193,4 +142,21 @@ public class RegisterPool {
freeReg(r1);
}
/**
* Blocks two registers while running some code.
*
* @param <T>
* the return type of the code
* @param r1
* the first register to reserve
* @param r2
* the second register to reserve
* @param code
* the code to run
* @return the return value of the code
*/
public <T> T blockReg(Reg r1, Reg r2, Supplier<T> code) {
return blockReg(r1, () -> blockReg(r2, code));
}
}