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
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
y = 0.0
xsquared = 0
ysquared = 0
iter = 0
while (iter<32 and xsquared+ysquared<4) {
y = x*y*2 + yy
while (iter<32 and xsquared+ysquared<4.0) {
y = x*y*2.0 + yy
x = xsquared - ysquared + xx
xsquared = x*x
ysquared = y*y

View File

@ -25,9 +25,9 @@
}
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 {
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 {
X=0
word mainvar = 44*Y
return
sub start() {
A=99
const byte b1 = 20//7
const word w1 = 20//7
const float f1 = 20/7
byte bvar = 4*X
word wvar = 44*XY
float fvar = 128.34+XY
A=100
_vm_write_num(b1)
_vm_write_char('\n')
_vm_write_num(w1)
_vm_write_char('\n')
_vm_write_num(f1)
_vm_write_char('\n')
return
}

View File

@ -521,12 +521,43 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stackvmProg.instr(Opcode.NOP)
}
private fun checkForFloatPrecisionProblem(left: IExpression, right: IExpression) {
val leftDt = left.resultingDatatype(namespace, heap)
val rightDt = right.resultingDatatype(namespace, heap)
if (leftDt == DataType.BYTE || leftDt == DataType.WORD) {
if(rightDt==DataType.FLOAT)
printWarning("byte or word value implicitly converted to float. Suggestion: use explicit flt() conversion or revert to byte/word arithmetic", left.position)
private fun commonDatatype(leftDt: DataType, rightDt: DataType, leftpos: Position, rightpos: Position): DataType {
// byte + byte -> byte
// byte + word -> word
// word + byte -> word
// word + word -> word
// 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))
}
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)
if(leftDt!=commonDt)
convertType(leftDt, commonDt)
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 -> {
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) {
val target = identifierRef.targetStatement(namespace)
when (target) {
@ -720,17 +784,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname)
}
private fun translateBinaryOperator(operator: String, leftDt: DataType?, rightDt: DataType?) {
if(leftDt==null || rightDt==null)
throw CompilerException("left and/or right operand datatype not known")
private fun translateBinaryOperator(operator: String, dt: DataType) {
val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
if(leftDt !in validDt || rightDt !in validDt)
throw CompilerException("invalid datatype(s) for operand(s)")
if(leftDt!=rightDt)
throw CompilerException("operands have different datatypes")
if(dt !in validDt)
throw CompilerException("invalid datatype for operator: $dt")
val opcode = when(operator) {
"+" -> {
when(leftDt) {
when(dt) {
DataType.BYTE -> Opcode.ADD_B
DataType.WORD -> Opcode.ADD_W
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.WORD -> Opcode.SUB_W
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.WORD -> Opcode.MUL_W
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.WORD -> Opcode.DIV_W
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.WORD -> Opcode.FLOORDIV_W
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.WORD -> Opcode.REMAINDER_W
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.WORD -> Opcode.POW_W
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.WORD -> Opcode.BITAND_W
else -> throw CompilerException("only byte/word possible")
}
}
"|" -> {
when(leftDt) {
when(dt) {
DataType.BYTE -> Opcode.BITOR
DataType.WORD -> Opcode.BITOR_W
else -> throw CompilerException("only byte/word possible")
}
}
"^" -> {
when(leftDt) {
when(dt) {
DataType.BYTE -> Opcode.BITXOR
DataType.WORD -> Opcode.BITXOR_W
else -> throw CompilerException("only byte/word possible")
}
}
"and" -> {
when(leftDt) {
when(dt) {
DataType.BYTE -> Opcode.AND
DataType.WORD -> Opcode.AND_W
else -> throw CompilerException("only byte/word possible")
}
}
"or" -> {
when(leftDt) {
when(dt) {
DataType.BYTE -> Opcode.OR
DataType.WORD -> Opcode.OR_W
else -> throw CompilerException("only byte/word possible")
}
}
"xor" -> {
when(leftDt) {
when(dt) {
DataType.BYTE -> Opcode.XOR
DataType.WORD -> Opcode.XOR_W
else -> throw CompilerException("only byte/word possible")
}
}
"<" -> {
when(leftDt) {
when(dt) {
DataType.BYTE -> Opcode.LESS
DataType.WORD -> Opcode.LESS_W
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.WORD -> Opcode.GREATER_W
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.WORD -> Opcode.LESSEQ_W
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.WORD -> Opcode.GREATEREQ_W
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.WORD -> Opcode.EQUAL_W
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.WORD -> Opcode.NOTEQUAL_W
DataType.FLOAT -> Opcode.NOTEQUAL_F

View File

@ -215,7 +215,8 @@ class ConstExprEvaluator {
left.asIntegerValue!=null -> when {
right.asIntegerValue!=null -> {
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 -> {
if(right.floatvalue==0.0) divideByZeroError(right.position)
@ -273,7 +274,7 @@ class ConstExprEvaluator {
left.asIntegerValue!=null -> when {
right.asIntegerValue!=null -> {
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 -> {
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 % 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)
*/