changed array implementation (size is no longer part of type)

This commit is contained in:
User 2018-02-10 15:20:18 +01:00
parent 68093f96e9
commit c503ff31c5
10 changed files with 216 additions and 141 deletions

View File

@ -102,6 +102,14 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
return false;
}
/**
* Visits the parse tree, then records the returned type in the type
* annotations and returns it too.
*
* @param tree
* the tree to visit
* @return the evaluated type of the tree
*/
@Override
public Type visit(ParseTree tree) {
Type type = super.visit(tree);
@ -150,16 +158,13 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
Variable<Type> var = an.symbols.put(ctx.IDENTIFIER().getText(), visit(ctx.type()));
var.setConstant(ctx.CONSTANT() != null);
an.variables.put(ctx, var);
an.variableRoot.put(var, ctx.getParent());
an.variableRoot.put(var, ctx.getParent().getParent());
if (var.getType() instanceof TupleType)
log.severe(getError(ctx, Messages.getString("BoppiChecker.4"), //$NON-NLS-1$
BoppiLexer.VOCABULARY.getLiteralName(BoppiLexer.BOOLTYPE),
BoppiLexer.VOCABULARY.getLiteralName(BoppiLexer.CHARTYPE),
BoppiLexer.VOCABULARY.getLiteralName(BoppiLexer.INTTYPE)));
if (var.getType() instanceof ReferenceType)
var.assign();
} catch (SymbolTableException e) {
log.severe(getError(ctx, e.getMessage()));
}
@ -200,6 +205,13 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
return SimpleType.VOID;
}
@Override
public Type visitDefineArray(DefineArrayContext ctx) {
checkConstraint(visit(ctx.size), SimpleType.INT, ctx);
return new ArrayType(visit(ctx.type()));
}
@Override
public Type visitGetVariable(GetVariableContext ctx) {
return visit(ctx.variable());
@ -301,6 +313,16 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
return SimpleType.VOID;
}
@Override
public Type visitLiteralArray(LiteralArrayContext ctx) {
Type elementType = visit(ctx.expr(0));
for (int i = 1; i < ctx.expr().size(); i++)
checkConstraint(visit(ctx.expr(i)), elementType, ctx);
return new ArrayType(elementType);
}
@Override
public Type visitLiteralBoolean(LiteralBooleanContext ctx) {
return SimpleType.BOOL;
@ -390,15 +412,7 @@ 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, Messages.getString("BoppiChecker.6"), ctx.LITERAL10().getText())); //$NON-NLS-1$
}
return new ArrayType(size, visit(ctx.type()));
return new ArrayType(visit(ctx.type()));
}
@Override

View File

