mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 04:30:03 +00:00
w.i.p pointer-to
This commit is contained in:
parent
3e7e44acfe
commit
1069b5f5d5
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 ""
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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? ')' ;
|
||||
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user