fixed datatype conversions

This commit is contained in:
Irmen de Jong 2018-10-05 17:44:29 +02:00
parent 52e1661c8e
commit 6350bf8024
6 changed files with 111 additions and 55 deletions

View File

@ -27,15 +27,15 @@
yy = flt((pixely-yoffset))/height/3.6+0.4 yy = flt((pixely-yoffset))/height/3.6+0.4
for pixelx in xoffset to xoffset+width-1 { for pixelx in xoffset to xoffset+width-1 {
xx = flt((pixelx-xoffset))/width/3+0.2 xx = flt((pixelx-xoffset))/width/3.0+0.2
x = 0.0 x = 0.0
y = 0.0 y = 0.0
xsquared = 0 xsquared = 0
ysquared = 0 ysquared = 0
iter = 0 iter = 0
while (iter<32 and xsquared+ysquared<4) { while (iter<32 and xsquared+ysquared<4.0) {
y = x*y*2 + yy y = x*y*2.0 + yy
x = xsquared - ysquared + xx x = xsquared - ysquared + xx
xsquared = x*x xsquared = x*x
ysquared = y*y ysquared = y*y

View File

@ -25,9 +25,9 @@
} }
sub screenx(x: float) -> word { sub screenx(x: float) -> word {
return floor(x * width/4.1) + width // 2 return floor(x * flt(width)/4.1) + width // 2 ; @todo const-fold x*y/z
} }
sub screeny(y: float) -> word { sub screeny(y: float) -> word {
return floor(y * height/4.1) + height // 2 return floor(y * flt(height)/4.1) + height // 2 ; @todo const-fold x*y/z
} }
} }

View File