@ -35,6 +35,22 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
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_REF_COUNT = new Num(-8),
OFFSET_REF_SIZE = new Num(-4);
/**
* Unknown type used in a read expression
*/
public static final Num ERROR_INPUT_UNKNOWN_TYPE = new Num(0x72656164);
/**
* Unknown type used in a print expression
*/
public static final Num ERROR_OUTPUT_UNKNOWN_TYPE = new Num(0x77726974);
/**
* Array out of bounds
*/
public static final Num ERROR_OUT_OF_BOUNDS = new Num(0x616f6f62);
/**
* Negative array size
*/
public static final Num ERROR_ILLEGAL_ARRAY_SIZE = new Num(0x616e737a);
private Program prog;
private Annotations an;
@ -531,29 +547,6 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
});
}
@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); //$NON-NLS-1$
if (t instanceof ArrayType) {
ArrayType type = (ArrayType) t;
regPool.withReg((temp) -> {
malloc(temp, type.getReferenceSize());
emit("link array", OpCode.store, temp, addr); //$NON-NLS-1$
});
}
});
}
return null;
}
/**
* Declare named function:
* <ol>
@ -570,7 +563,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
*/
@Override
public Reg visitDeclareFunction(DeclareFunctionContext ctx) {
ReferenceType type = (ReferenceType) an.variables.get(ctx).getType();
FunctionType funcType = (FunctionType) an.variables.get(ctx).getType();
String base = "define " + ctx.IDENTIFIER().getText() + " - "; //$NON-NLS-1$ //$NON-NLS-2$
Label skip = makeLabel("s"); //$NON-NLS-1$
@ -579,7 +572,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
Reg result = visit(ctx.body);
if (((FunctionType) an.variables.get(ctx).getType()).getReturn() != SimpleType.VOID)
if (funcType.getReturn() != SimpleType.VOID)
emit(base + "move result", OpCode.storeAI, result, arp, OFFSET_RETURN_VAL); //$NON-NLS-1$
if (PROPER_CLEANUP_INSTEAD_OF_PROPER_CLOSURES)
@ -607,7 +600,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit(base + "skip target", skip, OpCode.nop); //$NON-NLS-1$
regPool.withReg((r1, r2) -> {
malloc(r2, type.getReferenceSize());
malloc(r2, funcType.getReferenceSize());
emit(base + "load target address", OpCode.loadI, new Num(callAddress), r1); //$NON-NLS-1$
emit(base + "set target address", OpCode.storeAI, r1, r2, OFFSET_FUNCREF_ADDR); //$NON-NLS-1$
emit(base + "copy ARP", OpCode.storeAI, arp, r2, OFFSET_FUNCREF_ARP); //$NON-NLS-1$
@ -622,6 +615,32 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
return null;
}
@Override
public Reg visitDefineArray(DefineArrayContext ctx) {
Type elementType = ((ArrayType) an.types.get(ctx)).getType();
Reg arrSize = visit(ctx.size);
emit("produce array size", OpCode.multI, arrSize, new Num(elementType.getSize()), arrSize); //$NON-NLS-1$
return regPool.blockReg(arrSize, () -> regPool.withReg((temp) -> {
Label validSize = makeLabel("aszt"), invalidSize = makeLabel("aszf");
emit("check size non negative", OpCode.cmp_GE, arrSize, RegisterPool.ZERO, temp);
emit("", OpCode.cbr, temp, validSize, invalidSize);
emit("invalid array size", invalidSize, OpCode.haltI, ERROR_ILLEGAL_ARRAY_SIZE);
emit("valid array size", validSize, OpCode.nop);
malloc(temp, arrSize);
}));
}
/**
* Loads the value on the address pointed to by the variable context.
* Because the array length is not stored by itself, it will be calculated
* here from the size property.
*
* @see BoppiBaseVisitor#visitGetVariable(GetVariableContext)
*/
@Override
public Reg visitGetVariable(GetVariableContext ctx) {
Type type = an.types.get(ctx);
@ -635,6 +654,15 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
incrementReference(type, result);
});
if (ctx.variable() instanceof VariablePropertyContext) {
VariablePropertyContext vpctx = (VariablePropertyContext) ctx.variable();
Type varType = an.types.get(vpctx.variable());
if (varType instanceof ArrayType)
emit("divide by element size", OpCode.divI, result, //$NON-NLS-1$
new Num(((ArrayType) varType).getType().getSize()), result);
}
return result;
}
@ -717,9 +745,15 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
return regPool.withReg((i, temp1) -> {
regPool.withReg((temp2) -> {
Label cond = makeLabel("aeqc"), loop = makeLabel("aeql"), end = makeLabel("aeqe"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Label equalSize = makeLabel("aeqs"), cond = makeLabel("aeqc"), loop = makeLabel("aeql"), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
end = makeLabel("aeqe"); //$NON-NLS-1$
emit("iterate from 0", OpCode.loadI, ZERO, i); //$NON-NLS-1$
emit("load size lhs", OpCode.loadAI, lhs, OFFSET_REF_SIZE, temp1); //$NON-NLS-1$
emit("load size rhs", OpCode.loadAI, rhs, OFFSET_REF_SIZE, temp2); //$NON-NLS-1$
emit("compare array sizes", OpCode.cmp_EQ, temp1, temp2, temp1); //$NON-NLS-1$
emit("loop if equal", OpCode.cbr, temp1, equalSize, end); //$NON-NLS-1$
emit("iterate from 0", equalSize, OpCode.loadI, ZERO, i); //$NON-NLS-1$
emit("equality true", OpCode.loadI, new Num(1), temp1); //$NON-NLS-1$
emit("load arr size", cond, OpCode.loadAI, lhs, OFFSET_REF_SIZE, temp2); //$NON-NLS-1$
@ -767,6 +801,26 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
return visit(ctx.expr());
}
@Override
public Reg visitLiteralArray(LiteralArrayContext ctx) {
int elements = ctx.expr().size();
int elementSize = ((ArrayType) an.types.get(ctx)).getType().getSize();
return regPool.withReg((addr) -> {
malloc(addr, elements * elementSize);
for (int i = 0; i < elements; i++) {
Reg result = visit(ctx.expr(i));
Num offset = new Num(i * elementSize);
if (elementSize == 1)
emit("store array element", OpCode.cstoreAI, result, addr, offset); //$NON-NLS-1$
else
emit("store array element", OpCode.storeAI, result, addr, offset); //$NON-NLS-1$
}
});
}
@Override
public Reg visitLiteralBoolean(LiteralBooleanContext ctx) {
return regPool.withReg((reg) -> {
@ -852,7 +906,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit("save to var " + expr.getText(), OpCode.cstore, temp, addr); //$NON-NLS-1$
});
else
emit("reading unknown type", OpCode.haltI, new Num(0x72656164)); //$NON-NLS-1$
emit("reading unknown type", OpCode.haltI, ERROR_INPUT_UNKNOWN_TYPE); //$NON-NLS-1$
}
return res;
@ -897,7 +951,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit("check array index", OpCode.cmp_GE, offset, RegisterPool.ZERO, r2); //$NON-NLS-1$
emit("check array index", OpCode.and, r1, r2, r2); //$NON-NLS-1$
emit("check array index", OpCode.cbr, r2, inBounds, outOfBounds); //$NON-NLS-1$
emit("array index out of bounds", outOfBounds, OpCode.haltI, new Num(0x616f6f62)); //$NON-NLS-1$
emit("array index out of bounds", outOfBounds, OpCode.haltI, ERROR_OUT_OF_BOUNDS); //$NON-NLS-1$
emit("multiply index by size", inBounds, OpCode.multI, offset, new Num(type.getType().getSize()), //$NON-NLS-1$
offset);
@ -914,8 +968,10 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
Type innerType = an.types.get(ctx.variable());
Reg addr = visit(ctx.variable());
emit("get object address", OpCode.load, addr, addr); //$NON-NLS-1$
if (innerType instanceof ArrayType) {
emit("get size", OpCode.loadAI, addr, OFFSET_REF_SIZE, addr); //$NON-NLS-1$
emit("add size offset", OpCode.addI, addr, OFFSET_REF_SIZE, addr); //$NON-NLS-1$
return addr;
} else {
return addr;
@ -984,7 +1040,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
emit("print character", OpCode.cout, new Str("")); //$NON-NLS-1$ //$NON-NLS-2$
});
} else {
emit("writing unknown type", OpCode.haltI, new Num(0x77726974)); //$NON-NLS-1$
emit("writing unknown type", OpCode.haltI, ERROR_OUTPUT_UNKNOWN_TYPE); //$NON-NLS-1$
}
if (!expr.equals(ctx.expr(ctx.expr().size() - 1)))

View File

@ -35,16 +35,18 @@ expr
| OUT PAROPEN expr (LISTDELIM expr)* PARCLOSE #write
| IFOPEN cond=stats IFTRUE onTrue=stats (IFFALSE onFalse=stats)? IFCLOSE #if
| WHILEOPEN cond=stats WHILETRUE onTrue=stats WHILECLOSE #while
| LAMBDA IDENTIFIER+ ARROW expr #lambda
| LAMBDA IDENTIFIER+ ARROW body=expr #lambda
| variable PAROPEN (expr (LISTDELIM expr)*)? PARCLOSE #call
| variable #getVariable
| ARRAY PAROPEN type LISTDELIM size=expr PARCLOSE #defineArray
| ARROPEN expr (LISTDELIM expr)* ARRCLOSE #literalArray
| LITERAL10 #literalInteger
| CHAR #literalCharacter
| (TRUE|FALSE) #literalBoolean
;
type
: ARROPEN LITERAL10 ARRCLOSE type #typeArray
: type ARROPEN ARRCLOSE #typeArray
| type ARROW type #typeFunction
| staticType=(INTTYPE | BOOLTYPE | CHARTYPE) #typeSimple
| PAROPEN (type (LISTDELIM type)*)? PARCLOSE #typeTuple

View File

@ -28,10 +28,16 @@ public class ArrayTest {
BoppiTests.parseString("var []int arr; 0");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.parseString("var int a; a := 5; var [5][a]int arr; 0");
BoppiTests.parseString("var int[6] arr; 0");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.parseString("var [4]int arr; (arr)[5]");
BoppiTests.parseString("var int[[]] a; 0");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.parseString("var int[] arr; (arr)[5]");
assertThat(BoppiTests.log, hasSize(1));
BoppiTests.parseString("var int[] arr; arr := array(5)");
assertThat(BoppiTests.log, hasSize(1));
}
@ -52,13 +58,31 @@ public class ArrayTest {
BoppiTests.checkString("var int a; a[5]");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var [5]int arr; arr := 5");
BoppiTests.checkString("var int[] arr; arr := 5");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var [5]int arr; arr[4][2] := 5");
BoppiTests.checkString("var int[] arr; arr[4][2] := 5");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var int a; var int[5] arr; a := arr");
BoppiTests.checkString("var int a; var int[] arr; a := arr");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var int[] arr; arr := array(char, 5)");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var int[] arr; arr := ['a', 'c']");
assertThat(BoppiTests.log, not(empty()));
}
/**
* Uninitialized arrays
*/
@Test
public void wrongArrayChecking2() {
BoppiTests.checkString("var int[] a; a[5]");
assertThat(BoppiTests.log, not(empty()));
BoppiTests.checkString("var int[] a; var int[] b; a := b; a[0]");
assertThat(BoppiTests.log, not(empty()));
}
@ -67,6 +91,11 @@ public class ArrayTest {
*/
@Test
public void correctArrayGeneration() {
BoppiTests.compileAndRunString("var int n; read(n); var int[] arr; arr := array(int, n); print(arr.length)", "7");
assertThat(BoppiTests.vm.getInterrupt(), is(0));
assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("7")));
BoppiTests.compileAndRunFile("simpleArray.boppi");
assertThat(BoppiTests.vm.getInterrupt(), is(0));
assertThat(BoppiTests.log, is(empty()));
@ -84,10 +113,13 @@ public class ArrayTest {
*/
@Test
public void wrongArrayGeneration() {
BoppiTests.compileAndRunString("var [10]int arr; arr[10] := 5");
BoppiTests.compileAndRunString("var int[] arr; arr := array(int, 10); arr[10] := 5");
assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
BoppiTests.compileAndRunString("var [10]int arr; arr[-1]");
BoppiTests.compileAndRunString("var int[] arr; arr := array(int, 10); arr[-1]");
assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
BoppiTests.compileAndRunString("var int[] arr; arr := array(int, -1)");
assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
}

View File

@ -2,33 +2,29 @@ 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 int[][][] arr3;
arr3 := [
[[1,0],
[0,1]],
[[1,1],
[0,1]],
[[3,2],
[2,3]]
];
var [8][2]int arr2_1;
var arr2_1 arr2_2;
arr3[0][0][0] := arr3[2][0][1] := 1337;
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]);
print(arr3[2][0][1]);
// array passing
var [2][4]int target;
var int[][] target; target := array(int[], 2);
function [4]int populate(int start) {
var [4]int arr;
function int[] populate(int start) {
var int[] arr; arr := array(int, 4);
var int i; i := 0;
while i < 4 do
arr[i] := start+i;
i := i+1;
@ -48,7 +44,7 @@ print(target[1][3]);
var target target2;
target2 := target;
var [4]int firstRow;
var int[] firstRow; firstRow := array(int, 4);
firstRow := target2[0];
print(firstRow[2]);
@ -56,13 +52,11 @@ print(firstRow[2]);
// function array
var [10]int arr10;
function arr10 mapArray((int)->int f, arr10 array) {
var arr10 newArr;
function int[] mapArray((int)->int f, int[] arr) {
var int[] newArr; newArr := array(int, arr.length);
var int i; i := 0;
while i < 10 do
newArr[i] := f(array[i]);
while i < arr.length do
newArr[i] := f(arr[i]);
i := i+1;
od;
newArr
@ -70,10 +64,10 @@ function arr10 mapArray((int)->int f, arr10 array) {
function int increment(int a) a+1;
var arr10 myArray;
var int[] myArray; myArray := array(int, 9);
i := 0;
while i < 10 do
while i < myArray.length do
myArray[i] := i*i+10;
i := i+1;
od;

View File

@ -1,46 +1,36 @@
//Recursive fibonacci with memoization closure
var int n;
function (int)->int memoizedFib() {
var int[] memo;
memo := array(int, 50);
var (int)->int fib;
function fib memoize(fib f) {
var [50]int memo;
var int i; i := 0; while i < 50 do
memo[i] := 0;
i := i+1;
od;
function int memoFib(int n) {
if n >= 0 && n < 50 then
if memo[n] > 0 then
memo[n]
else
memo[n] := f(n)
fi
else
f(n)
fi
};
memoFib
};
function int fib_(int n) {
function int fib(int n) {
if n < 2 then
1
else
fib(n-1)+fib(n-2) //has to call `fib` instead of `fib_` because `fib_` is constant
if memo[n] > 0 then
memo[n]
else
var int answer;
answer := fib(n-1)+fib(n-2);
if n < memo.length then
memo[n] := answer
fi;
answer
fi
fi
};
fib
};
fib := memoize(fib_);
var (int)->int myFib;
myFib := memoizedFib();
var int n;
read(n);
while n > 0 do
print(fib(n));
print(myFib(n));
read(n)
od;

View File

@ -1,4 +1,4 @@
var [5]int arr;
var int[] arr; arr := array(int, 5);
var int i; i := 0;
@ -11,13 +11,11 @@ print(arr[3]);
var [2]char arr2;
arr2[0] := 'H';
arr2[1] := 'a';
var char[] arr2; arr2 := ['H', 'a'];
print(arr2[0], arr2[1]);
var [2]char arr3;
var char[] arr3; arr3 := array(char, 2);
arr3[1] := 'a';
arr3[0] := 'H';

View File

@ -3,33 +3,24 @@ package pp.s1184725.boppi.type;
import pp.iloc.eval.Machine;
/**
* A vector type of fixed size. Takes a length and a type parameter.
* A vector type of run-time defined size. Takes 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;
public ArrayType(Type type) {
this.elType = type;
}
@Override
public int getReferenceSize() {
return count * elType.getSize();
}
@Override
public int getSize() {
return Machine.INT_SIZE;
@ -41,12 +32,12 @@ public class ArrayType implements ReferenceType {
return false;
ArrayType other = (ArrayType) obj;
return count == other.count && elType.equals(other.elType);
return elType.equals(other.elType);
}
@Override
public String toString() {
return elType.toString()+"["+count+"]";
return elType.toString()+"[]";
}
/**

View File

@ -28,9 +28,13 @@ public class FunctionType implements ReferenceType {
return Machine.INT_SIZE;
}
@Override
/**
* Returns the size of the function context.
*
* @return the size (in bytes) of the function context
*/
public int getReferenceSize() {
return 3*Machine.INT_SIZE;
return 3 * Machine.INT_SIZE;
}
@Override

View File

@ -6,10 +6,4 @@ package pp.s1184725.boppi.type;
* @author Frank Wibbelink
*/
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();
}