From c07bd8a4a8e0ee851787ebc337c4f4487aedf0d1 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 31 Dec 2018 02:25:45 +0100 Subject: [PATCH] created direct-on-memory ++/-- and augmented assignemnts. --- compiler/examples/test.p8 | 21 +++++++++---- compiler/src/prog8/ast/AstChecker.kt | 23 ++++++++++---- compiler/src/prog8/compiler/Compiler.kt | 30 ++++++++++++++----- .../src/prog8/compiler/intermediate/Opcode.kt | 2 ++ .../src/prog8/compiler/target/c64/AsmGen.kt | 2 ++ compiler/src/prog8/stackvm/StackVm.kt | 10 +++++++ 6 files changed, 69 insertions(+), 19 deletions(-) diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 056001a56..771e8fb38 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -4,11 +4,22 @@ sub start() { - ubyte[63] balloonsprite = [ 0,127,0,1,255,192,3,255,224,3,231,224, - 7,217,240,7,223,240,7,217,240,3,231,224, - 3,255,224,3,255,224,2,255,160,1,127,64, - 1,62,64,0,156,128,0,156,128,0,73,0,0,73,0, - 0,62,0,0,62,0,0,62,0,0,28,0 ] + A+=5 + + ; @todo if-else if should compile ?: +; if A>100 +; Y=2 +; else if A>20 +; Y=3 + + +; @($d020) = 5 + @($d020)++ + @($d021)-- +; @($d020)=(@$d020)+5 + @($d020)+=5 +; @($d021)=(@$d021)-5 + @($d021)-=5 } } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 24ded452e..b7f7f14ba 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -391,7 +391,6 @@ class AstChecker(private val namespace: INameScope, if(memAddr!=null) { if(memAddr<0 || memAddr>=65536) checkResult.add(ExpressionError("address out of range", target.position)) - return assignment } if(target.identifier!=null) { @@ -433,9 +432,19 @@ class AstChecker(private val namespace: INameScope, // A /= 3 -> check as if it was A = A / 3 val newTarget: IExpression = when { - target.register!=null -> RegisterExpr(target.register, target.position) - target.identifier!=null -> target.identifier - target.arrayindexed!=null -> target.arrayindexed + target.register != null -> RegisterExpr(target.register, target.position) + target.identifier != null -> target.identifier + target.arrayindexed != null -> target.arrayindexed + target.memAddressExpression != null -> { + // @addr += 4 --> @addr = @addr +4 + // TODO: make it so that it follows the others + val memRead = DirectMemoryExpression(target.memAddressExpression!!, target.position) + val expression = BinaryExpression(memRead, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position) + expression.linkParents(assignment.parent) + val assignment2 = Assignment(listOf(target), null, expression, assignment.position) + assignment2.linkParents(assignment.parent) + return assignment2 + } else -> throw FatalAstException("strange assignment") } @@ -796,7 +805,7 @@ class AstChecker(private val namespace: INameScope, } override fun process(postIncrDecr: PostIncrDecr): IStatement { - if(postIncrDecr.target.identifier!=null) { + if(postIncrDecr.target.identifier != null) { val targetName = postIncrDecr.target.identifier!!.nameInSource val target = namespace.lookup(targetName, postIncrDecr) if(target==null) { @@ -808,7 +817,7 @@ class AstChecker(private val namespace: INameScope, checkResult.add(SyntaxError("can only increment or decrement a byte/float/word variable", postIncrDecr.position)) } } - } else if(postIncrDecr.target.arrayindexed!=null) { + } else if(postIncrDecr.target.arrayindexed != null) { val target = postIncrDecr.target.arrayindexed?.identifier?.targetStatement(namespace) if(target==null) { checkResult.add(SyntaxError("undefined symbol", postIncrDecr.position)) @@ -818,6 +827,8 @@ class AstChecker(private val namespace: INameScope, if(dt !in NumericDatatypes && dt !in ArrayDatatypes) checkResult.add(SyntaxError("can only increment or decrement a byte/float/word", postIncrDecr.position)) } + } else if(postIncrDecr.target.memAddressExpression != null) { + // a memory location can always be ++/-- } return super.process(postIncrDecr) } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 5413f07e1..f43dfbe86 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -1254,18 +1254,18 @@ private class StatementTranslator(private val prog: IntermediateProgram, private fun translate(stmt: PostIncrDecr) { prog.line(stmt.position) when { - stmt.target.register!=null -> when(stmt.operator) { + stmt.target.register != null -> when(stmt.operator) { "++" -> prog.instr(Opcode.INC_VAR_UB, callLabel = stmt.target.register.toString()) "--" -> prog.instr(Opcode.DEC_VAR_UB, callLabel = stmt.target.register.toString()) } - stmt.target.identifier!=null -> { + stmt.target.identifier != null -> { val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl when(stmt.operator) { "++" -> prog.instr(opcodeIncvar(targetStatement.datatype), callLabel = targetStatement.scopedname) "--" -> prog.instr(opcodeDecvar(targetStatement.datatype), callLabel = targetStatement.scopedname) } } - stmt.target.arrayindexed!=null -> { + stmt.target.arrayindexed != null -> { val variable = stmt.target.arrayindexed!!.identifier?.targetStatement(namespace) as VarDecl translate(stmt.target.arrayindexed!!.arrayspec.x) when(stmt.operator) { @@ -1273,7 +1273,18 @@ private class StatementTranslator(private val prog: IntermediateProgram, "--" -> prog.instr(opcodeDecArrayindexedVar(variable.datatype), callLabel = variable.scopedname) } } - else -> throw CompilerException("very strange postincrdecr") + stmt.target.memAddressExpression != null -> { + val address = stmt.target.memAddressExpression!!.constValue(namespace, heap)?.asIntegerValue + if(address!=null) { + when(stmt.operator) { + "++" -> prog.instr(Opcode.INC_MEMORY, Value(DataType.UWORD, address)) + "--" -> prog.instr(Opcode.DEC_MEMORY, Value(DataType.UWORD, address)) + } + } else { + TODO("memory ++/-- ${stmt.target.memAddressExpression}") + } + } + else -> throw CompilerException("very strange postincrdecr ${stmt.target}") } } @@ -1345,7 +1356,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, if(stmt.aug_op!=null) { // augmented assignment when { - assignTarget.identifier!=null -> { + assignTarget.identifier != null -> { val target = assignTarget.identifier.targetStatement(namespace)!! when(target) { is VarDecl -> { @@ -1355,8 +1366,11 @@ private class StatementTranslator(private val prog: IntermediateProgram, else -> throw CompilerException("invalid assignment target type ${target::class}") } } - assignTarget.register!=null -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = assignTarget.register.toString()) - assignTarget.arrayindexed!=null -> translate(assignTarget.arrayindexed, false) + assignTarget.register != null -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = assignTarget.register.toString()) + assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, false) + assignTarget.memAddressExpression != null -> { + TODO("translate aug assign on memory address $stmt") + } } translateAugAssignOperator(stmt.aug_op, stmt.value.resultingDatatype(namespace, heap)) @@ -1496,7 +1510,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, } } - private fun translateAugAssignOperator(aug_op: String, valueDt: DataType?) { + private fun translateAugAssignOperator(aug_op: String, valueDt: DataType?) { // @todo: not used in practice? (all augassigns are converted to normal assigns) if(valueDt==null) throw CompilerException("value datatype not known") val validDt = setOf(DataType.UBYTE, DataType.UWORD, DataType.FLOAT) diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index 6387fb628..085f0341e 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -164,6 +164,8 @@ enum class Opcode { DEC_VAR_W, DEC_VAR_UW, DEC_VAR_F, + INC_MEMORY, + DEC_MEMORY, // comparisons // @todo the comparisons push the result back on the stack. Optimize this to work with just processor flags? This does mean you can no longer use a logical boolean result as a byte 0/1 value ? diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 4e1cf3f52..75bb25314 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -655,6 +655,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, jsr prog8_lib.dec_var_f """ } + Opcode.INC_MEMORY -> " inc ${hexVal(ins)}" + Opcode.DEC_MEMORY -> " dec ${hexVal(ins)}" Opcode.NEG_B -> " jsr prog8_lib.neg_b" Opcode.NEG_W -> " jsr prog8_lib.neg_w" Opcode.NEG_F -> " jsr prog8_lib.neg_f" diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 600260ee0..6e0144d6b 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -968,6 +968,16 @@ class StackVm(private var traceOutputFile: String?) { val array = heap.get(variable.heapId) array.array!![index].dec() } + Opcode.INC_MEMORY -> { + val address = evalstack.pop() + checkDt(address, DataType.UWORD) + TODO("inc_memory $address") + } + Opcode.DEC_MEMORY -> { + val address = evalstack.pop() + checkDt(address, DataType.UWORD) + TODO("dec_memory $address") + } Opcode.MSB -> { val v = evalstack.pop() checkDt(v, DataType.UWORD, DataType.WORD)