diff --git a/src/pp/s1184725/boppi/BoppiChecker.java b/src/pp/s1184725/boppi/BoppiChecker.java index bc98367..bc33b46 100644 --- a/src/pp/s1184725/boppi/BoppiChecker.java +++ b/src/pp/s1184725/boppi/BoppiChecker.java @@ -283,36 +283,6 @@ public class BoppiChecker extends BoppiBaseVisitor { 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 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 public Type visitLiteralArray(LiteralArrayContext ctx) { Type elementType = visit(ctx.expr(0)); @@ -320,6 +290,9 @@ public class BoppiChecker extends BoppiBaseVisitor { for (int i = 1; i < ctx.expr().size(); i++) 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); } diff --git a/src/pp/s1184725/boppi/BoppiGenerator.java b/src/pp/s1184725/boppi/BoppiGenerator.java index e79c1e0..006cc1a 100644 --- a/src/pp/s1184725/boppi/BoppiGenerator.java +++ b/src/pp/s1184725/boppi/BoppiGenerator.java @@ -623,11 +623,11 @@ public class BoppiGenerator extends BoppiBaseVisitor { 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); + 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); //$NON-NLS-1$ + emit("", OpCode.cbr, temp, validSize, invalidSize); //$NON-NLS-1$ + emit("invalid array size", invalidSize, OpCode.haltI, ERROR_ILLEGAL_ARRAY_SIZE); //$NON-NLS-1$ + emit("valid array size", validSize, OpCode.nop); //$NON-NLS-1$ malloc(temp, arrSize); })); @@ -768,6 +768,9 @@ public class BoppiGenerator extends BoppiBaseVisitor { emit("loop or break", OpCode.cbr, temp1, cond, end); //$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 { return lhs; } - @Override - public Reg visitLambda(LambdaContext ctx) { - emit(ctx.getText(), OpCode.haltI, new Num(768)); - - return visit(ctx.expr()); - } - @Override public Reg visitLiteralArray(LiteralArrayContext ctx) { int elements = ctx.expr().size(); @@ -905,6 +901,15 @@ public class BoppiGenerator extends BoppiBaseVisitor { Reg addr = visit(expr); 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 emit("reading unknown type", OpCode.haltI, ERROR_INPUT_UNKNOWN_TYPE); //$NON-NLS-1$ } @@ -1025,7 +1030,7 @@ public class BoppiGenerator extends BoppiBaseVisitor { if (SimpleType.BOOL.equals(type)) { 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, result); //$NON-NLS-1$ emit("call stdbout", OpCode.jumpI, new Label("stdbout")); //$NON-NLS-1$ //$NON-NLS-2$ @@ -1039,6 +1044,13 @@ public class BoppiGenerator extends BoppiBaseVisitor { emit("push 1", OpCode.push, temp); //$NON-NLS-1$ 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 { emit("writing unknown type", OpCode.haltI, ERROR_OUTPUT_UNKNOWN_TYPE); //$NON-NLS-1$ } diff --git a/src/pp/s1184725/boppi/antlr/Boppi.g4 b/src/pp/s1184725/boppi/antlr/Boppi.g4 index 2ed67e9..8c436c1 100644 --- a/src/pp/s1184725/boppi/antlr/Boppi.g4 +++ b/src/pp/s1184725/boppi/antlr/Boppi.g4 @@ -35,7 +35,6 @@ 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 body=expr #lambda | variable PAROPEN (expr (LISTDELIM expr)*)? PARCLOSE #call | variable #getVariable | ARRAY PAROPEN type LISTDELIM size=expr PARCLOSE #defineArray diff --git a/src/pp/s1184725/boppi/memlib.iloc b/src/pp/s1184725/boppi/memlib.iloc index 040fdfe..527b361 100644 --- a/src/pp/s1184725/boppi/memlib.iloc +++ b/src/pp/s1184725/boppi/memlib.iloc @@ -70,6 +70,10 @@ ma_final: storeAI m_n => m_p,@off_next // link previous free slot to n loadI 1 => m_1 storeAI m_1 => m_c,@off_oref // set reference count to 1 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 push m_c // store object address jump -> m_1 diff --git a/src/pp/s1184725/boppi/messages.properties b/src/pp/s1184725/boppi/messages.properties index 8dd2538..785f940 100644 --- a/src/pp/s1184725/boppi/messages.properties +++ b/src/pp/s1184725/boppi/messages.properties @@ -6,6 +6,7 @@ BoppiChecker.12=Cannot print argument of type '%s'. BoppiChecker.13=Constant '%s' may already be assigned. BoppiChecker.14=Variable '%s' may not be 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.3='%s' is not a function. BoppiChecker.4=Variable must have a type %s, %s, %s or function. diff --git a/src/pp/s1184725/boppi/stdlib.iloc b/src/pp/s1184725/boppi/stdlib.iloc index c347468..9133d8d 100644 --- a/src/pp/s1184725/boppi/stdlib.iloc +++ b/src/pp/s1184725/boppi/stdlib.iloc @@ -20,10 +20,26 @@ sbout_e: pop => m_1 // load return address 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 // stack: [return address] -> [char] -stdcin: cin "" // get line - pop => m_1 // get length +stdcin: cin "" // get line + pop => m_1 // get length cbr m_1 -> scin_t,stdcin // repeat until at least one character scin_t: cpop => m_2 // save character 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 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 -// end of stdlib +// end of stdlib \ No newline at end of file diff --git a/src/pp/s1184725/boppi/test/ArrayTest.java b/src/pp/s1184725/boppi/test/ArrayTest.java index f152b7d..e30e350 100644 --- a/src/pp/s1184725/boppi/test/ArrayTest.java +++ b/src/pp/s1184725/boppi/test/ArrayTest.java @@ -106,6 +106,20 @@ public class ArrayTest { assertThat(BoppiTests.log, is(empty())); 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"))); } /** diff --git a/src/pp/s1184725/boppi/test/programs/arrayFunctions.boppi b/src/pp/s1184725/boppi/test/programs/arrayFunctions.boppi new file mode 100644 index 0000000..77451be --- /dev/null +++ b/src/pp/s1184725/boppi/test/programs/arrayFunctions.boppi @@ -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)], [';']));