removed lambdas, added string I/O, improved tests, malloc zeroes memory
This commit is contained in:
parent
12d878d24b
commit
c8c13e5d96
|
@ -283,36 +283,6 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
|
||||||
return SimpleType.BOOL;
|
return SimpleType.BOOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type visitLambda(LambdaContext ctx) {
|
|
||||||
// try {
|
|
||||||
// TupleType parameterTypes = new TupleType(
|
|
||||||
// ctx.type().stream().skip(1).map(this::visit).collect(Collectors.toList()));
|
|
||||||
// FunctionType type = new FunctionType(visit(ctx.result),
|
|
||||||
// parameterTypes);
|
|
||||||
// Variable<Type> func = an.symbols.put(ctx.name.getText(), type);
|
|
||||||
// an.variables.put(ctx, func);
|
|
||||||
//
|
|
||||||
// an.function.put(ctx, an.symbols.withFunctionScope(() -> {
|
|
||||||
// for (int i = 1; i < ctx.type().size(); i++)
|
|
||||||
// try {
|
|
||||||
// an.symbols.put(ctx.IDENTIFIER(i).getText(),
|
|
||||||
// an.types.get(ctx.type(i)));
|
|
||||||
// } catch (SymbolTableException e) {
|
|
||||||
// log.severe(getError(ctx, e.getMessage()));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// checkConstraint(an.symbols.withScope(() -> visit(ctx.body)),
|
|
||||||
// an.types.get(ctx.result), ctx);
|
|
||||||
// }));
|
|
||||||
// } catch (SymbolTableException e) {
|
|
||||||
// log.severe(getError(ctx, e.getMessage()));
|
|
||||||
// }
|
|
||||||
log.severe("Lambda not yet implemented"); //$NON-NLS-1$
|
|
||||||
|
|
||||||
return SimpleType.VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type visitLiteralArray(LiteralArrayContext ctx) {
|
public Type visitLiteralArray(LiteralArrayContext ctx) {
|
||||||
Type elementType = visit(ctx.expr(0));
|
Type elementType = visit(ctx.expr(0));
|
||||||
|
@ -320,6 +290,9 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
|
||||||
for (int i = 1; i < ctx.expr().size(); i++)
|
for (int i = 1; i < ctx.expr().size(); i++)
|
||||||
checkConstraint(visit(ctx.expr(i)), elementType, ctx);
|
checkConstraint(visit(ctx.expr(i)), elementType, ctx);
|
||||||
|
|
||||||
|
if (SimpleType.VOID.equals(elementType))
|
||||||
|
log.severe(getError(ctx, Messages.getString("BoppiChecker.16"))); //$NON-NLS-1$
|
||||||
|
|
||||||
return new ArrayType(elementType);
|
return new ArrayType(elementType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -623,11 +623,11 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
|
||||||
emit("produce array size", OpCode.multI, arrSize, new Num(elementType.getSize()), arrSize); //$NON-NLS-1$
|
emit("produce array size", OpCode.multI, arrSize, new Num(elementType.getSize()), arrSize); //$NON-NLS-1$
|
||||||
|
|
||||||
return regPool.blockReg(arrSize, () -> regPool.withReg((temp) -> {
|
return regPool.blockReg(arrSize, () -> regPool.withReg((temp) -> {
|
||||||
Label validSize = makeLabel("aszt"), invalidSize = makeLabel("aszf");
|
Label validSize = makeLabel("aszt"), invalidSize = makeLabel("aszf"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
emit("check size non negative", OpCode.cmp_GE, arrSize, RegisterPool.ZERO, temp);
|
emit("check size non negative", OpCode.cmp_GE, arrSize, RegisterPool.ZERO, temp); //$NON-NLS-1$
|
||||||
emit("", OpCode.cbr, temp, validSize, invalidSize);
|
emit("", OpCode.cbr, temp, validSize, invalidSize); //$NON-NLS-1$
|
||||||
emit("invalid array size", invalidSize, OpCode.haltI, ERROR_ILLEGAL_ARRAY_SIZE);
|
emit("invalid array size", invalidSize, OpCode.haltI, ERROR_ILLEGAL_ARRAY_SIZE); //$NON-NLS-1$
|
||||||
emit("valid array size", validSize, OpCode.nop);
|
emit("valid array size", validSize, OpCode.nop); //$NON-NLS-1$
|
||||||
|
|
||||||
malloc(temp, arrSize);
|
malloc(temp, arrSize);
|
||||||
}));
|
}));
|
||||||
|
@ -768,6 +768,9 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
|
||||||
emit("loop or break", OpCode.cbr, temp1, cond, end); //$NON-NLS-1$
|
emit("loop or break", OpCode.cbr, temp1, cond, end); //$NON-NLS-1$
|
||||||
|
|
||||||
emit("end equality check", end, OpCode.nop); //$NON-NLS-1$
|
emit("end equality check", end, OpCode.nop); //$NON-NLS-1$
|
||||||
|
|
||||||
|
if (ops.get(ctx.op.getType()).equals(OpCode.cmp_NE))
|
||||||
|
emit("invert equality", OpCode.cmp_EQ, temp1, RegisterPool.ZERO, temp1); //$NON-NLS-1$
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -794,13 +797,6 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Reg visitLambda(LambdaContext ctx) {
|
|
||||||
emit(ctx.getText(), OpCode.haltI, new Num(768));
|
|
||||||
|
|
||||||
return visit(ctx.expr());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reg visitLiteralArray(LiteralArrayContext ctx) {
|
public Reg visitLiteralArray(LiteralArrayContext ctx) {
|
||||||
int elements = ctx.expr().size();
|
int elements = ctx.expr().size();
|
||||||
|
@ -905,6 +901,15 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
|
||||||
Reg addr = visit(expr);
|
Reg addr = visit(expr);
|
||||||
emit("save to var " + expr.getText(), OpCode.cstore, temp, addr); //$NON-NLS-1$
|
emit("save to var " + expr.getText(), OpCode.cstore, temp, addr); //$NON-NLS-1$
|
||||||
});
|
});
|
||||||
|
else if (an.types.get(expr) instanceof ArrayType && SimpleType.CHAR.equals(((ArrayType)an.types.get(expr)).getType()))
|
||||||
|
res = regPool.withReg((temp) -> {
|
||||||
|
emit("call stdsin", OpCode.loadI, new Num(prog.size() + 3), temp); //$NON-NLS-1$
|
||||||
|
emit("call stdsin", OpCode.push, temp); //$NON-NLS-1$
|
||||||
|
emit("call stdsin", OpCode.jumpI, new Label("stdsin")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
emit("get address", OpCode.pop, temp); //$NON-NLS-1$
|
||||||
|
Reg addr = visit(expr);
|
||||||
|
emit("save to var " + expr.getText(), OpCode.store, temp, addr); //$NON-NLS-1$
|
||||||
|
});
|
||||||
else
|
else
|
||||||
emit("reading unknown type", OpCode.haltI, ERROR_INPUT_UNKNOWN_TYPE); //$NON-NLS-1$
|
emit("reading unknown type", OpCode.haltI, ERROR_INPUT_UNKNOWN_TYPE); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
@ -1025,7 +1030,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
|
||||||
|
|
||||||
if (SimpleType.BOOL.equals(type)) {
|
if (SimpleType.BOOL.equals(type)) {
|
||||||
regPool.withReg((temp) -> {
|
regPool.withReg((temp) -> {
|
||||||
emit("call stdbout", OpCode.loadI, new Num(prog.size() + 4), temp); // $NON-NLS-2$ //$NON-NLS-1$
|
emit("call stdbout", OpCode.loadI, new Num(prog.size() + 4), temp); //$NON-NLS-1$
|
||||||
emit("call stdbout", OpCode.push, temp); //$NON-NLS-1$
|
emit("call stdbout", OpCode.push, temp); //$NON-NLS-1$
|
||||||
emit("call stdbout", OpCode.push, result); //$NON-NLS-1$
|
emit("call stdbout", OpCode.push, result); //$NON-NLS-1$
|
||||||
emit("call stdbout", OpCode.jumpI, new Label("stdbout")); //$NON-NLS-1$ //$NON-NLS-2$
|
emit("call stdbout", OpCode.jumpI, new Label("stdbout")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
@ -1039,6 +1044,13 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
|
||||||
emit("push 1", OpCode.push, temp); //$NON-NLS-1$
|
emit("push 1", OpCode.push, temp); //$NON-NLS-1$
|
||||||
emit("print character", OpCode.cout, new Str("")); //$NON-NLS-1$ //$NON-NLS-2$
|
emit("print character", OpCode.cout, new Str("")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
});
|
});
|
||||||
|
} else if (type instanceof ArrayType && SimpleType.CHAR.equals(((ArrayType)type).getType())) {
|
||||||
|
regPool.withReg((temp) -> {
|
||||||
|
emit("call stdsout", OpCode.loadI, new Num(prog.size() + 4), temp); //$NON-NLS-1$
|
||||||
|
emit("call stdsout", OpCode.push, temp); //$NON-NLS-1$
|
||||||
|
emit("call stdsout", OpCode.push, result); //$NON-NLS-1$
|
||||||
|
emit("call stdsout", OpCode.jumpI, new Label("stdsout")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
emit("writing unknown type", OpCode.haltI, ERROR_OUTPUT_UNKNOWN_TYPE); //$NON-NLS-1$
|
emit("writing unknown type", OpCode.haltI, ERROR_OUTPUT_UNKNOWN_TYPE); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ expr
|
||||||
| OUT PAROPEN expr (LISTDELIM expr)* PARCLOSE #write
|
| OUT PAROPEN expr (LISTDELIM expr)* PARCLOSE #write
|
||||||
| IFOPEN cond=stats IFTRUE onTrue=stats (IFFALSE onFalse=stats)? IFCLOSE #if
|
| IFOPEN cond=stats IFTRUE onTrue=stats (IFFALSE onFalse=stats)? IFCLOSE #if
|
||||||
| WHILEOPEN cond=stats WHILETRUE onTrue=stats WHILECLOSE #while
|
| WHILEOPEN cond=stats WHILETRUE onTrue=stats WHILECLOSE #while
|
||||||
| LAMBDA IDENTIFIER+ ARROW body=expr #lambda
|
|
||||||
| variable PAROPEN (expr (LISTDELIM expr)*)? PARCLOSE #call
|
| variable PAROPEN (expr (LISTDELIM expr)*)? PARCLOSE #call
|
||||||
| variable #getVariable
|
| variable #getVariable
|
||||||
| ARRAY PAROPEN type LISTDELIM size=expr PARCLOSE #defineArray
|
| ARRAY PAROPEN type LISTDELIM size=expr PARCLOSE #defineArray
|
||||||
|
|
|
@ -70,6 +70,10 @@ ma_final: storeAI m_n => m_p,@off_next // link previous free slot to n
|
||||||
loadI 1 => m_1
|
loadI 1 => m_1
|
||||||
storeAI m_1 => m_c,@off_oref // set reference count to 1
|
storeAI m_1 => m_c,@off_oref // set reference count to 1
|
||||||
storeAI m_s => m_c,@off_osize // set object size
|
storeAI m_s => m_c,@off_osize // set object size
|
||||||
|
ma_zerc: cbr m_s -> ma_zerl,ma_null // zero memory
|
||||||
|
ma_zerl: subI m_s,1 => m_s
|
||||||
|
cstoreAO m_0 => m_c,m_s
|
||||||
|
jumpI -> ma_zerc
|
||||||
ma_null: pop => m_1 // load return address
|
ma_null: pop => m_1 // load return address
|
||||||
push m_c // store object address
|
push m_c // store object address
|
||||||
jump -> m_1
|
jump -> m_1
|
||||||
|
|
|
@ -6,6 +6,7 @@ BoppiChecker.12=Cannot print argument of type '%s'.
|
||||||
BoppiChecker.13=Constant '%s' may already be assigned.
|
BoppiChecker.13=Constant '%s' may already be assigned.
|
||||||
BoppiChecker.14=Variable '%s' may not be assigned.
|
BoppiChecker.14=Variable '%s' may not be assigned.
|
||||||
BoppiChecker.15=Variable '%s' is not assigned.
|
BoppiChecker.15=Variable '%s' is not assigned.
|
||||||
|
BoppiChecker.16=Cannot make array of void elements
|
||||||
BoppiChecker.2=Expected %d arguments but got %d.
|
BoppiChecker.2=Expected %d arguments but got %d.
|
||||||
BoppiChecker.3='%s' is not a function.
|
BoppiChecker.3='%s' is not a function.
|
||||||
BoppiChecker.4=Variable must have a type %s, %s, %s or function.
|
BoppiChecker.4=Variable must have a type %s, %s, %s or function.
|
||||||
|
|
|
@ -20,10 +20,26 @@ sbout_e: pop => m_1 // load return address
|
||||||
jump -> m_1
|
jump -> m_1
|
||||||
|
|
||||||
|
|
||||||
|
// write an array of characters (a string) to output
|
||||||
|
// stack: [return address, address] -> []
|
||||||
|
stdsout: pop => m_1 // get address
|
||||||
|
loadAI m_1,@off_osize => m_2 // get length
|
||||||
|
sout_lc: cbr m_2 -> sout_ll,sout_le // check if any character to push
|
||||||
|
sout_ll: subI m_2, 1 => m_2 // iterate backward
|
||||||
|
cloadAO m_1, m_2 => m_c // get character
|
||||||
|
cpush m_c // push character
|
||||||
|
jumpI -> sout_lc // repeat
|
||||||
|
sout_le: loadAI m_1,@off_osize => m_2 // get length
|
||||||
|
push m_2 // push string length
|
||||||
|
cout "" // print string
|
||||||
|
pop => m_1 // get return address
|
||||||
|
jump -> m_1
|
||||||
|
|
||||||
|
|
||||||
// read a character from input
|
// read a character from input
|
||||||
// stack: [return address] -> [char]
|
// stack: [return address] -> [char]
|
||||||
stdcin: cin "" // get line
|
stdcin: cin "" // get line
|
||||||
pop => m_1 // get length
|
pop => m_1 // get length
|
||||||
cbr m_1 -> scin_t,stdcin // repeat until at least one character
|
cbr m_1 -> scin_t,stdcin // repeat until at least one character
|
||||||
scin_t: cpop => m_2 // save character
|
scin_t: cpop => m_2 // save character
|
||||||
scin_lc: subI m_1, 1 => m_1 // decrement char count
|
scin_lc: subI m_1, 1 => m_1 // decrement char count
|
||||||
|
@ -35,5 +51,32 @@ scin_le: loadI 0 => m_0 // reset zero register
|
||||||
cpush m_2 // push result character
|
cpush m_2 // push result character
|
||||||
jump -> m_1
|
jump -> m_1
|
||||||
|
|
||||||
|
|
||||||
|
// read an array of characters (a string) from input
|
||||||
|
// the memalloc label cannot be used, so address 28 is used instead
|
||||||
|
// stack: [return address] -> [address]
|
||||||
|
stdsin: cin "" // get line
|
||||||
|
pop => m_2 // get length
|
||||||
|
push m_2 // save length
|
||||||
|
loadI #ssin_a => m_1 // call malloc
|
||||||
|
push m_1 // call malloc
|
||||||
|
push m_2 // call malloc
|
||||||
|
loadI 28 => m_c // call malloc
|
||||||
|
jump -> m_c // call malloc
|
||||||
|
ssin_a: pop => m_1 // get array address
|
||||||
|
pop => m_2 // get length
|
||||||
|
i2i m_1 => m_n // load character iterator
|
||||||
|
ssin_c: cbr m_2 -> ssin_l, ssin_e // pop characters into the array
|
||||||
|
ssin_l: subI m_2,1 => m_2
|
||||||
|
cpop => m_c // pop character
|
||||||
|
cstore m_c => m_n // save character
|
||||||
|
addI m_n,1 => m_n // increment iterator
|
||||||
|
jumpI -> ssin_c
|
||||||
|
ssin_e: pop => m_2 // get return address
|
||||||
|
push m_1 // push array address
|
||||||
|
jump -> m_2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
estdlib_: nop
|
estdlib_: nop
|
||||||
// end of stdlib
|
// end of stdlib
|
|
@ -106,6 +106,20 @@ public class ArrayTest {
|
||||||
assertThat(BoppiTests.log, is(empty()));
|
assertThat(BoppiTests.log, is(empty()));
|
||||||
assertThat(BoppiTests.out, is(arrayContaining("1337", "13", "2", "15")));
|
assertThat(BoppiTests.out, is(arrayContaining("1337", "13", "2", "15")));
|
||||||
|
|
||||||
|
BoppiTests.compileAndRunString("var int[][] m; m := [[1,3]]; m[0]; var int[] a; a := [8,9]; print(m[0][1])");
|
||||||
|
assertThat(BoppiTests.vm.getInterrupt(), is(0));
|
||||||
|
assertThat(BoppiTests.log, is(empty()));
|
||||||
|
assertThat(BoppiTests.out, is(arrayContaining("3")));
|
||||||
|
|
||||||
|
BoppiTests.compileAndRunString("print([1,2]==[1,2],[1,2]<>[1,2],[1]==[1,2],[0]<>[2])");
|
||||||
|
assertThat(BoppiTests.vm.getInterrupt(), is(0));
|
||||||
|
assertThat(BoppiTests.log, is(empty()));
|
||||||
|
assertThat(BoppiTests.out, is(arrayContaining("true", "false", "false", "true")));
|
||||||
|
|
||||||
|
BoppiTests.compileAndRunFile("arrayFunctions.boppi", "Hello");
|
||||||
|
assertThat(BoppiTests.vm.getInterrupt(), is(0));
|
||||||
|
assertThat(BoppiTests.log, is(empty()));
|
||||||
|
assertThat(BoppiTests.out, is(arrayContaining("Hi;Hello;1337")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
function char[] concat(char[] a, char[] b) {
|
||||||
|
var char[] result; result := array(char, a.length+b.length);
|
||||||
|
var int i; i := 0;
|
||||||
|
|
||||||
|
while i < result.length do
|
||||||
|
result[i] := if i < a.length then a[i] else b[i-a.length] fi;
|
||||||
|
i := i+1;
|
||||||
|
od;
|
||||||
|
|
||||||
|
result
|
||||||
|
};
|
||||||
|
|
||||||
|
function char[] substring(char[] s, int start, int stop) {
|
||||||
|
var char[] result; result := array(char, stop-start);
|
||||||
|
var int i; i := 0;
|
||||||
|
|
||||||
|
while i < result.length do
|
||||||
|
result[i] := s[i+start];
|
||||||
|
i := i+1;
|
||||||
|
od;
|
||||||
|
|
||||||
|
result
|
||||||
|
};
|
||||||
|
|
||||||
|
function char dtoa(int d) {
|
||||||
|
var char c; c := '0';
|
||||||
|
if d == 1 then c := '1' fi;
|
||||||
|
if d == 2 then c := '2' fi;
|
||||||
|
if d == 3 then c := '3' fi;
|
||||||
|
if d == 4 then c := '4' fi;
|
||||||
|
if d == 5 then c := '5' fi;
|
||||||
|
if d == 6 then c := '6' fi;
|
||||||
|
if d == 7 then c := '7' fi;
|
||||||
|
if d == 8 then c := '8' fi;
|
||||||
|
if d == 9 then c := '9' fi;
|
||||||
|
c
|
||||||
|
};
|
||||||
|
|
||||||
|
function char[] itoa(int n) {
|
||||||
|
if n == 0 then
|
||||||
|
['0']
|
||||||
|
else
|
||||||
|
if n < 0 then
|
||||||
|
concat(['-'], itoa(-n))
|
||||||
|
else
|
||||||
|
if n >= 10 then
|
||||||
|
concat(itoa(n/10), [dtoa(n-n/10*10)])
|
||||||
|
else
|
||||||
|
[dtoa(n)]
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
};
|
||||||
|
|
||||||
|
function char[] strjoin(char[][] strings, char[] sep) {
|
||||||
|
var char[] result; result := array(char, 0);
|
||||||
|
var int i; i := 0;
|
||||||
|
|
||||||
|
while i < strings.length do
|
||||||
|
result := concat(result, strings[i]);
|
||||||
|
if i < strings.length-1 then
|
||||||
|
result := concat(result, sep);
|
||||||
|
fi;
|
||||||
|
i := i+1;
|
||||||
|
od;
|
||||||
|
|
||||||
|
result
|
||||||
|
};
|
||||||
|
|
||||||
|
var char[] input;
|
||||||
|
|
||||||
|
print(strjoin([['H','i'], read(input), itoa(1337)], [';']));
|
Loading…
Reference in New Issue