removed lambdas, added string I/O, improved tests, malloc zeroes memory

This commit is contained in:
User 2018-02-18 19:13:39 +01:00
parent 12d878d24b
commit c8c13e5d96
8 changed files with 165 additions and 47 deletions

View File

@ -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);
} }

View File

@ -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$
} }

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -20,6 +20,22 @@ 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
@ -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

View File

@ -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")));
} }
/** /**

View File

@ -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)], [';']));