w.i.p pointer-to

This commit is contained in:
Irmen de Jong 2019-04-04 21:02:24 +02:00
parent 3e7e44acfe
commit 1069b5f5d5
12 changed files with 1079 additions and 915 deletions

View File

@ -42,13 +42,10 @@ enum class DataType {
UWORD -> targetType == UWORD || targetType == FLOAT
WORD -> targetType == WORD || targetType==UWORD || targetType == FLOAT
FLOAT -> targetType == FLOAT
STR -> targetType == STR || targetType==STR_S || targetType == UWORD
STR_S -> targetType == STR || targetType==STR_S || targetType == UWORD
ARRAY_UB -> targetType == UWORD || targetType==ARRAY_UB
ARRAY_B -> targetType == UWORD || targetType==ARRAY_B
ARRAY_UW -> targetType == UWORD || targetType==ARRAY_UW
ARRAY_W -> targetType == UWORD || targetType==ARRAY_W
ARRAY_F -> targetType == UWORD || targetType==ARRAY_F
STR -> targetType == STR || targetType==STR_S
STR_S -> targetType == STR || targetType==STR_S
in ArrayDatatypes -> targetType === this
else -> false
}
@ -291,6 +288,10 @@ interface IAstProcessor {
memwrite.addressExpression = memwrite.addressExpression.process(this)
return memwrite
}
fun process(pointerOf: PointerOf): IExpression {
return pointerOf
}
}
@ -1009,6 +1010,22 @@ class TypecastExpression(var expression: IExpression, var type: DataType, overri
}
data class PointerOf(val identifier: IdentifierReference, override val position: Position) : IExpression {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
identifier.parent=this
}
override fun isIterable(namespace: INameScope, heap: HeapValues) = false
override fun constValue(namespace: INameScope, heap: HeapValues): LiteralValue? = null
override fun referencesIdentifier(name: String) = false
override fun resultingDatatype(namespace: INameScope, heap: HeapValues) = DataType.UWORD
override fun process(processor: IAstProcessor) = processor.process(this)
}
class DirectMemoryRead(var addressExpression: IExpression, override val position: Position) : IExpression {
override lateinit var parent: Node
@ -2196,6 +2213,9 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
if(directmemory()!=null)
return DirectMemoryRead(directmemory().expression().toAst(), toPosition())
if(pointerof()!=null)
return PointerOf(pointerof().scoped_identifier().toAst(), toPosition())
throw FatalAstException(text)
}

View File

