mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
datatype cleanups
This commit is contained in:
parent
95f7c9bad0
commit
2f1249489b
@ -103,9 +103,11 @@ val IterableDatatypes = setOf(
|
|||||||
DataType.ARRAY_UW, DataType.ARRAY_W,
|
DataType.ARRAY_UW, DataType.ARRAY_W,
|
||||||
DataType.ARRAY_F)
|
DataType.ARRAY_F)
|
||||||
|
|
||||||
val StringDatatypes = setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)
|
val ByteDatatypes = setOf(DataType.UBYTE, DataType.BYTE)
|
||||||
val NumericDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT)
|
val WordDatatypes = setOf(DataType.UWORD, DataType.WORD)
|
||||||
val IntegerDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD)
|
val IntegerDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD)
|
||||||
|
val NumericDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT)
|
||||||
|
val StringDatatypes = setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS)
|
||||||
val ArrayDatatypes = setOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F)
|
val ArrayDatatypes = setOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F)
|
||||||
|
|
||||||
|
|
||||||
@ -918,19 +920,19 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
|
|||||||
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
||||||
}
|
}
|
||||||
DataType.BYTE -> when(rightDt) {
|
DataType.BYTE -> when(rightDt) {
|
||||||
DataType.BYTE, DataType.UBYTE -> DataType.BYTE
|
in ByteDatatypes -> DataType.BYTE
|
||||||
DataType.WORD, DataType.UWORD -> DataType.WORD
|
in WordDatatypes -> DataType.WORD
|
||||||
DataType.FLOAT -> DataType.FLOAT
|
DataType.FLOAT -> DataType.FLOAT
|
||||||
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
||||||
}
|
}
|
||||||
DataType.UWORD -> when(rightDt) {
|
DataType.UWORD -> when(rightDt) {
|
||||||
DataType.UBYTE, DataType.UWORD -> DataType.UWORD
|
in ByteDatatypes -> DataType.UWORD
|
||||||
DataType.BYTE, DataType.WORD -> DataType.WORD
|
in WordDatatypes -> DataType.WORD
|
||||||
DataType.FLOAT -> DataType.FLOAT
|
DataType.FLOAT -> DataType.FLOAT
|
||||||
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
||||||
}
|
}
|
||||||
DataType.WORD -> when(rightDt) {
|
DataType.WORD -> when(rightDt) {
|
||||||
DataType.BYTE, DataType.UBYTE, DataType.WORD, DataType.UWORD -> DataType.WORD
|
in IntegerDatatypes -> DataType.WORD
|
||||||
DataType.FLOAT -> DataType.FLOAT
|
DataType.FLOAT -> DataType.FLOAT
|
||||||
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
|
||||||
}
|
}
|
||||||
@ -1073,8 +1075,8 @@ class LiteralValue(val type: DataType,
|
|||||||
|
|
||||||
fun fromNumber(value: Number, type: DataType, position: Position) : LiteralValue {
|
fun fromNumber(value: Number, type: DataType, position: Position) : LiteralValue {
|
||||||
return when(type) {
|
return when(type) {
|
||||||
DataType.UBYTE, DataType.BYTE -> LiteralValue(type, bytevalue = value.toShort(), position = position)
|
in ByteDatatypes -> LiteralValue(type, bytevalue = value.toShort(), position = position)
|
||||||
DataType.UWORD, DataType.WORD -> LiteralValue(type, wordvalue = value.toInt(), position = position)
|
in WordDatatypes -> LiteralValue(type, wordvalue = value.toInt(), position = position)
|
||||||
DataType.FLOAT -> LiteralValue(type, floatvalue = value.toDouble(), position = position)
|
DataType.FLOAT -> LiteralValue(type, floatvalue = value.toDouble(), position = position)
|
||||||
else -> throw FatalAstException("non numeric datatype")
|
else -> throw FatalAstException("non numeric datatype")
|
||||||
}
|
}
|
||||||
@ -1110,8 +1112,8 @@ class LiteralValue(val type: DataType,
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
when(type){
|
when(type){
|
||||||
DataType.UBYTE, DataType.BYTE -> if(bytevalue==null) throw FatalAstException("literal value missing bytevalue")
|
in ByteDatatypes -> if(bytevalue==null) throw FatalAstException("literal value missing bytevalue")
|
||||||
DataType.UWORD, DataType.WORD -> if(wordvalue==null) throw FatalAstException("literal value missing wordvalue")
|
in WordDatatypes -> if(wordvalue==null) throw FatalAstException("literal value missing wordvalue")
|
||||||
DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
|
DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
|
||||||
in StringDatatypes ->
|
in StringDatatypes ->
|
||||||
if(initialstrvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
|
if(initialstrvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
|
||||||
|
@ -830,6 +830,19 @@ private class AstChecker(private val namespace: INameScope,
|
|||||||
if (arg.first.value !is LiteralValue && arg.first.value !is IdentifierReference)
|
if (arg.first.value !is LiteralValue && arg.first.value !is IdentifierReference)
|
||||||
printWarning("calling a subroutine that expects X as a parameter is problematic, more so when providing complex arguments. If you see a compiler error/crash about this later, try to simplify this call", position)
|
printWarning("calling a subroutine that expects X as a parameter is problematic, more so when providing complex arguments. If you see a compiler error/crash about this later, try to simplify this call", position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if the argument types match the register(pairs)
|
||||||
|
val asmParamReg = target.asmParameterRegisters[arg.first.index]
|
||||||
|
if(asmParamReg.statusflag!=null) {
|
||||||
|
if(argDt !in ByteDatatypes)
|
||||||
|
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be byte type for statusflag", position))
|
||||||
|
} else if(asmParamReg.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) {
|
||||||
|
if(argDt !in ByteDatatypes)
|
||||||
|
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be byte type for single register", position))
|
||||||
|
} else if(asmParamReg.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
||||||
|
if(argDt !in WordDatatypes+ IterableDatatypes)
|
||||||
|
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be word type for register pair", position))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -954,8 +967,8 @@ private class AstChecker(private val namespace: INameScope,
|
|||||||
when (targetDt) {
|
when (targetDt) {
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
val number = when(value.type) {
|
val number = when(value.type) {
|
||||||
DataType.UBYTE, DataType.BYTE -> value.bytevalue!!.toDouble()
|
in ByteDatatypes -> value.bytevalue!!.toDouble()
|
||||||
DataType.UWORD, DataType.WORD -> value.wordvalue!!.toDouble()
|
in WordDatatypes -> value.wordvalue!!.toDouble()
|
||||||
DataType.FLOAT -> value.floatvalue!!
|
DataType.FLOAT -> value.floatvalue!!
|
||||||
else -> return err("numeric value expected")
|
else -> return err("numeric value expected")
|
||||||
}
|
}
|
||||||
|
@ -237,12 +237,11 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
|
|
||||||
private fun opcodePush(dt: DataType): Opcode {
|
private fun opcodePush(dt: DataType): Opcode {
|
||||||
return when (dt) {
|
return when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_BYTE
|
in ByteDatatypes -> Opcode.PUSH_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.PUSH_WORD
|
in WordDatatypes -> Opcode.PUSH_WORD
|
||||||
|
in IterableDatatypes -> Opcode.PUSH_WORD
|
||||||
DataType.FLOAT -> Opcode.PUSH_FLOAT
|
DataType.FLOAT -> Opcode.PUSH_FLOAT
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
else -> throw CompilerException("invalid dt $dt")
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
|
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_WORD
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,12 +279,11 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
|
|
||||||
private fun opcodePushvar(dt: DataType): Opcode {
|
private fun opcodePushvar(dt: DataType): Opcode {
|
||||||
return when (dt) {
|
return when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_VAR_BYTE
|
in ByteDatatypes -> Opcode.PUSH_VAR_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.PUSH_VAR_WORD
|
in WordDatatypes -> Opcode.PUSH_VAR_WORD
|
||||||
|
in IterableDatatypes -> Opcode.PUSH_ADDR_HEAPVAR
|
||||||
DataType.FLOAT -> Opcode.PUSH_VAR_FLOAT
|
DataType.FLOAT -> Opcode.PUSH_VAR_FLOAT
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
else -> throw CompilerException("invalid dt $dt")
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
|
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_ADDR_HEAPVAR
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,34 +311,31 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
|
|
||||||
private fun opcodeDiscard(dt: DataType): Opcode {
|
private fun opcodeDiscard(dt: DataType): Opcode {
|
||||||
return when(dt) {
|
return when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.DISCARD_BYTE
|
in ByteDatatypes -> Opcode.DISCARD_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.DISCARD_WORD
|
in WordDatatypes -> Opcode.DISCARD_WORD
|
||||||
|
in IterableDatatypes -> Opcode.DISCARD_WORD
|
||||||
DataType.FLOAT -> Opcode.DISCARD_FLOAT
|
DataType.FLOAT -> Opcode.DISCARD_FLOAT
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
else -> throw CompilerException("invalid dt $dt")
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
|
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.DISCARD_WORD
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun opcodePopvar(dt: DataType): Opcode {
|
private fun opcodePopvar(dt: DataType): Opcode {
|
||||||
return when (dt) {
|
return when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.POP_VAR_BYTE
|
in ByteDatatypes -> Opcode.POP_VAR_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.POP_VAR_WORD
|
in WordDatatypes -> Opcode.POP_VAR_WORD
|
||||||
|
in IterableDatatypes -> Opcode.POP_VAR_WORD
|
||||||
DataType.FLOAT -> Opcode.POP_VAR_FLOAT
|
DataType.FLOAT -> Opcode.POP_VAR_FLOAT
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
else -> throw CompilerException("invalid dt $dt")
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
|
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.POP_VAR_WORD
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun opcodePopmem(dt: DataType): Opcode {
|
private fun opcodePopmem(dt: DataType): Opcode {
|
||||||
return when (dt) {
|
return when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.POP_MEM_BYTE
|
in ByteDatatypes -> Opcode.POP_MEM_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.POP_MEM_WORD
|
in WordDatatypes -> Opcode.POP_MEM_WORD
|
||||||
|
in IterableDatatypes -> Opcode.POP_MEM_WORD
|
||||||
DataType.FLOAT -> Opcode.POP_MEM_FLOAT
|
DataType.FLOAT -> Opcode.POP_MEM_FLOAT
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
else -> throw CompilerException("invalid dt $dt")
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
|
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.POP_MEM_WORD
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,8 +512,8 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
if(trueGoto!=null) {
|
if(trueGoto!=null) {
|
||||||
// optimization for if (condition) goto ....
|
// optimization for if (condition) goto ....
|
||||||
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ
|
in ByteDatatypes -> Opcode.JNZ
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.JNZW
|
in WordDatatypes -> Opcode.JNZW
|
||||||
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
||||||
}
|
}
|
||||||
translate(trueGoto, conditionJumpOpcode)
|
translate(trueGoto, conditionJumpOpcode)
|
||||||
@ -527,8 +522,8 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.JZ
|
in ByteDatatypes -> Opcode.JZ
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.JZW
|
in WordDatatypes -> Opcode.JZW
|
||||||
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
||||||
}
|
}
|
||||||
val labelEnd = makeLabel("end")
|
val labelEnd = makeLabel("end")
|
||||||
@ -573,8 +568,8 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
}
|
}
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
when(rightDt) {
|
when(rightDt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> DataType.BYTE
|
in ByteDatatypes -> DataType.BYTE
|
||||||
DataType.UWORD, DataType.WORD -> DataType.WORD
|
in WordDatatypes -> DataType.WORD
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
printWarning(floatWarning, leftpos)
|
printWarning(floatWarning, leftpos)
|
||||||
DataType.FLOAT
|
DataType.FLOAT
|
||||||
@ -662,20 +657,20 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
else -> {
|
else -> {
|
||||||
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
|
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
|
||||||
when(lv.type) {
|
when(lv.type) {
|
||||||
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.PUSH_BYTE, Value(lv.type, lv.bytevalue!!))
|
in ByteDatatypes -> prog.instr(Opcode.PUSH_BYTE, Value(lv.type, lv.bytevalue!!))
|
||||||
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.wordvalue!!))
|
in WordDatatypes -> prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.wordvalue!!))
|
||||||
DataType.FLOAT -> prog.instr(Opcode.PUSH_FLOAT, Value(lv.type, lv.floatvalue!!))
|
DataType.FLOAT -> prog.instr(Opcode.PUSH_FLOAT, Value(lv.type, lv.floatvalue!!))
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
in StringDatatypes -> {
|
||||||
if(lv.heapId==null)
|
if(lv.heapId==null)
|
||||||
throw CompilerException("string should have been moved into heap ${lv.position}")
|
throw CompilerException("string should have been moved into heap ${lv.position}")
|
||||||
TODO("push address of string with PUSH_ADDR_HEAPVAR")
|
TODO("push address of string with PUSH_ADDR_HEAPVAR")
|
||||||
}
|
}
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
|
in ArrayDatatypes -> {
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W -> {
|
|
||||||
if(lv.heapId==null)
|
if(lv.heapId==null)
|
||||||
throw CompilerException("array should have been moved into heap ${lv.position}")
|
throw CompilerException("array should have been moved into heap ${lv.position}")
|
||||||
TODO("push address of array with PUSH_WORD")
|
TODO("push address of array with PUSH_WORD")
|
||||||
}
|
}
|
||||||
|
else -> throw CompilerException("weird datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,12 +709,12 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
DataType.UWORD -> when(targetDt) {
|
DataType.UWORD -> when(targetDt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> throw CompilerException("narrowing type")
|
in ByteDatatypes -> throw CompilerException("narrowing type")
|
||||||
DataType.FLOAT -> prog.instr(Opcode.CAST_UW_TO_F)
|
DataType.FLOAT -> prog.instr(Opcode.CAST_UW_TO_F)
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
DataType.WORD -> when(targetDt) {
|
DataType.WORD -> when(targetDt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> throw CompilerException("narrowing type")
|
in ByteDatatypes -> throw CompilerException("narrowing type")
|
||||||
DataType.FLOAT -> prog.instr(Opcode.CAST_W_TO_F)
|
DataType.FLOAT -> prog.instr(Opcode.CAST_W_TO_F)
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
@ -893,12 +888,12 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
val arg = args.single()
|
val arg = args.single()
|
||||||
val dt = arg.resultingDatatype(namespace, heap)
|
val dt = arg.resultingDatatype(namespace, heap)
|
||||||
when (dt) {
|
when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.SHL_BYTE)
|
in ByteDatatypes -> prog.instr(Opcode.SHL_BYTE)
|
||||||
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.SHL_WORD)
|
in WordDatatypes -> prog.instr(Opcode.SHL_WORD)
|
||||||
else -> throw CompilerException("wrong datatype")
|
else -> throw CompilerException("wrong datatype")
|
||||||
}
|
}
|
||||||
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
||||||
popValueIntoTarget(AssignTarget.fromExpr(arg), dt)
|
popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
|
||||||
}
|
}
|
||||||
"lsr" -> {
|
"lsr" -> {
|
||||||
val arg = args.single()
|
val arg = args.single()
|
||||||
@ -928,34 +923,34 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
val arg = args.single()
|
val arg = args.single()
|
||||||
val dt = arg.resultingDatatype(namespace, heap)
|
val dt = arg.resultingDatatype(namespace, heap)
|
||||||
when (dt) {
|
when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROR_BYTE)
|
in ByteDatatypes -> prog.instr(Opcode.ROR_BYTE)
|
||||||
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROR_WORD)
|
in WordDatatypes -> prog.instr(Opcode.ROR_WORD)
|
||||||
else -> throw CompilerException("wrong datatype")
|
else -> throw CompilerException("wrong datatype")
|
||||||
}
|
}
|
||||||
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
||||||
popValueIntoTarget(AssignTarget.fromExpr(arg), dt)
|
popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
|
||||||
}
|
}
|
||||||
"rol2" -> {
|
"rol2" -> {
|
||||||
val arg = args.single()
|
val arg = args.single()
|
||||||
val dt = arg.resultingDatatype(namespace, heap)
|
val dt = arg.resultingDatatype(namespace, heap)
|
||||||
when (dt) {
|
when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROL2_BYTE)
|
in ByteDatatypes -> prog.instr(Opcode.ROL2_BYTE)
|
||||||
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROL2_WORD)
|
in WordDatatypes -> prog.instr(Opcode.ROL2_WORD)
|
||||||
else -> throw CompilerException("wrong datatype")
|
else -> throw CompilerException("wrong datatype")
|
||||||
}
|
}
|
||||||
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
||||||
popValueIntoTarget(AssignTarget.fromExpr(arg), dt)
|
popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
|
||||||
}
|
}
|
||||||
"ror2" -> {
|
"ror2" -> {
|
||||||
val arg = args.single()
|
val arg = args.single()
|
||||||
val dt = arg.resultingDatatype(namespace, heap)
|
val dt = arg.resultingDatatype(namespace, heap)
|
||||||
when (dt) {
|
when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROR2_BYTE)
|
in ByteDatatypes -> prog.instr(Opcode.ROR2_BYTE)
|
||||||
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROR2_WORD)
|
in WordDatatypes -> prog.instr(Opcode.ROR2_WORD)
|
||||||
else -> throw CompilerException("wrong datatype")
|
else -> throw CompilerException("wrong datatype")
|
||||||
}
|
}
|
||||||
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
||||||
popValueIntoTarget(AssignTarget.fromExpr(arg), dt)
|
popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
|
||||||
}
|
}
|
||||||
"set_carry" -> prog.instr(Opcode.SEC)
|
"set_carry" -> prog.instr(Opcode.SEC)
|
||||||
"clear_carry" -> prog.instr(Opcode.CLC)
|
"clear_carry" -> prog.instr(Opcode.CLC)
|
||||||
@ -1116,7 +1111,7 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
translate(assignA)
|
translate(assignA)
|
||||||
translate(assignY)
|
translate(assignY)
|
||||||
}
|
}
|
||||||
DataType.UWORD, DataType.WORD -> {
|
in WordDatatypes -> {
|
||||||
translate(arg.first)
|
translate(arg.first)
|
||||||
prog.instr(Opcode.POP_REGAY_WORD)
|
prog.instr(Opcode.POP_REGAY_WORD)
|
||||||
}
|
}
|
||||||
@ -1249,43 +1244,43 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
}
|
}
|
||||||
"&" -> {
|
"&" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.BITAND_BYTE
|
in ByteDatatypes -> Opcode.BITAND_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.BITAND_WORD
|
in WordDatatypes -> Opcode.BITAND_WORD
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"|" -> {
|
"|" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.BITOR_BYTE
|
in ByteDatatypes -> Opcode.BITOR_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.BITOR_WORD
|
in WordDatatypes -> Opcode.BITOR_WORD
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"^" -> {
|
"^" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.BITXOR_BYTE
|
in ByteDatatypes -> Opcode.BITXOR_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.BITXOR_WORD
|
in WordDatatypes -> Opcode.BITXOR_WORD
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"and" -> {
|
"and" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.AND_BYTE
|
in ByteDatatypes -> Opcode.AND_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.AND_WORD
|
in WordDatatypes -> Opcode.AND_WORD
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"or" -> {
|
"or" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.OR_BYTE
|
in ByteDatatypes -> Opcode.OR_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.OR_WORD
|
in WordDatatypes -> Opcode.OR_WORD
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"xor" -> {
|
"xor" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.XOR_BYTE
|
in ByteDatatypes -> Opcode.XOR_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.XOR_WORD
|
in WordDatatypes -> Opcode.XOR_WORD
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1331,16 +1326,16 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
}
|
}
|
||||||
"==" -> {
|
"==" -> {
|
||||||
when (dt) {
|
when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.EQUAL_BYTE
|
in ByteDatatypes -> Opcode.EQUAL_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.EQUAL_WORD
|
in WordDatatypes -> Opcode.EQUAL_WORD
|
||||||
DataType.FLOAT -> Opcode.EQUAL_F
|
DataType.FLOAT -> Opcode.EQUAL_F
|
||||||
else -> throw CompilerException("only byte/word/lfoat possible")
|
else -> throw CompilerException("only byte/word/lfoat possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"!=" -> {
|
"!=" -> {
|
||||||
when (dt) {
|
when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.NOTEQUAL_BYTE
|
in ByteDatatypes -> Opcode.NOTEQUAL_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.NOTEQUAL_WORD
|
in WordDatatypes -> Opcode.NOTEQUAL_WORD
|
||||||
DataType.FLOAT -> Opcode.NOTEQUAL_F
|
DataType.FLOAT -> Opcode.NOTEQUAL_F
|
||||||
else -> throw CompilerException("only byte/word/lfoat possible")
|
else -> throw CompilerException("only byte/word/lfoat possible")
|
||||||
}
|
}
|
||||||
@ -1371,8 +1366,8 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
}
|
}
|
||||||
} else if(operator=="<<") {
|
} else if(operator=="<<") {
|
||||||
when (leftDt) {
|
when (leftDt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.SHIFTEDL_BYTE)
|
in ByteDatatypes -> prog.instr(Opcode.SHIFTEDL_BYTE)
|
||||||
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.SHIFTEDL_WORD)
|
in WordDatatypes -> prog.instr(Opcode.SHIFTEDL_WORD)
|
||||||
else -> throw CompilerException("wrong datatype")
|
else -> throw CompilerException("wrong datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1395,15 +1390,15 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
}
|
}
|
||||||
"~" -> {
|
"~" -> {
|
||||||
when(operandDt) {
|
when(operandDt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.INV_BYTE
|
in ByteDatatypes -> Opcode.INV_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.INV_WORD
|
in WordDatatypes -> Opcode.INV_WORD
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"not" -> {
|
"not" -> {
|
||||||
when(operandDt) {
|
when(operandDt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.NOT_BYTE
|
in ByteDatatypes -> Opcode.NOT_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.NOT_WORD
|
in WordDatatypes -> Opcode.NOT_WORD
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1514,7 +1509,7 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
// convert value to target datatype if possible
|
// convert value to target datatype if possible
|
||||||
// @todo use convertType()????
|
// @todo use convertType()????
|
||||||
when(targetDt) {
|
when(targetDt) {
|
||||||
DataType.UBYTE, DataType.BYTE ->
|
in ByteDatatypes ->
|
||||||
if(valueDt!=DataType.BYTE && valueDt!=DataType.UBYTE)
|
if(valueDt!=DataType.BYTE && valueDt!=DataType.UBYTE)
|
||||||
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||||
DataType.WORD -> {
|
DataType.WORD -> {
|
||||||
@ -1550,9 +1545,9 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
in StringDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
in ArrayDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||||
null -> throw CompilerException("could not determine targetdt")
|
else -> throw CompilerException("weird/unknonwn targetdt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1787,9 +1782,7 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
|
|
||||||
val numElements: Int
|
val numElements: Int
|
||||||
when(iterableValue.type) {
|
when(iterableValue.type) {
|
||||||
DataType.UBYTE, DataType.BYTE,
|
!in IterableDatatypes -> throw CompilerException("non-iterableValue type")
|
||||||
DataType.UWORD, DataType.WORD,
|
|
||||||
DataType.FLOAT -> throw CompilerException("non-iterableValue type")
|
|
||||||
DataType.STR_P, DataType.STR_PS -> throw CompilerException("can't iterate string type ${iterableValue.type}")
|
DataType.STR_P, DataType.STR_PS -> throw CompilerException("can't iterate string type ${iterableValue.type}")
|
||||||
DataType.STR, DataType.STR_S -> {
|
DataType.STR, DataType.STR_S -> {
|
||||||
numElements = iterableValue.strvalue(heap).length
|
numElements = iterableValue.strvalue(heap).length
|
||||||
@ -1804,6 +1797,7 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).arraysize
|
numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).arraysize
|
||||||
if(numElements>255) throw CompilerException("string length > 255")
|
if(numElements>255) throw CompilerException("string length > 255")
|
||||||
}
|
}
|
||||||
|
else -> throw CompilerException("weird datatype")
|
||||||
}
|
}
|
||||||
|
|
||||||
if(loop.loopRegister!=null && loop.loopRegister==Register.X)
|
if(loop.loopRegister!=null && loop.loopRegister==Register.X)
|
||||||
@ -2053,8 +2047,8 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
}
|
}
|
||||||
// TODO: optimize this to use a compare + branch opcode somehow?
|
// TODO: optimize this to use a compare + branch opcode somehow?
|
||||||
val conditionJumpOpcode = when(targetStatement!!.datatype) {
|
val conditionJumpOpcode = when(targetStatement!!.datatype) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ
|
in ByteDatatypes -> Opcode.JNZ
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.JNZW
|
in WordDatatypes -> Opcode.JNZW
|
||||||
else -> throw CompilerException("invalid loopvar datatype (expected byte or word) $lvTarget")
|
else -> throw CompilerException("invalid loopvar datatype (expected byte or word) $lvTarget")
|
||||||
}
|
}
|
||||||
prog.instr(conditionJumpOpcode, callLabel = loopLabel)
|
prog.instr(conditionJumpOpcode, callLabel = loopLabel)
|
||||||
@ -2105,8 +2099,8 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
prog.label(continueLabel)
|
prog.label(continueLabel)
|
||||||
translate(stmt.condition)
|
translate(stmt.condition)
|
||||||
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ
|
in ByteDatatypes -> Opcode.JNZ
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.JNZW
|
in WordDatatypes -> Opcode.JNZW
|
||||||
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
||||||
}
|
}
|
||||||
prog.instr(conditionJumpOpcode, callLabel = loopLabel)
|
prog.instr(conditionJumpOpcode, callLabel = loopLabel)
|
||||||
@ -2142,8 +2136,8 @@ internal class Compiler(private val rootModule: Module,
|
|||||||
prog.label(continueLabel)
|
prog.label(continueLabel)
|
||||||
translate(stmt.untilCondition)
|
translate(stmt.untilCondition)
|
||||||
val conditionJumpOpcode = when(stmt.untilCondition.resultingDatatype(namespace, heap)) {
|
val conditionJumpOpcode = when(stmt.untilCondition.resultingDatatype(namespace, heap)) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.JZ
|
in ByteDatatypes -> Opcode.JZ
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.JZW
|
in WordDatatypes -> Opcode.JZW
|
||||||
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
||||||
}
|
}
|
||||||
prog.instr(conditionJumpOpcode, callLabel = loopLabel)
|
prog.instr(conditionJumpOpcode, callLabel = loopLabel)
|
||||||
|
@ -20,8 +20,8 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
|||||||
|
|
||||||
val size =
|
val size =
|
||||||
when (datatype) {
|
when (datatype) {
|
||||||
DataType.UBYTE, DataType.BYTE -> 1
|
in ByteDatatypes -> 1
|
||||||
DataType.UWORD, DataType.WORD -> 2
|
in WordDatatypes -> 2
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
if (options.floats) {
|
if (options.floats) {
|
||||||
if(position!=null)
|
if(position!=null)
|
||||||
|
@ -389,20 +389,20 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
|||||||
when(decl.type) {
|
when(decl.type) {
|
||||||
VarDeclType.VAR -> {
|
VarDeclType.VAR -> {
|
||||||
val value = when(decl.datatype) {
|
val value = when(decl.datatype) {
|
||||||
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!)
|
in NumericDatatypes -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!)
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
in StringDatatypes -> {
|
||||||
val litval = (decl.value as LiteralValue)
|
val litval = (decl.value as LiteralValue)
|
||||||
if(litval.heapId==null)
|
if(litval.heapId==null)
|
||||||
throw CompilerException("string should already be in the heap")
|
throw CompilerException("string should already be in the heap")
|
||||||
Value(decl.datatype, litval.heapId)
|
Value(decl.datatype, litval.heapId)
|
||||||
}
|
}
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W,
|
in ArrayDatatypes -> {
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F -> {
|
|
||||||
val litval = (decl.value as LiteralValue)
|
val litval = (decl.value as LiteralValue)
|
||||||
if(litval.heapId==null)
|
if(litval.heapId==null)
|
||||||
throw CompilerException("array should already be in the heap")
|
throw CompilerException("array should already be in the heap")
|
||||||
Value(decl.datatype, litval.heapId)
|
Value(decl.datatype, litval.heapId)
|
||||||
}
|
}
|
||||||
|
else -> throw CompilerException("weird datatype")
|
||||||
}
|
}
|
||||||
currentBlock.variables[scopedname] = value
|
currentBlock.variables[scopedname] = value
|
||||||
if(decl.zeropage)
|
if(decl.zeropage)
|
||||||
|
@ -79,8 +79,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
|
|
||||||
fun numericValue(): Number {
|
fun numericValue(): Number {
|
||||||
return when(type) {
|
return when(type) {
|
||||||
DataType.UBYTE, DataType.BYTE -> byteval!!
|
in ByteDatatypes -> byteval!!
|
||||||
DataType.UWORD, DataType.WORD -> wordval!!
|
in WordDatatypes -> wordval!!
|
||||||
DataType.FLOAT -> floatval!!
|
DataType.FLOAT -> floatval!!
|
||||||
else -> throw ValueException("invalid datatype for numeric value: $type")
|
else -> throw ValueException("invalid datatype for numeric value: $type")
|
||||||
}
|
}
|
||||||
@ -88,8 +88,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
|
|
||||||
fun integerValue(): Int {
|
fun integerValue(): Int {
|
||||||
return when(type) {
|
return when(type) {
|
||||||
DataType.UBYTE, DataType.BYTE -> byteval!!.toInt()
|
in ByteDatatypes -> byteval!!.toInt()
|
||||||
DataType.UWORD, DataType.WORD -> wordval!!
|
in WordDatatypes -> wordval!!
|
||||||
DataType.FLOAT -> throw ValueException("float to integer loss of precision")
|
DataType.FLOAT -> throw ValueException("float to integer loss of precision")
|
||||||
else -> throw ValueException("invalid datatype for integer value: $type")
|
else -> throw ValueException("invalid datatype for integer value: $type")
|
||||||
}
|
}
|
||||||
@ -393,8 +393,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
|
|
||||||
fun msb(): Value {
|
fun msb(): Value {
|
||||||
return when(type) {
|
return when(type) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Value(DataType.UBYTE, 0)
|
in ByteDatatypes -> Value(DataType.UBYTE, 0)
|
||||||
DataType.UWORD, DataType.WORD -> Value(DataType.UBYTE, wordval!! ushr 8 and 255)
|
in WordDatatypes -> Value(DataType.UBYTE, wordval!! ushr 8 and 255)
|
||||||
else -> throw ValueException("msb can only work on (u)byte/(u)word")
|
else -> throw ValueException("msb can only work on (u)byte/(u)word")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -428,7 +428,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
}
|
}
|
||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
when (targetType) {
|
when (targetType) {
|
||||||
DataType.BYTE, DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255)
|
in ByteDatatypes -> Value(DataType.UBYTE, integerValue() and 255)
|
||||||
DataType.UWORD -> this
|
DataType.UWORD -> this
|
||||||
DataType.WORD -> {
|
DataType.WORD -> {
|
||||||
if(integerValue()<=32767)
|
if(integerValue()<=32767)
|
||||||
@ -442,7 +442,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
}
|
}
|
||||||
DataType.WORD -> {
|
DataType.WORD -> {
|
||||||
when (targetType) {
|
when (targetType) {
|
||||||
DataType.BYTE, DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255)
|
in ByteDatatypes -> Value(DataType.UBYTE, integerValue() and 255)
|
||||||
DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535)
|
DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535)
|
||||||
DataType.WORD -> this
|
DataType.WORD -> this
|
||||||
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
|
DataType.FLOAT -> Value(DataType.FLOAT, numericValue())
|
||||||
|
@ -78,7 +78,7 @@ val BuiltinFunctions = mapOf(
|
|||||||
"memset" to FunctionSignature(false, listOf(
|
"memset" to FunctionSignature(false, listOf(
|
||||||
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
|
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
|
||||||
BuiltinFunctionParam("numbytes", setOf(DataType.UWORD)),
|
BuiltinFunctionParam("numbytes", setOf(DataType.UWORD)),
|
||||||
BuiltinFunctionParam("bytevalue", setOf(DataType.UBYTE, DataType.BYTE))), null),
|
BuiltinFunctionParam("bytevalue", ByteDatatypes)), null),
|
||||||
"memsetw" to FunctionSignature(false, listOf(
|
"memsetw" to FunctionSignature(false, listOf(
|
||||||
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
|
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
|
||||||
BuiltinFunctionParam("numwords", setOf(DataType.UWORD)),
|
BuiltinFunctionParam("numwords", setOf(DataType.UWORD)),
|
||||||
@ -126,14 +126,14 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
if(arglist is IdentifierReference) {
|
if(arglist is IdentifierReference) {
|
||||||
val dt = arglist.resultingDatatype(namespace, heap)
|
val dt = arglist.resultingDatatype(namespace, heap)
|
||||||
return when(dt) {
|
return when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT,
|
in NumericDatatypes -> dt!!
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> dt
|
in StringDatatypes -> dt!!
|
||||||
DataType.ARRAY_UB -> DataType.UBYTE
|
DataType.ARRAY_UB -> DataType.UBYTE
|
||||||
DataType.ARRAY_B -> DataType.BYTE
|
DataType.ARRAY_B -> DataType.BYTE
|
||||||
DataType.ARRAY_UW -> DataType.UWORD
|
DataType.ARRAY_UW -> DataType.UWORD
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
DataType.ARRAY_F -> DataType.FLOAT
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
null -> throw FatalAstException("function '$function' requires one argument which is an iterable")
|
else -> throw FatalAstException("function '$function' requires one argument which is an iterable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw FatalAstException("function '$function' requires one argument which is an iterable")
|
throw FatalAstException("function '$function' requires one argument which is an iterable")
|
||||||
@ -148,8 +148,8 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
"abs" -> {
|
"abs" -> {
|
||||||
val dt = args.single().resultingDatatype(namespace, heap)
|
val dt = args.single().resultingDatatype(namespace, heap)
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> DataType.UBYTE
|
in ByteDatatypes -> DataType.UBYTE
|
||||||
DataType.UWORD, DataType.WORD -> DataType.UWORD
|
in WordDatatypes -> DataType.UWORD
|
||||||
DataType.FLOAT -> DataType.FLOAT
|
DataType.FLOAT -> DataType.FLOAT
|
||||||
else -> throw FatalAstException("weird datatype passed to abs $dt")
|
else -> throw FatalAstException("weird datatype passed to abs $dt")
|
||||||
}
|
}
|
||||||
@ -157,13 +157,14 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
"max", "min" -> {
|
"max", "min" -> {
|
||||||
val dt = datatypeFromIterableArg(args.single())
|
val dt = datatypeFromIterableArg(args.single())
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> dt
|
in NumericDatatypes -> dt
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UBYTE
|
in StringDatatypes -> DataType.UBYTE
|
||||||
DataType.ARRAY_UB -> DataType.UBYTE
|
DataType.ARRAY_UB -> DataType.UBYTE
|
||||||
DataType.ARRAY_B -> DataType.BYTE
|
DataType.ARRAY_B -> DataType.BYTE
|
||||||
DataType.ARRAY_UW -> DataType.UWORD
|
DataType.ARRAY_UW -> DataType.UWORD
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
DataType.ARRAY_F -> DataType.FLOAT
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"sum" -> {
|
"sum" -> {
|
||||||
@ -175,7 +176,8 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
DataType.ARRAY_UB, DataType.ARRAY_UW -> DataType.UWORD
|
DataType.ARRAY_UB, DataType.ARRAY_UW -> DataType.UWORD
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_B, DataType.ARRAY_W -> DataType.WORD
|
||||||
DataType.ARRAY_F -> DataType.FLOAT
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UWORD
|
in StringDatatypes -> DataType.UWORD
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"len" -> {
|
"len" -> {
|
||||||
@ -325,15 +327,14 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
|
|||||||
throw CompilerException("array length exceeds byte limit ${argument.position}")
|
throw CompilerException("array length exceeds byte limit ${argument.position}")
|
||||||
LiteralValue.optimalInteger(arraySize, args[0].position)
|
LiteralValue.optimalInteger(arraySize, args[0].position)
|
||||||
}
|
}
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
in StringDatatypes -> {
|
||||||
val str = argument.strvalue(heap)
|
val str = argument.strvalue(heap)
|
||||||
if(str.length>255)
|
if(str.length>255)
|
||||||
throw CompilerException("string length exceeds byte limit ${argument.position}")
|
throw CompilerException("string length exceeds byte limit ${argument.position}")
|
||||||
LiteralValue.optimalInteger(str.length, args[0].position)
|
LiteralValue.optimalInteger(str.length, args[0].position)
|
||||||
}
|
}
|
||||||
DataType.UBYTE, DataType.BYTE,
|
in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position)
|
||||||
DataType.UWORD, DataType.WORD,
|
else -> throw CompilerException("weird datatype")
|
||||||
DataType.FLOAT -> throw SyntaxError("len of weird argument ${args[0]}", position)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package prog8.stackvm
|
package prog8.stackvm
|
||||||
|
|
||||||
import prog8.ast.DataType
|
import prog8.ast.DataType
|
||||||
|
import prog8.ast.NumericDatatypes
|
||||||
import prog8.ast.Position
|
import prog8.ast.Position
|
||||||
import prog8.ast.unescape
|
import prog8.ast.unescape
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
@ -103,7 +104,8 @@ class Program (val name: String,
|
|||||||
val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray()
|
val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray()
|
||||||
heap.add(it.second, doublearray)
|
heap.add(it.second, doublearray)
|
||||||
}
|
}
|
||||||
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("invalid heap value type ${it.second}")
|
in NumericDatatypes -> throw VmExecutionException("invalid heap value type ${it.second}")
|
||||||
|
else -> throw VmExecutionException("weird datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,10 @@ import org.hamcrest.MatcherAssert.assertThat
|
|||||||
import org.hamcrest.Matchers.empty
|
import org.hamcrest.Matchers.empty
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
|
import prog8.ast.ByteDatatypes
|
||||||
import prog8.ast.DataType
|
import prog8.ast.DataType
|
||||||
|
import prog8.ast.IterableDatatypes
|
||||||
|
import prog8.ast.WordDatatypes
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.intermediate.Instruction
|
import prog8.compiler.intermediate.Instruction
|
||||||
import prog8.compiler.intermediate.Opcode
|
import prog8.compiler.intermediate.Opcode
|
||||||
@ -1234,12 +1237,11 @@ class TestStackVmOpcodes {
|
|||||||
|
|
||||||
private fun pushOpcode(dt: DataType): Opcode {
|
private fun pushOpcode(dt: DataType): Opcode {
|
||||||
return when (dt) {
|
return when (dt) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_BYTE
|
in ByteDatatypes -> Opcode.PUSH_BYTE
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.PUSH_WORD
|
in WordDatatypes -> Opcode.PUSH_WORD
|
||||||
|
in IterableDatatypes -> Opcode.PUSH_WORD
|
||||||
DataType.FLOAT -> Opcode.PUSH_FLOAT
|
DataType.FLOAT -> Opcode.PUSH_FLOAT
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
else -> throw IllegalArgumentException("invalid datatype")
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
|
|
||||||
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_WORD
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.7 (py3)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
@ -321,6 +321,11 @@ be set to zero only for the first run of the program. A second run will utilize
|
|||||||
where it left off (but your code will be a bit smaller because no initialization instructions
|
where it left off (but your code will be a bit smaller because no initialization instructions
|
||||||
are generated)
|
are generated)
|
||||||
|
|
||||||
|
.. caution::
|
||||||
|
variables that get allocated in zero-page will *not* have a zero starting value when you omit
|
||||||
|
the variable's initialization. They'll be whatever the last value in that zero page
|
||||||
|
location was. So it's best to don't depend on the uninitialized starting value!
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
this behavior may change in a future version so that subsequent runs always
|
this behavior may change in a future version so that subsequent runs always
|
||||||
use the same initial values
|
use the same initial values
|
||||||
@ -462,11 +467,7 @@ There are various built-in functions such as sin(), cos(), min(), max() that can
|
|||||||
You can also reference idendifiers defined elsewhere in your code.
|
You can also reference idendifiers defined elsewhere in your code.
|
||||||
|
|
||||||
.. attention::
|
.. attention::
|
||||||
**Data type conversion (during calculations) and floating point handling:**
|
**Floating points used in expressions:**
|
||||||
|
|
||||||
BYTE values used in arithmetic expressions (calculations) will be automatically converted into WORD values
|
|
||||||
if the calculation needs that to store the resulting value. Once a WORD value is used, all other results will be WORDs as well
|
|
||||||
(there's no automatic conversion of WORD into BYTE).
|
|
||||||
|
|
||||||
When a floating point value is used in a calculation, the result will be a floating point, and byte or word values
|
When a floating point value is used in a calculation, the result will be a floating point, and byte or word values
|
||||||
will be automatically converted into floats in this case. The compiler will issue a warning though when this happens, because floating
|
will be automatically converted into floats in this case. The compiler will issue a warning though when this happens, because floating
|
||||||
@ -494,6 +495,28 @@ Usually the normal precedence rules apply (``*`` goes before ``+`` etc.) but sub
|
|||||||
within parentheses will be evaluated first. So ``(4 + 8) * 2`` is 24 and not 20,
|
within parentheses will be evaluated first. So ``(4 + 8) * 2`` is 24 and not 20,
|
||||||
and ``(true or false) and false`` is false instead of true.
|
and ``(true or false) and false`` is false instead of true.
|
||||||
|
|
||||||
|
.. attention::
|
||||||
|
**calculations keep their datatype:**
|
||||||
|
When you do calculations on a BYTE type, the result will remain a BYTE.
|
||||||
|
When you do calculations on a WORD type, the result will remain a WORD.
|
||||||
|
For instance::
|
||||||
|
|
||||||
|
byte b = 44
|
||||||
|
word w = b*55 ; the result will be 116! (even though the target variable is a word)
|
||||||
|
w *= 999 ; the result will be -15188 (the multiplication stays within a word)
|
||||||
|
|
||||||
|
The compiler will NOT give a warning about this! It's doing this for
|
||||||
|
performance reasons - so you won't get sudden 16 bit (or even float)
|
||||||
|
calculations where you needed only simple fast byte arithmetic.
|
||||||
|
If you do need the extended resulting value, cast at least one of the
|
||||||
|
operands of an operator to the larger datatype. For example::
|
||||||
|
|
||||||
|
byte b = 44
|
||||||
|
word w = b*55.w ; the result will be 2420
|
||||||
|
w = (b as word)*55 ; same result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Subroutines
|
Subroutines
|
||||||
-----------
|
-----------
|
||||||
|
@ -10,15 +10,24 @@
|
|||||||
memset(sieve, 256, false) ; clear the sieve
|
memset(sieve, 256, false) ; clear the sieve
|
||||||
|
|
||||||
; calculate primes
|
; calculate primes
|
||||||
|
|
||||||
|
; @todo fix this, it misses some primes....
|
||||||
|
|
||||||
|
|
||||||
c64scr.print("prime numbers up to 255:\n\n")
|
c64scr.print("prime numbers up to 255:\n\n")
|
||||||
|
ubyte amount
|
||||||
while true {
|
while true {
|
||||||
ubyte prime = find_next_prime()
|
ubyte prime = find_next_prime()
|
||||||
if prime==0
|
if prime==0
|
||||||
break
|
break
|
||||||
c64scr.print_ub(prime)
|
c64scr.print_ub(prime)
|
||||||
c64scr.print(", ")
|
c64scr.print(", ")
|
||||||
|
amount++
|
||||||
}
|
}
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
|
c64scr.print("amount of primes: ")
|
||||||
|
c64scr.print_ub(amount)
|
||||||
|
c64.CHROUT('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,53 +5,38 @@
|
|||||||
|
|
||||||
; @todo test memset/memcopy (there's a bug in memcopy?)
|
; @todo test memset/memcopy (there's a bug in memcopy?)
|
||||||
|
|
||||||
; @todo see looplabelproblem.p8
|
; @todo see problem in looplabelproblem.p8
|
||||||
|
|
||||||
|
; @todo fix primes.p8 (it misses some primes)
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte xx
|
|
||||||
|
|
||||||
c64scr.print_ub(X)
|
uword ypos=4
|
||||||
|
|
||||||
|
byte bb=44
|
||||||
|
byte bb2
|
||||||
|
word ww=4444
|
||||||
|
word ww2
|
||||||
|
|
||||||
|
bb2 = bb*55
|
||||||
|
ww2 = ww*55
|
||||||
|
|
||||||
|
ww2 = bb * 55.w ; @todo why is this resulting in a byte?
|
||||||
|
ypos += 5000 ; @todo fix "cannot assign word to uword"
|
||||||
|
c64scr.print_w(ww2)
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
ww2 = (bb as word)*55
|
||||||
|
c64scr.print_w(ww2)
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
A=c64scr.getchr(20,1)
|
;
|
||||||
c64scr.print_ub(A)
|
; memset($0400+(ypos+0)*40, 40, 1)
|
||||||
c64.CHROUT('\n')
|
; memset($0400+(ypos+1)*40, 40, 2)
|
||||||
xx=c64scr.getchr(20,1)
|
; memset($0400+(ypos+2)*40, 40, 3)
|
||||||
c64scr.print_ub(xx)
|
; memset($0400+(ypos+3)*40, 40, 4)
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64scr.print_ub(X)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
A=1+c64scr.getchr(20,1)
|
|
||||||
c64scr.print_ub(A)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
xx=1+c64scr.getchr(20,1)
|
|
||||||
c64scr.print_ub(xx)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64scr.print_ub(X)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
A=c64scr.getchr(20,1)+1
|
|
||||||
c64scr.print_ub(A)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
xx=c64scr.getchr(20,1)+1
|
|
||||||
c64scr.print_ub(xx)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64scr.print_ub(X)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
|
;memsetw($0400+(ypos+1)*40, 20, $4455)
|
||||||
|
;memsetw($0400+(ypos+3)*40, 20, $4455)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub asm_routine(ubyte arg1 @ A, ubyte arg2 @ Y) -> clobbers() -> (ubyte @ A) {
|
|
||||||
return A+Y
|
|
||||||
}
|
|
||||||
|
|
||||||
sub drawNext(ubyte x) {
|
|
||||||
A=x
|
|
||||||
}
|
|
||||||
sub drawNextW(uword w) {
|
|
||||||
w++
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user