@ -4,22 +4,18 @@
~ main { ~ main {
X=0
word mainvar = 44*Y
return
sub start() { sub start() {
A=99 const byte b1 = 20//7
const word w1 = 20//7
const float f1 = 20/7
byte bvar = 4*X _vm_write_num(b1)
word wvar = 44*XY _vm_write_char('\n')
float fvar = 128.34+XY _vm_write_num(w1)
_vm_write_char('\n')
A=100 _vm_write_num(f1)
_vm_write_char('\n')
return return
} }

View File

@ -521,12 +521,43 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stackvmProg.instr(Opcode.NOP) stackvmProg.instr(Opcode.NOP)
} }
private fun checkForFloatPrecisionProblem(left: IExpression, right: IExpression) { private fun commonDatatype(leftDt: DataType, rightDt: DataType, leftpos: Position, rightpos: Position): DataType {
val leftDt = left.resultingDatatype(namespace, heap) // byte + byte -> byte
val rightDt = right.resultingDatatype(namespace, heap) // byte + word -> word
if (leftDt == DataType.BYTE || leftDt == DataType.WORD) { // word + byte -> word
if(rightDt==DataType.FLOAT) // word + word -> word
printWarning("byte or word value implicitly converted to float. Suggestion: use explicit flt() conversion or revert to byte/word arithmetic", left.position) // a combination with a float will be float (but give a warning about this!)
val floatWarning = "byte or word value implicitly converted to float. Suggestion: use explicit flt() conversion, a float number, or revert to byte/word arithmetic"
return when(leftDt) {
DataType.BYTE -> {
when(rightDt) {
DataType.BYTE -> DataType.BYTE
DataType.WORD -> DataType.WORD
DataType.FLOAT -> {
printWarning(floatWarning, leftpos)
DataType.FLOAT
}
else -> throw CompilerException("non-numeric datatype $rightDt")
}
}
DataType.WORD -> {
when(rightDt) {
DataType.BYTE, DataType.WORD -> DataType.WORD
DataType.FLOAT -> {
printWarning(floatWarning, leftpos)
DataType.FLOAT
}
else -> throw CompilerException("non-numeric datatype $rightDt")
}
}
DataType.FLOAT -> {
if(rightDt!=DataType.FLOAT)
printWarning(floatWarning, rightpos)
DataType.FLOAT
}
else -> throw CompilerException("non-numeric datatype $leftDt")
} }
} }
@ -541,10 +572,16 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
translatePrefixOperator(expr.operator, expr.expression.resultingDatatype(namespace, heap)) translatePrefixOperator(expr.operator, expr.expression.resultingDatatype(namespace, heap))
} }
is BinaryExpression -> { is BinaryExpression -> {
checkForFloatPrecisionProblem(expr.left, expr.right) val leftDt = expr.left.resultingDatatype(namespace, heap)!!
val rightDt = expr.right.resultingDatatype(namespace, heap)!!
val commonDt = commonDatatype(leftDt, rightDt, expr.left.position, expr.right.position)
translate(expr.left) translate(expr.left)
if(leftDt!=commonDt)
convertType(leftDt, commonDt)
translate(expr.right) translate(expr.right)
translateBinaryOperator(expr.operator, expr.left.resultingDatatype(namespace, heap), expr.right.resultingDatatype(namespace, heap)) if(rightDt!=commonDt)
convertType(rightDt, commonDt)
translateBinaryOperator(expr.operator, commonDt)
} }
is FunctionCall -> { is FunctionCall -> {
val target = expr.target.targetStatement(namespace) val target = expr.target.targetStatement(namespace)
@ -586,6 +623,33 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
private fun convertType(givenDt: DataType, targetDt: DataType) {
// only WIDENS a type, never NARROWS
if(givenDt==targetDt)
return
if(givenDt!=DataType.BYTE && givenDt!=DataType.WORD && givenDt!=DataType.FLOAT)
throw CompilerException("converting a non-numeric $givenDt")
if(targetDt!=DataType.BYTE && targetDt!=DataType.WORD && targetDt!=DataType.FLOAT)
throw CompilerException("converting to non-numeric $targetDt")
when(givenDt) {
DataType.BYTE -> when(targetDt) {
DataType.WORD -> stackvmProg.instr(Opcode.B2WORD)
DataType.FLOAT -> stackvmProg.instr(Opcode.B2FLOAT)
else -> {}
}
DataType.WORD -> when(targetDt) {
DataType.BYTE -> throw CompilerException("narrowing type")
DataType.FLOAT -> stackvmProg.instr(Opcode.W2FLOAT)
else -> {}
}
DataType.FLOAT -> when(targetDt) {
DataType.BYTE, DataType.WORD -> throw CompilerException("narrowing type")
else -> {}
}
else -> {}
}
}
private fun translate(identifierRef: IdentifierReference) { private fun translate(identifierRef: IdentifierReference) {
val target = identifierRef.targetStatement(namespace) val target = identifierRef.targetStatement(namespace)
when (target) { when (target) {
@ -720,17 +784,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname) stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname)
} }
private fun translateBinaryOperator(operator: String, leftDt: DataType?, rightDt: DataType?) { private fun translateBinaryOperator(operator: String, dt: DataType) {
if(leftDt==null || rightDt==null)
throw CompilerException("left and/or right operand datatype not known")
val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
if(leftDt !in validDt || rightDt !in validDt) if(dt !in validDt)
throw CompilerException("invalid datatype(s) for operand(s)") throw CompilerException("invalid datatype for operator: $dt")
if(leftDt!=rightDt)
throw CompilerException("operands have different datatypes")
val opcode = when(operator) { val opcode = when(operator) {
"+" -> { "+" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.ADD_B DataType.BYTE -> Opcode.ADD_B
DataType.WORD -> Opcode.ADD_W DataType.WORD -> Opcode.ADD_W
DataType.FLOAT -> Opcode.ADD_F DataType.FLOAT -> Opcode.ADD_F
@ -738,7 +798,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"-" -> { "-" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.SUB_B DataType.BYTE -> Opcode.SUB_B
DataType.WORD -> Opcode.SUB_W DataType.WORD -> Opcode.SUB_W
DataType.FLOAT -> Opcode.SUB_F DataType.FLOAT -> Opcode.SUB_F
@ -746,7 +806,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"*" -> { "*" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.MUL_B DataType.BYTE -> Opcode.MUL_B
DataType.WORD -> Opcode.MUL_W DataType.WORD -> Opcode.MUL_W
DataType.FLOAT -> Opcode.MUL_F DataType.FLOAT -> Opcode.MUL_F
@ -754,7 +814,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"/" -> { "/" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.DIV_B DataType.BYTE -> Opcode.DIV_B
DataType.WORD -> Opcode.DIV_W DataType.WORD -> Opcode.DIV_W
DataType.FLOAT -> Opcode.DIV_F DataType.FLOAT -> Opcode.DIV_F
@ -762,7 +822,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"//" -> { "//" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.FLOORDIV_B DataType.BYTE -> Opcode.FLOORDIV_B
DataType.WORD -> Opcode.FLOORDIV_W DataType.WORD -> Opcode.FLOORDIV_W
DataType.FLOAT -> Opcode.FLOORDIV_F DataType.FLOAT -> Opcode.FLOORDIV_F
@ -770,7 +830,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"%" -> { "%" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.REMAINDER_B DataType.BYTE -> Opcode.REMAINDER_B
DataType.WORD -> Opcode.REMAINDER_W DataType.WORD -> Opcode.REMAINDER_W
DataType.FLOAT -> Opcode.REMAINDER_F DataType.FLOAT -> Opcode.REMAINDER_F
@ -778,7 +838,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"**" -> { "**" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.POW_B DataType.BYTE -> Opcode.POW_B
DataType.WORD -> Opcode.POW_W DataType.WORD -> Opcode.POW_W
DataType.FLOAT -> Opcode.POW_F DataType.FLOAT -> Opcode.POW_F
@ -786,49 +846,49 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"&" -> { "&" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.BITAND DataType.BYTE -> Opcode.BITAND
DataType.WORD -> Opcode.BITAND_W DataType.WORD -> Opcode.BITAND_W
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"|" -> { "|" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.BITOR DataType.BYTE -> Opcode.BITOR
DataType.WORD -> Opcode.BITOR_W DataType.WORD -> Opcode.BITOR_W
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"^" -> { "^" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.BITXOR DataType.BYTE -> Opcode.BITXOR
DataType.WORD -> Opcode.BITXOR_W DataType.WORD -> Opcode.BITXOR_W
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"and" -> { "and" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.AND DataType.BYTE -> Opcode.AND
DataType.WORD -> Opcode.AND_W DataType.WORD -> Opcode.AND_W
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"or" -> { "or" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.OR DataType.BYTE -> Opcode.OR
DataType.WORD -> Opcode.OR_W DataType.WORD -> Opcode.OR_W
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"xor" -> { "xor" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.XOR DataType.BYTE -> Opcode.XOR
DataType.WORD -> Opcode.XOR_W DataType.WORD -> Opcode.XOR_W
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"<" -> { "<" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.LESS DataType.BYTE -> Opcode.LESS
DataType.WORD -> Opcode.LESS_W DataType.WORD -> Opcode.LESS_W
DataType.FLOAT -> Opcode.LESS_F DataType.FLOAT -> Opcode.LESS_F
@ -836,7 +896,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
">" -> { ">" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.GREATER DataType.BYTE -> Opcode.GREATER
DataType.WORD -> Opcode.GREATER_W DataType.WORD -> Opcode.GREATER_W
DataType.FLOAT -> Opcode.GREATER_F DataType.FLOAT -> Opcode.GREATER_F
@ -844,7 +904,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"<=" -> { "<=" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.LESSEQ DataType.BYTE -> Opcode.LESSEQ
DataType.WORD -> Opcode.LESSEQ_W DataType.WORD -> Opcode.LESSEQ_W
DataType.FLOAT -> Opcode.LESSEQ_F DataType.FLOAT -> Opcode.LESSEQ_F
@ -852,7 +912,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
">=" -> { ">=" -> {
when(leftDt) { when(dt) {
DataType.BYTE -> Opcode.GREATEREQ DataType.BYTE -> Opcode.GREATEREQ
DataType.WORD -> Opcode.GREATEREQ_W DataType.WORD -> Opcode.GREATEREQ_W
DataType.FLOAT -> Opcode.GREATEREQ_F DataType.FLOAT -> Opcode.GREATEREQ_F
@ -860,7 +920,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"==" -> { "==" -> {
when (leftDt) { when (dt) {
DataType.BYTE -> Opcode.EQUAL DataType.BYTE -> Opcode.EQUAL
DataType.WORD -> Opcode.EQUAL_W DataType.WORD -> Opcode.EQUAL_W
DataType.FLOAT -> Opcode.EQUAL_F DataType.FLOAT -> Opcode.EQUAL_F
@ -868,7 +928,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
"!=" -> { "!=" -> {
when (leftDt) { when (dt) {
DataType.BYTE -> Opcode.NOTEQUAL DataType.BYTE -> Opcode.NOTEQUAL
DataType.WORD -> Opcode.NOTEQUAL_W DataType.WORD -> Opcode.NOTEQUAL_W
DataType.FLOAT -> Opcode.NOTEQUAL_F DataType.FLOAT -> Opcode.NOTEQUAL_F

View File

@ -215,7 +215,8 @@ class ConstExprEvaluator {
left.asIntegerValue!=null -> when { left.asIntegerValue!=null -> when {
right.asIntegerValue!=null -> { right.asIntegerValue!=null -> {
if(right.asIntegerValue==0) divideByZeroError(right.position) if(right.asIntegerValue==0) divideByZeroError(right.position)
LiteralValue.optimalNumeric(left.asIntegerValue / right.asIntegerValue, left.position) val result = left.asIntegerValue.toDouble() / right.asIntegerValue.toDouble()
LiteralValue.optimalNumeric(result, left.position)
} }
right.floatvalue!=null -> { right.floatvalue!=null -> {
if(right.floatvalue==0.0) divideByZeroError(right.position) if(right.floatvalue==0.0) divideByZeroError(right.position)
@ -273,7 +274,7 @@ class ConstExprEvaluator {
left.asIntegerValue!=null -> when { left.asIntegerValue!=null -> when {
right.asIntegerValue!=null -> { right.asIntegerValue!=null -> {
if(right.asIntegerValue==0) divideByZeroError(right.position) if(right.asIntegerValue==0) divideByZeroError(right.position)
LiteralValue.optimalNumeric(left.asIntegerValue % right.asIntegerValue, left.position) LiteralValue.optimalNumeric(left.asIntegerValue.toDouble() % right.asIntegerValue.toDouble(), left.position)
} }
right.floatvalue!=null -> { right.floatvalue!=null -> {
if(right.floatvalue==0.0) divideByZeroError(right.position) if(right.floatvalue==0.0) divideByZeroError(right.position)

View File

@ -14,7 +14,6 @@ import kotlin.math.abs
X % 1 -> constant 0 (if X is byte/word) X % 1 -> constant 0 (if X is byte/word)
X % 2 -> X and 1 (if X is byte/word) X % 2 -> X and 1 (if X is byte/word)
todo expression optimization: remove redundant builtin function calls
todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call) todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call)
*/ */