@ -58,7 +58,7 @@ private class AstChecker(private val namespace: INameScope,
private val heapStringSentinel: Int
init {
val stringSentinel = heap.allEntries().firstOrNull {it.value.str==""}
heapStringSentinel = stringSentinel?.key ?: heap.add(DataType.STR, "")
heapStringSentinel = stringSentinel?.key ?: heap.addString(DataType.STR, "")
}
fun result(): List<AstException> {
@ -401,23 +401,10 @@ private class AstChecker(private val namespace: INameScope,
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
return assignment
}
if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes) {
if(targetSymbol.datatype==DataType.UWORD)
return assignment // array can be assigned to UWORD (it's address should be taken as the value then)
}
}
}
}
// it is only possible to assign an array to something that is an UWORD or UWORD array (in which case the address of the array value is used as the value)
if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes) {
// the UWORD case has been handled above already, check for UWORD array
val arrayVar = target.arrayindexed?.identifier?.targetStatement(namespace)
if(arrayVar is VarDecl && arrayVar.datatype==DataType.ARRAY_UW)
return assignment
checkResult.add(SyntaxError("it's not possible to assign an array to something other than an UWORD, use it as a variable decl initializer instead", assignment.position))
}
if(assignment.aug_op!=null) {
// check augmented assignment (and convert it into a normal assignment!)
// A /= 3 -> check as if it was A = A / 3
@ -468,6 +455,16 @@ private class AstChecker(private val namespace: INameScope,
return assignment
}
override fun process(pointerOf: PointerOf): IExpression {
val variable=pointerOf.identifier.targetStatement(namespace) as? VarDecl
if(variable==null)
checkResult.add(ExpressionError("pointer-of operand must be the name of a heap variable", pointerOf.position))
else {
if(variable.datatype !in ArrayDatatypes && variable.datatype !in StringDatatypes)
checkResult.add(ExpressionError("pointer-of operand must be the name of a string or array heap variable", pointerOf.position))
}
return pointerOf
}
/**
* Check the variable declarations (values within range etc)
@ -984,8 +981,6 @@ private class AstChecker(private val namespace: INameScope,
return err("value '$number' out of range for byte")
}
DataType.UWORD -> {
if(value.isString || value.isArray) // string or array are assignable to uword; their memory address is used.
return true
val number = value.asIntegerValue ?: return if (value.floatvalue!=null)
err("unsigned word value expected instead of float; possible loss of precision")
else
@ -1091,16 +1086,16 @@ private class AstChecker(private val namespace: INameScope,
val correct: Boolean
when(type) {
DataType.ARRAY_UB -> {
correct=array.array!=null && array.array.all { it in 0..255 }
correct=array.array!=null && array.array.all { it.integer!=null && it.integer in 0..255 }
}
DataType.ARRAY_B -> {
correct=array.array!=null && array.array.all { it in -128..127 }
correct=array.array!=null && array.array.all { it.integer!=null && it.integer in -128..127 }
}
DataType.ARRAY_UW -> {
correct=array.array!=null && array.array.all { it in 0..65535 }
correct=array.array!=null && array.array.all { (it.integer!=null && it.integer in 0..65535) || it.pointerOf!=null}
}
DataType.ARRAY_W -> {
correct=array.array!=null && array.array.all { it in -32768..32767 }
correct=array.array!=null && array.array.all { it.integer!=null && it.integer in -32768..32767 }
}
DataType.ARRAY_F -> correct = array.doubleArray!=null
else -> throw AstException("invalid array type $type")
@ -1123,7 +1118,7 @@ private class AstChecker(private val namespace: INameScope,
DataType.BYTE -> sourceDatatype==DataType.BYTE
DataType.UBYTE -> sourceDatatype==DataType.UBYTE
DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.WORD
DataType.UWORD -> sourceDatatype in setOf(DataType.UBYTE, DataType.UWORD, DataType.STR, DataType.STR_S) || sourceDatatype in ArrayDatatypes
DataType.UWORD -> sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.UWORD
DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype==DataType.STR
DataType.STR_S -> sourceDatatype==DataType.STR_S

View File

@ -36,8 +36,11 @@ fun Number.toHex(): String {
}
data class IntegerOrPointerOf(val integer: Int?, val pointerOf: PointerOf?)
class HeapValues {
data class HeapValue(val type: DataType, val str: String?, val array: IntArray?, val doubleArray: DoubleArray?) {
data class HeapValue(val type: DataType, val str: String?, val array: Array<IntegerOrPointerOf>?, val doubleArray: DoubleArray?) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@ -61,7 +64,7 @@ class HeapValues {
fun size(): Int = heap.size
fun add(type: DataType, str: String): Int {
fun addString(type: DataType, str: String): Int {
if (str.length > 255)
throw IllegalArgumentException("string length must be 0-255")
@ -76,14 +79,14 @@ class HeapValues {
return newId
}
fun add(type: DataType, array: IntArray): Int {
fun addIntegerArray(type: DataType, array: Array<IntegerOrPointerOf>): Int {
// arrays are never shared, don't check for existing
val newId = heapId++
heap[newId] = HeapValue(type, null, array, null)
return newId
}
fun add(type: DataType, darray: DoubleArray): Int {
fun addDoublesArray(type: DataType, darray: DoubleArray): Int {
// arrays are never shared, don't check for existing
val newId = heapId++
heap[newId] = HeapValue(type, null, null, darray)
@ -653,6 +656,7 @@ internal class Compiler(private val rootModule: Module,
is TypecastExpression -> translate(expr)
is DirectMemoryRead -> translate(expr)
is DirectMemoryWrite -> translate(expr)
is PointerOf -> translate(expr)
else -> {
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
when(lv.type) {
@ -1081,12 +1085,13 @@ internal class Compiler(private val rootModule: Module,
translate(assignA)
translate(assignX)
}
DataType.UWORD -> {
in WordDatatypes -> {
translate(arg.first)
prog.instr(Opcode.POP_REGAX_WORD)
}
// TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available
DataType.STR, DataType.STR_S -> {
pushStringAddress(arg.first, false)
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGAX_WORD)
}
DataType.FLOAT -> {
@ -1094,7 +1099,7 @@ internal class Compiler(private val rootModule: Module,
prog.instr(Opcode.POP_REGAX_WORD)
}
in ArrayDatatypes -> {
pushStringAddress(arg.first, false)
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGAX_WORD)
}
else -> TODO("pass parameter of type $paramDt in registers AX at $callPosition")
@ -1119,8 +1124,9 @@ internal class Compiler(private val rootModule: Module,
translate(arg.first)
prog.instr(Opcode.POP_REGAY_WORD)
}
// TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available
DataType.STR, DataType.STR_S -> {
pushStringAddress(arg.first, false)
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGAY_WORD)
}
DataType.FLOAT -> {
@ -1128,7 +1134,7 @@ internal class Compiler(private val rootModule: Module,
prog.instr(Opcode.POP_REGAY_WORD)
}
in ArrayDatatypes -> {
pushStringAddress(arg.first, false)
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGAY_WORD)
}
else -> TODO("pass parameter of type $paramDt in registers AY at $callPosition")
@ -1153,12 +1159,13 @@ internal class Compiler(private val rootModule: Module,
translate(assignX)
translate(assignY)
}
DataType.UWORD -> {
in WordDatatypes -> {
translate(arg.first)
prog.instr(Opcode.POP_REGXY_WORD)
}
// TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available
DataType.STR, DataType.STR_S -> {
pushStringAddress(arg.first, false)
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGXY_WORD)
}
DataType.FLOAT -> {
@ -1166,7 +1173,7 @@ internal class Compiler(private val rootModule: Module,
prog.instr(Opcode.POP_REGXY_WORD)
}
in ArrayDatatypes -> {
pushStringAddress(arg.first, false)
pushHeapVarAddress(arg.first, false)
prog.instr(Opcode.POP_REGXY_WORD)
}
else -> TODO("pass parameter of type $paramDt in registers XY at $callPosition")
@ -1524,7 +1531,7 @@ internal class Compiler(private val rootModule: Module,
when (valueDt) {
DataType.UBYTE -> prog.instr(Opcode.CAST_UB_TO_UW)
DataType.BYTE -> prog.instr(Opcode.CAST_B_TO_UW)
DataType.STR, DataType.STR_S -> pushStringAddress(stmt.value, true)
DataType.STR, DataType.STR_S -> pushHeapVarAddress(stmt.value, true)
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.ARRAY_W, DataType.ARRAY_UW, DataType.ARRAY_F -> {
if (stmt.value is IdentifierReference) {
val vardecl = (stmt.value as IdentifierReference).targetStatement(namespace) as VarDecl
@ -1548,7 +1555,7 @@ internal class Compiler(private val rootModule: Module,
}
in StringDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
in ArrayDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
else -> throw CompilerException("weird/unknonwn targetdt")
else -> throw CompilerException("weird/unknown targetdt")
}
}
@ -1560,9 +1567,9 @@ internal class Compiler(private val rootModule: Module,
popValueIntoTarget(assignTarget, datatype)
}
private fun pushStringAddress(value: IExpression, removeLastOpcode: Boolean) {
private fun pushHeapVarAddress(value: IExpression, removeLastOpcode: Boolean) {
when (value) {
is LiteralValue -> throw CompilerException("can only push address of string that is a variable on the heap")
is LiteralValue -> throw CompilerException("can only push address of string or array (value on the heap)")
is IdentifierReference -> {
val vardecl = value.targetStatement(namespace) as VarDecl
if(removeLastOpcode) prog.removeLastInstruction()
@ -2163,6 +2170,18 @@ internal class Compiler(private val rootModule: Module,
}
}
private fun translate(ptrof: PointerOf) {
val target = ptrof.identifier.targetStatement(namespace) as VarDecl
if(target.datatype in ArrayDatatypes || target.datatype in StringDatatypes|| target.datatype==DataType.FLOAT) {
pushHeapVarAddress(ptrof.identifier, false)
}
else if(target.datatype==DataType.FLOAT) {
pushFloatAddress(ptrof.identifier)
}
else
throw CompilerException("cannot take memory pointer $ptrof")
}
private fun translateAsmInclude(args: List<DirectiveArg>, importedFrom: Path) {
val scopeprefix = if(args[1].str!!.isNotBlank()) "${args[1].str}\t.proc\n" else ""
val scopeprefixEnd = if(args[1].str!!.isNotBlank()) "\t.pend\n" else ""

View File

@ -359,20 +359,25 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
private fun makeArrayFillDataUnsigned(value: Value): List<String> {
val array = heap.get(value.heapId).array!!
return if (value.type == DataType.ARRAY_UB || value.type == DataType.ARRAY_UW)
array.map { "$"+it.toString(16).padStart(2, '0') }
if(value.type==DataType.ARRAY_UB) {
TODO("deal with byte array")
//return array.map { "$"+it.toString(16).padStart(2, '0') }
} else if(value.type==DataType.ARRAY_UW) {
TODO("deal with pointerto")
}
else
throw AssemblyError("invalid arrayspec type")
}
private fun makeArrayFillDataSigned(value: Value): List<String> {
val array = heap.get(value.heapId).array!!
// note: array of signed value can never contain pointer-to type, so simply process values as being all integers
return if (value.type == DataType.ARRAY_B || value.type == DataType.ARRAY_W) {
array.map {
if(it>=0)
"$"+it.toString(16).padStart(2, '0')
if(it.integer!!>=0)
"$"+it.integer.toString(16).padStart(2, '0')
else
"-$"+abs(it).toString(16).padStart(2, '0')
"-$"+abs(it.integer).toString(16).padStart(2, '0')
}
}
else throw AssemblyError("invalid arrayspec type")
@ -923,23 +928,21 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
if(mulIns.opcode == Opcode.MUL_B || mulIns.opcode==Opcode.MUL_UB) {
if(amount in setOf(0,1,2,4,8,16,32,64,128,256))
throw AssemblyError("multiplication by power of 2 should have been converted into a left shift instruction already")
printWarning("multiplication by power of 2 should have been optimized into a left shift instruction: $mulIns $amount")
if(amount in setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40))
return " jsr math.mul_byte_$amount"
if(mulIns.opcode == Opcode.MUL_B && amount in setOf(-3,-5,-6,-7,-9,-10,-11,-12,-13,-14,-15,-20,-25,-40))
return " jsr prog8_lib.neg_b | jsr math.mul_byte_${-amount}"
}
else if(mulIns.opcode == Opcode.MUL_UW) {
if(amount in setOf(0,1,2,4,8,16,32,64,128,256))
throw AssemblyError("multiplication by power of 2 should have been converted into a left shift instruction already")
printWarning("multiplication by power of 2 should have been optimized into a left shift instruction: $mulIns $amount")
if(amount in setOf(3,5,6,7,9,10,12,15,20,25,40))
return " jsr math.mul_word_$amount"
}
else if(mulIns.opcode == Opcode.MUL_W) {
if(amount in setOf(0,1,2,4,8,16,32,64,128,256))
throw AssemblyError("multiplication by power of 2 should have been converted into a left shift instruction already")
printWarning("multiplication by power of 2 should have been optimized into a left shift instruction: $mulIns $amount")
if(amount in setOf(3,5,6,7,9,10,12,15,20,25,40))
return " jsr math.mul_word_$amount"
if(amount in setOf(-3,-5,-6,-7,-9,-10,-12,-15,-20,-25,-40))

View File

@ -245,7 +245,12 @@ private fun collectionArgOutputNumber(args: List<IExpression>, position: Positio
if(iterable.heapId==null)
throw FatalAstException("iterable value should be on the heap")
val array = heap.get(iterable.heapId).array ?: throw SyntaxError("function expects an iterable type", position)
function(array.map { it.toDouble() })
function(array.map {
if(it.integer!=null)
it.integer.toDouble()
else
throw FatalAstException("cannot perform function over array that contains other values besides constant integers")
})
}
}
}
@ -266,7 +271,12 @@ private fun collectionArgOutputBoolean(args: List<IExpression>, position: Positi
function(constants.map { it!!.toDouble() })
} else {
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("function requires array argument", position)
function(array.map { it.toDouble() })
function(array.map {
if(it.integer!=null)
it.integer.toDouble()
else
throw FatalAstException("cannot perform function over array that contains other values besides constant integers")
})
}
return LiteralValue.fromBoolean(result, position)
}
@ -298,7 +308,12 @@ private fun builtinAvg(args: List<IExpression>, position: Position, namespace:IN
}
else {
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("avg requires array argument", position)
array.average()
if(array.all {it.integer!=null}) {
array.map { it.integer!! }.average()
} else {
throw ExpressionError("cannot avg() over array that does not only contain constant integer values", position)
}
// TODO what about avg() on floating point array variable!
}
return numericLiteral(result, args[0].position)
}

View File

@ -3,6 +3,7 @@ package prog8.optimizing
import prog8.ast.*
import prog8.compiler.CompilerException
import prog8.compiler.HeapValues
import prog8.compiler.IntegerOrPointerOf
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
import kotlin.math.floor
@ -69,8 +70,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
}
else -> {}
}
val fillArray = IntArray(size) { fillvalue }
val heapId = heap.add(decl.datatype, fillArray)
val heapId = heap.addIntegerArray(decl.datatype, Array(size) { IntegerOrPointerOf(fillvalue, null) })
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position)
}
}
@ -82,8 +82,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
if(fillvalue< FLOAT_MAX_NEGATIVE || fillvalue> FLOAT_MAX_POSITIVE)
errors.add(ExpressionError("float value overflow", litval?.position ?: decl.position))
else {
val fillArray = DoubleArray(size) { fillvalue }
val heapId = heap.add(decl.datatype, fillArray)
val heapId = heap.addDoublesArray(decl.datatype, DoubleArray(size) { fillvalue })
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position)
}
}
@ -112,7 +111,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
DataType.ARRAY_F -> {
if(array.array!=null) {
// convert a non-float array to floats
val doubleArray = array.array.map { it.toDouble() }.toDoubleArray()
val doubleArray = array.array.map { it.integer!!.toDouble() }.toDoubleArray()
heap.update(heapId, HeapValues.HeapValue(DataType.ARRAY_F, null, null, doubleArray))
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval.position)
}
@ -534,7 +533,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
if(literalValue.strvalue(heap).length !in 1..255)
addError(ExpressionError("string literal length must be between 1 and 255", literalValue.position))
else {
val heapId = heap.add(literalValue.type, literalValue.strvalue(heap)) // TODO: we don't know the actual string type yet, STR != STR_S etc...
val heapId = heap.addString(literalValue.type, literalValue.strvalue(heap)) // TODO: we don't know the actual string type yet, STR != STR_S etc...
val newValue = LiteralValue(literalValue.type, heapId = heapId, position = literalValue.position)
return super.process(newValue)
}
@ -547,13 +546,20 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
private fun moveArrayToHeap(arraylit: LiteralValue): LiteralValue {
val array: Array<IExpression> = arraylit.arrayvalue!!.map { it.process(this) }.toTypedArray()
val allElementsAreConstant = array.fold(true) { c, expr-> c and (expr is LiteralValue)}
if(!allElementsAreConstant) {
addError(ExpressionError("array literal can contain only constant values", arraylit.position))
val allElementsAreConstantOrPointerOf = array.fold(true) { c, expr-> c and (expr is LiteralValue || expr is PointerOf)}
if(!allElementsAreConstantOrPointerOf) {
addError(ExpressionError("array literal can only consist of constant primitive numerical values or memory pointers", arraylit.position))
return arraylit
} else if(array.any {it is PointerOf}) {
val arrayDt = DataType.UWORD
val intArrayWithPointers = mutableListOf<IntegerOrPointerOf>()
// TODO FILL THIS ARRAY
val heapId = heap.addIntegerArray(DataType.UWORD, intArrayWithPointers.toTypedArray())
return LiteralValue(arrayDt, heapId = heapId, position = arraylit.position)
} else {
// array is only constant numerical values
val valuesInArray = array.map { it.constValue(namespace, heap)!!.asNumericValue!! }
val integerArray = valuesInArray.map{it.toInt()}.toIntArray()
val integerArray = valuesInArray.map{ it.toInt() }
val doubleArray = valuesInArray.map{it.toDouble()}.toDoubleArray()
val typesInArray: Set<DataType> = array.mapNotNull { it.resultingDatatype(namespace, heap) }.toSet()
@ -587,8 +593,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
DataType.ARRAY_UB,
DataType.ARRAY_B,
DataType.ARRAY_UW,
DataType.ARRAY_W -> heap.add(arrayDt, integerArray)
DataType.ARRAY_F -> heap.add(arrayDt, doubleArray)
DataType.ARRAY_W -> heap.addIntegerArray(arrayDt, integerArray.map { IntegerOrPointerOf(it, null) }.toTypedArray())
DataType.ARRAY_F -> heap.addDoublesArray(arrayDt, doubleArray)
else -> throw CompilerException("invalid arrayspec type")
}
return LiteralValue(arrayDt, heapId = heapId, position = arraylit.position)

View File

@ -2,6 +2,7 @@ package prog8.stackvm
import prog8.ast.*
import prog8.compiler.HeapValues
import prog8.compiler.IntegerOrPointerOf
import prog8.compiler.intermediate.*
import java.io.File
import java.util.*
@ -87,17 +88,17 @@ class Program (val name: String,
}
heapvalues.sortedBy { it.first }.forEach {
when(it.second) {
DataType.STR, DataType.STR_S -> heap.add(it.second, unescape(it.third.substring(1, it.third.length-1), Position("<stackvmsource>", 0, 0, 0)))
DataType.STR, DataType.STR_S -> heap.addString(it.second, unescape(it.third.substring(1, it.third.length-1), Position("<stackvmsource>", 0, 0, 0)))
DataType.ARRAY_UB, DataType.ARRAY_B,
DataType.ARRAY_UW, DataType.ARRAY_W -> {
val numbers = it.third.substring(1, it.third.length-1).split(',')
val intarray = numbers.map{number->number.trim().toInt()}.toIntArray()
heap.add(it.second, intarray)
val intarray = numbers.map{number->IntegerOrPointerOf(number.trim().toInt(), null)}.toTypedArray()
heap.addIntegerArray(it.second, intarray)
}
DataType.ARRAY_F -> {
val numbers = it.third.substring(1, it.third.length-1).split(',')
val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray()
heap.add(it.second, doublearray)
heap.addDoublesArray(it.second, doublearray)
}
in NumericDatatypes -> throw VmExecutionException("invalid heap value type ${it.second}")
else -> throw VmExecutionException("weird datatype")

View File

@ -2,6 +2,7 @@ package prog8.stackvm
import prog8.ast.*
import prog8.compiler.HeapValues
import prog8.compiler.IntegerOrPointerOf
import prog8.compiler.intermediate.Instruction
import prog8.compiler.intermediate.Opcode
import prog8.compiler.intermediate.Value
@ -1602,8 +1603,8 @@ class StackVm(private var traceOutputFile: String?) {
// get indexed byte element from the arrayspec
val array = heap.get(variable.heapId)
when (array.type) {
DataType.ARRAY_UB -> Value(DataType.UBYTE, array.array!![index])
DataType.ARRAY_B -> Value(DataType.BYTE, array.array!![index])
DataType.ARRAY_UB -> Value(DataType.UBYTE, array.array!![index].integer!!)
DataType.ARRAY_B -> Value(DataType.BYTE, array.array!![index].integer!!)
DataType.STR, DataType.STR_S -> Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0])
else -> throw VmExecutionException("not a proper array/string variable with byte elements")
}
@ -1634,8 +1635,14 @@ class StackVm(private var traceOutputFile: String?) {
// get indexed word element from the arrayspec
val array = heap.get(variable.heapId)
when(array.type){
DataType.ARRAY_UW -> Value(DataType.UWORD, array.array!![index])
DataType.ARRAY_W -> Value(DataType.WORD, array.array!![index])
DataType.ARRAY_UW -> {
val value = array.array!![index]
if(value.integer!=null)
Value(DataType.UWORD, value.integer)
else
TODO("deal with pointerTo $value")
}
DataType.ARRAY_W -> Value(DataType.WORD, array.array!![index].integer!!)
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
}
}
@ -1701,8 +1708,8 @@ class StackVm(private var traceOutputFile: String?) {
// set indexed byte element in the arrayspec
val array = heap.get(variable.heapId)
when (array.type) {
DataType.ARRAY_UB -> array.array!![index] = value.integerValue()
DataType.ARRAY_B -> array.array!![index] = value.integerValue()
DataType.ARRAY_UB -> array.array!![index] = IntegerOrPointerOf(value.integerValue(), null)
DataType.ARRAY_B -> array.array!![index] = IntegerOrPointerOf(value.integerValue(), null)
DataType.STR, DataType.STR_S -> {
val chars = array.str!!.toCharArray()
val ps = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0]
@ -1749,8 +1756,8 @@ class StackVm(private var traceOutputFile: String?) {
// set indexed word element in the arrayspec
val array = heap.get(variable.heapId)
when (array.type) {
DataType.ARRAY_UW -> array.array!![index] = value.integerValue()
DataType.ARRAY_W -> array.array!![index] = value.integerValue()
DataType.ARRAY_UW -> array.array!![index] = IntegerOrPointerOf(value.integerValue(), null)
DataType.ARRAY_W -> array.array!![index] = IntegerOrPointerOf(value.integerValue(), null)
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
}
}
@ -2051,92 +2058,130 @@ class StackVm(private var traceOutputFile: String?) {
Syscall.FUNC_MAX_UB -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
val result = value.array.map{it.integer!!}.max() ?: 0
evalstack.push(Value(DataType.UBYTE, result))
}
Syscall.FUNC_MAX_B -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
val result = value.array.map{it.integer!!}.max() ?: 0
evalstack.push(Value(DataType.BYTE, result))
}
Syscall.FUNC_MAX_UW -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
val result = value.array.map{it.integer!!}.max() ?: 0
evalstack.push(Value(DataType.UWORD, result))
}
Syscall.FUNC_MAX_W -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
val result = value.array.map{it.integer!!}.max() ?: 0
evalstack.push(Value(DataType.WORD, result))
}
Syscall.FUNC_MAX_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
// TODO CHECK max(floatarray) correctness
val result = value.doubleArray!!.max() ?: 0.0
evalstack.push(Value(DataType.FLOAT, result))
}
Syscall.FUNC_MIN_UB -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
val result = value.array.map{it.integer!!}.min() ?: 0
evalstack.push(Value(DataType.UBYTE, result))
}
Syscall.FUNC_MIN_B -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
val result = value.array.map{it.integer!!}.min() ?: 0
evalstack.push(Value(DataType.BYTE, result))
}
Syscall.FUNC_MIN_UW -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
val result = value.array.map{it.integer!!}.min() ?: 0
evalstack.push(Value(DataType.UWORD, result))
}
Syscall.FUNC_MIN_W -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
val result = value.array.map{it.integer!!}.min() ?: 0
evalstack.push(Value(DataType.WORD, result))
}
Syscall.FUNC_MIN_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
// TODO check min(floatarray) correctness
val result = value.doubleArray!!.min() ?: 0.0
evalstack.push(Value(DataType.FLOAT, result))
}
Syscall.FUNC_AVG_UB, Syscall.FUNC_AVG_B, Syscall.FUNC_AVG_UW, Syscall.FUNC_AVG_W, Syscall.FUNC_AVG_F -> {
Syscall.FUNC_AVG_UB, Syscall.FUNC_AVG_B, Syscall.FUNC_AVG_UW, Syscall.FUNC_AVG_W -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.FLOAT, value.array!!.average()))
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
evalstack.push(Value(DataType.FLOAT, value.array.map{it.integer!!}.average()))
}
Syscall.FUNC_AVG_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
// TODO check avg(floatarray) correctness
evalstack.push(Value(DataType.FLOAT, value.doubleArray!!.average()))
}
Syscall.FUNC_SUM_UB -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.UWORD, value.array!!.sum()))
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
evalstack.push(Value(DataType.UWORD, value.array.map{it.integer!!}.sum()))
}
Syscall.FUNC_SUM_B -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.WORD, value.array!!.sum()))
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
evalstack.push(Value(DataType.WORD, value.array.map{it.integer!!}.sum()))
}
Syscall.FUNC_SUM_UW, Syscall.FUNC_SUM_W, Syscall.FUNC_SUM_F -> {
Syscall.FUNC_SUM_UW, Syscall.FUNC_SUM_W -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.FLOAT, value.array!!.sum()))
if(value.array!!.any{it.integer==null})
throw VmExecutionException("cannot deal with PointerTo value in array $value")
evalstack.push(Value(DataType.FLOAT, value.array.map{it.integer!!}.sum()))
}
Syscall.FUNC_SUM_F -> {
// TODO check sum(floatarray) correctness
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.FLOAT, value.doubleArray!!.sum()))
}
Syscall.FUNC_ANY_B, Syscall.FUNC_ANY_W, Syscall.FUNC_ANY_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.UBYTE, if (value.array!!.any { v -> v != 0 }) 1 else 0))
evalstack.push(Value(DataType.UBYTE, if (value.array!!.any { v -> v.pointerOf!=null || (v.integer!=null && v.integer != 0) }) 1 else 0))
}
Syscall.FUNC_ALL_B, Syscall.FUNC_ALL_W, Syscall.FUNC_ALL_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.UBYTE, if (value.array!!.all { v -> v != 0 }) 1 else 0))
evalstack.push(Value(DataType.UBYTE, if (value.array!!.all { v -> v.pointerOf!=null || (v.integer!=null && v.integer != 0) }) 1 else 0))
}
Syscall.FUNC_MEMCOPY -> {
val numbytes = evalstack.pop().integerValue()

View File

@ -1,35 +1,48 @@
%zeropage basicsafe
%option enable_floats
%import c64flt
~ main {
sub start() {
ubyte ub='^'
ubyte ub2=7
uword uw=2
uword uw2=5
float fl=2.3
float fl2=20
; TODO what about avg() on floating point array variable!
fl = (ub as float) ** 4
fl = 2.3
fl = fl ** 20.0
c64flt.print_f(fl)
c64.CHROUT('\n')
ubyte[3] array1
ubyte[3] array2
ubyte[3] array3
fl = 2.3
fl = fl ** fl2
c64flt.print_f(fl)
c64.CHROUT('\n')
str string1="hello"
str string2="bye"
fl = 2.3
fl **=20.0
c64flt.print_f(fl)
c64.CHROUT('\n')
uword pointer = &array1
byte bt
pointer = &array2
pointer = &string1
uword[4] pointers = [&array1, &array2, &string1, &string2] ; @todo make it possible to initialize array with pointers
;ptrsubasm("moet werken") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler)
;pointersub("moet werken") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler)
;myprintasm("moet werken3") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler)
ptrsubasm(&array1)
ptrsubasm(&string1)
pointersub(&array1)
pointersub(&string1)
}
sub pointersub(uword arg) {
A=lsb(arg)
}
asmsub ptrsubasm(uword arg @ AY) -> clobbers() -> () {
A=4
}
asmsub myprintasm(str arg @ AY) -> clobbers() -> () {
A=4
}
}

View File

@ -154,6 +154,7 @@ expression :
| scoped_identifier
| arrayindexed
| directmemory
| pointerof
| expression typecast
| '(' expression ')'
;
@ -166,6 +167,8 @@ arrayindexed : scoped_identifier arrayspec ;
directmemory : '@' '(' expression ')';
pointerof : <assoc=right> '&' scoped_identifier ;
functioncall : scoped_identifier '(' expression_list? ')' ;

View File

@ -1,4 +1,4 @@
// Generated from ./parser/antlr/prog8.g4 by ANTLR 4.7.2
// Generated from prog8.g4 by ANTLR 4.7.2
package prog8.parser;

File diff suppressed because it is too large Load Diff