diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index a7f1c578e..2cbccac6c 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -48,30 +48,115 @@ sub start() { memory word[3] mwarr1 = $e100 memory uword[3] muwarr1 = $e100 + str string = "hello" + str_p stringp = "hello" -; all possible assignments to a BYTE VARIABLE -assignments: +; all possible assignments to a BYTE VARIABLE (not array) + +byte_assignment_to_register: A = 42 - A = Y A = X - Y = X A = ub - X = ub - Y = ub A = mubyte - X = mubyte - Y = mubyte A = ubarr1[2] - X = ubarr1[2] - Y = ubarr1[2] A = ubmatrix1[1,2] - X = ubmatrix1[1,2] - Y = ubmatrix1[1,2] + A = string[4] + A = AY[4] + +byte_assignment_to_bytevar: + b = 42 + b = b2 + b = mbyte + b = barr1[2] + b = bmatrix1[1,2] + + ub = 42 + ub = X + ub = ub2 + ub = mubyte + ub = ubarr1[2] + ub = ubmatrix1[1,2] + ub = string[4] + ub = AY[4] +; all possible assignments to a WORD VARIABLE (not array) + +word_assignment_to_registerpair: + AY = 42 + AY = 42.w + AY = 42555 + AY = X + AY = XY + AY = ub + AY = mubyte + AY = ubarr1[2] + AY = ubmatrix1[1,2] + AY = string[4] + AY = uw + AY = muword + AY = uwarr1[2] + AY = string[4] + AY = XY[4] + +;word_assignment_to_wordvar: + w = -42 + w = -42.w + w = -12345 + w = X + w = b2 + w = ub2 + w = w2 + w = mbyte + w = mubyte + w = mword + w = barr1[2] + w = ubarr1[2] + w = warr1[2] + w = bmatrix1[1,2] + w = ubmatrix1[1,2] + w = string[4] + w = AY[4] + + uw = 42 + uw = 42.w + uw = 42555 + uw = X + uw = AY + uw = ub2 + uw = uw2 + uw = mubyte + uw = muword + uw = ubarr1[2] + uw = uwarr1[2] + uw = ubmatrix1[1,2] + uw = string[4] + uw = AY[4] +; all possible assignments to a FLOAT VARIABLE +float_assignment_to_floatvar: + fl1 = 34 + fl1 = 34555.w + fl1 = 3.33e22 + fl1 = X + fl1 = AY + fl1 = b2 + fl1 = ub2 + fl1 = w2 + fl1 = uw2 + fl1 = mbyte + fl1 = mubyte + fl1 = mword + fl1 = muword + fl1 = barr1[2] + fl1 = ubarr1[2] + fl1 = warr1[2] + fl1 = uwarr1[2] + fl1 = bmatrix1[1,2] + fl1 = ubmatrix1[1,2] + fl1 = string[4] return } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 52d5d1992..45d621fd1 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -67,7 +67,7 @@ enum class BranchCondition { } val IterableDatatypes = setOf( - DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, + DataType.STR, DataType.STR_S, // note: the STR_P/STR_PS types aren't iterable because they store their length as the first byte DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX_UB, DataType.MATRIX_B) diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 240a6baf7..657451d92 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -702,7 +702,7 @@ class AstChecker(private val namespace: INameScope, val indexedRegister = postIncrDecr.target.arrayindexed?.register if(indexedRegister!=null) { if(indexedRegister==Register.A || indexedRegister==Register.X || indexedRegister==Register.Y) - checkResult.add(SyntaxError("arrayspec indexing on registers requires register pair variable", postIncrDecr.position)) + checkResult.add(SyntaxError("indexing on registers requires register pair variable", postIncrDecr.position)) } else { val target = postIncrDecr.target.arrayindexed?.identifier?.targetStatement(namespace) if(target==null) { @@ -724,7 +724,7 @@ class AstChecker(private val namespace: INameScope, val target = arrayIndexedExpression.identifier!!.targetStatement(namespace) if(target is VarDecl) { if(target.datatype !in IterableDatatypes) - checkResult.add(SyntaxError("arrayspec indexing requires an iterable variable", arrayIndexedExpression.position)) + checkResult.add(SyntaxError("indexing requires an iterable variable", arrayIndexedExpression.position)) val arraysize = target.arrayspec?.size() if(arraysize!=null) { // check out of bounds @@ -734,13 +734,21 @@ class AstChecker(private val namespace: INameScope, val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue if(index!=null && (index<0 || index>=arraysize)) checkResult.add(ExpressionError("arrayspec index out of bounds", arrayIndexedExpression.arrayspec.position)) + } else if(target.datatype in StringDatatypes) { + // check string lengths + (arrayIndexedExpression.arrayspec.y as? LiteralValue)?.asIntegerValue + val heapId = (target.value as LiteralValue).heapId!! + val stringLen = heap.get(heapId).str!!.length + val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue + if(index!=null && (index<0 || index>=stringLen)) + checkResult.add(ExpressionError("index out of bounds", arrayIndexedExpression.arrayspec.position)) } } else - checkResult.add(SyntaxError("arrayspec indexing requires a variable to act upon", arrayIndexedExpression.position)) + checkResult.add(SyntaxError("indexing requires a variable to act upon", arrayIndexedExpression.position)) } else if(reg==Register.A || reg==Register.X || reg==Register.Y) { - checkResult.add(SyntaxError("arrayspec indexing on registers requires register pair variable", arrayIndexedExpression.position)) + checkResult.add(SyntaxError("indexing on registers requires register pair variable", arrayIndexedExpression.position)) } else if(arrayIndexedExpression.arrayspec.y!=null) { - checkResult.add(SyntaxError("arrayspec indexing on registers can only use one index dimension", arrayIndexedExpression.position)) + checkResult.add(SyntaxError("indexing on registers can only use one index dimension", arrayIndexedExpression.position)) } // check index value 0..255 diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index bb699e009..c3e029c93 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -312,7 +312,9 @@ private class StatementTranslator(private val prog: IntermediateProgram, DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.READ_INDEXED_VAR_WORD DataType.ARRAY_F -> Opcode.READ_INDEXED_VAR_FLOAT DataType.MATRIX_UB, DataType.MATRIX_B -> Opcode.READ_INDEXED_VAR_BYTE - else -> throw CompilerException("invalid dt for indexed $dt") + DataType.STR, DataType.STR_S -> Opcode.READ_INDEXED_VAR_BYTE + DataType.STR_P, DataType.STR_PS -> throw CompilerException("cannot access pascal-string type $dt with index") + else -> throw CompilerException("invalid dt for indexed access $dt") } } @@ -322,7 +324,9 @@ private class StatementTranslator(private val prog: IntermediateProgram, DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.WRITE_INDEXED_VAR_WORD DataType.ARRAY_F -> Opcode.WRITE_INDEXED_VAR_FLOAT DataType.MATRIX_UB, DataType.MATRIX_B -> Opcode.WRITE_INDEXED_VAR_BYTE - else -> throw CompilerException("invalid dt for indexed $dt") + DataType.STR, DataType.STR_S -> Opcode.WRITE_INDEXED_VAR_BYTE + DataType.STR_P, DataType.STR_PS -> throw CompilerException("cannot access pascal-string type $dt with index") + else -> throw CompilerException("invalid dt for indexed access $dt") } } diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index b316bb70f..3c7173a41 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -910,7 +910,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, private val patterns = listOf( // ----------- assignment to BYTE VARIABLE ---------------- - // @todo var=var // var = bytevalue AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_VAR_BYTE)) { segment -> when (segment[1].callLabel) { @@ -999,7 +998,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // var = bytearray[indexvar] AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment -> - "nop" // TODO + TODO("$segment") }, @@ -1050,6 +1049,45 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ } }, + // var = other var + AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_VAR_WORD)) { segment -> + when(segment[1].callLabel) { + "AX" -> + when(segment[0].callLabel) { + "AX" -> null + "AY" -> " stx ${C64Zeropage.SCRATCH_B1} | ldy ${C64Zeropage.SCRATCH_B1}" + "XY" -> " stx ${C64Zeropage.SCRATCH_B1} | tax | ldy ${C64Zeropage.SCRATCH_B1}" + else -> " lda ${segment[0].callLabel} | ldx ${segment[0].callLabel}+1" + } + "AY" -> + when(segment[0].callLabel) { + "AX" -> " sty ${C64Zeropage.SCRATCH_B1} | ldx ${C64Zeropage.SCRATCH_B1}" + "AY" -> null + "XY" -> " tax" + else -> " lda ${segment[0].callLabel} | ldy ${segment[0].callLabel}+1" + } + "XY" -> + when(segment[0].callLabel) { + "AX" -> " txa | sty ${C64Zeropage.SCRATCH_B1} | ldx ${C64Zeropage.SCRATCH_B1}" + "AY" -> " txa" + "XY" -> null + else -> " ldx ${segment[0].callLabel} | ldy ${segment[0].callLabel}+1" + } + else -> + when(segment[0].callLabel) { + "AX" -> " sta ${segment[1].callLabel} | stx ${segment[1].callLabel}+1" + "AY" -> " sta ${segment[1].callLabel} | sty ${segment[1].callLabel}+1" + "XY" -> " stx ${segment[1].callLabel} | sty ${segment[1].callLabel}+1" + else -> + """ + lda ${segment[0].callLabel} + ldy ${segment[0].callLabel}+1 + sta ${segment[1].callLabel} + sty ${segment[1].callLabel}+1 + """ + } + } + }, // var = mem (u)word AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.POP_VAR_WORD)) { segment -> when(segment[1].callLabel) { @@ -1156,6 +1194,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } }, + // var = bytearray[index_byte] (sign extended) + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.B2WORD, Opcode.POP_VAR_WORD)) { segment -> + val index = segment[0].arg!!.integerValue().toHex() + TODO("$segment (sign extended)") + }, // var = (u)wordarray[index_byte] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_VAR_WORD)) { segment -> val index = segment[0].arg!!.integerValue()*2 @@ -1168,11 +1211,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // var = bytearray[indexvar] (sign extended) AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment -> - "nop" // TODO + TODO("$segment") }, // var = (u)wordarray[indexvar] AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.POP_VAR_WORD)) { segment -> - "nop" // TODO + TODO("$segment") }, @@ -1413,18 +1456,18 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // floatvar = floatarray[index] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> - "nop" // TODO + TODO("$segment") }, // floatvar = floatarray[indexvar] AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> - "nop" // TODO + TODO("$segment") }, // floatvar = floatarray[mem index (u)byte] AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> - "nop" // TODO + TODO("$segment") }, AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.POP_VAR_FLOAT)) { segment -> - "nop" // TODO + TODO("$segment") }, @@ -1506,27 +1549,27 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // assignment: bytearray[memory (u)byte] = byte AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_MEM_B, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> - "nop" // TODO + TODO("$segment") }, AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_MEM_UB, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> - "nop" // TODO + TODO("$segment") }, // assignment: bytearray[idxvar] = byte AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> - "nop" // TODO + TODO("$segment") }, // assignment: bytearray[idxvar] = bytevar AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> - "nop" // TODO + TODO("$segment") }, // assignment: bytearray[mem (u)byte] = bytevar AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_MEM_B, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> - "nop" // TODO + TODO("$segment") }, AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_MEM_UB, Opcode.WRITE_INDEXED_VAR_BYTE)) { segment -> - "nop" // TODO + TODO("$segment") }, // assignment: bytearray[idxbyte] = membyte @@ -1557,15 +1600,15 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // assignment: wordarray[memory (u)byte] = word AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.PUSH_MEM_B, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - "nop" // TODO + TODO("$segment") }, AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.PUSH_MEM_UB, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - "nop" // TODO + TODO("$segment") }, // assignment: wordarray[indexvar] = word AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - "nop" // TODO + TODO("$segment") }, // assignment: wordarray[idxbyte] = wordvar AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> @@ -1585,7 +1628,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, }, // assignment: wordarray[indexvar] = wordvar AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> - "nop" // TODO + TODO("$segment") }, // assignment: wordarray[idxbyte] = memword AsmPattern(listOf(Opcode.PUSH_MEM_W, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->