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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@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
 | 
			
		||||
	public Type visitLiteralArray(LiteralArrayContext ctx) {
 | 
			
		||||
		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++)
 | 
			
		||||
			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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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$
 | 
			
		||||
 | 
			
		||||
		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<Reg> {
 | 
			
		|||
						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<Reg> {
 | 
			
		|||
		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> {
 | 
			
		|||
					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<Reg> {
 | 
			
		|||
 | 
			
		||||
				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<Reg> {
 | 
			
		|||
						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$
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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