got rid of problematic signed POW operator, added compiler checks for this

This commit is contained in:
Irmen de Jong 2019-03-31 13:54:22 +02:00
parent ec2e7db23e
commit 83ace753b2
10 changed files with 83 additions and 41 deletions

View File

@ -1 +1 @@
1.5 (beta)
1.6 (beta)

View File

@ -673,6 +673,9 @@ private class AstChecker(private val namespace: INameScope,
}
override fun process(expr: BinaryExpression): IExpression {
val leftDt = expr.left.resultingDatatype(namespace, heap)
val rightDt = expr.right.resultingDatatype(namespace, heap)
when(expr.operator){
"/", "%" -> {
val constvalRight = expr.right.constValue(namespace, heap)
@ -680,16 +683,23 @@ private class AstChecker(private val namespace: INameScope,
if(divisor==0.0)
checkResult.add(ExpressionError("division by zero", expr.right.position))
if(expr.operator=="%") {
val rightDt = constvalRight?.resultingDatatype(namespace, heap)
val leftDt = expr.left.resultingDatatype(namespace, heap)
if ((rightDt != DataType.UBYTE && rightDt != DataType.UWORD) || (leftDt!=DataType.UBYTE && leftDt!=DataType.UWORD))
checkResult.add(ExpressionError("remainder can only be used on unsigned integer operands", expr.right.position))
}
}
"**" -> {
if(leftDt in IntegerDatatypes) {
val constvalRight = expr.right.constValue(namespace, heap)?.asNumericValue?.toDouble()
if(constvalRight==null) {
if(rightDt==DataType.FLOAT || rightDt==DataType.BYTE || rightDt==DataType.WORD)
checkResult.add(ExpressionError("raising to a signed value requires floating point", expr.position))
} else if(constvalRight<0.0) {
checkResult.add(ExpressionError("raising to negative power requires floating point", expr.position))
}
}
}
"and", "or", "xor" -> {
// only integer numeric operands accepted, and if literal constants, only boolean values accepted (0 or 1)
val rightDt = expr.right.resultingDatatype(namespace, heap)
val leftDt = expr.left.resultingDatatype(namespace, heap)
if(leftDt !in IntegerDatatypes || rightDt !in IntegerDatatypes)
checkResult.add(ExpressionError("logical operator can only be used on boolean operands", expr.right.position))
val constLeft = expr.left.constValue(namespace, heap)
@ -699,15 +709,11 @@ private class AstChecker(private val namespace: INameScope,
}
"&", "|", "^" -> {
// only integer numeric operands accepted
val rightDt = expr.right.resultingDatatype(namespace, heap)
val leftDt = expr.left.resultingDatatype(namespace, heap)
if(leftDt !in IntegerDatatypes || rightDt !in IntegerDatatypes)
checkResult.add(ExpressionError("bitwise operator can only be used on integer operands", expr.right.position))
}
}
val leftDt = expr.left.resultingDatatype(namespace, heap)
val rightDt = expr.right.resultingDatatype(namespace, heap)
if(leftDt !in NumericDatatypes)
checkResult.add(ExpressionError("left operand is not numeric", expr.left.position))
if(rightDt!in NumericDatatypes)

View File

@ -1239,9 +1239,8 @@ internal class Compiler(private val rootModule: Module,
"**" -> {
when(dt) {
DataType.UBYTE -> Opcode.POW_UB
DataType.BYTE -> Opcode.POW_B
DataType.BYTE, DataType.WORD -> throw CompilerException("power operator only available for unsigned integer types and floats")
DataType.UWORD -> Opcode.POW_UW
DataType.WORD -> Opcode.POW_W
DataType.FLOAT -> Opcode.POW_F
else -> throw CompilerException("only byte/word/float possible")
}

View File

@ -59,9 +59,7 @@ enum class Opcode {
REMAINDER_UB, // signed remainder is undefined/unimplemented
REMAINDER_UW, // signed remainder is undefined/unimplemented
POW_UB,
POW_B,
POW_UW,
POW_W,
POW_F,
NEG_B,
NEG_W,

View File

@ -729,6 +729,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.ABS_B -> " jsr prog8_lib.abs_b"
Opcode.ABS_W -> " jsr prog8_lib.abs_w"
Opcode.ABS_F -> " jsr c64flt.abs_f"
Opcode.POW_UB -> " jsr prog8_lib.pow_ub" // @todo implement
Opcode.POW_UW -> " jsr prog8_lib.pow_uw" // @todo implement
Opcode.POW_F -> " jsr c64flt.pow_f" // @todo implement
Opcode.INV_BYTE -> {
"""
lda ${(ESTACK_LO + 1).toHex()},x

View File

@ -631,22 +631,6 @@ class StackVm(private var traceOutputFile: String?) {
evalstack.push(value)
setFlags(value)
}
Opcode.POW_B -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
val value=second.pow(top)
evalstack.push(value)
setFlags(value)
}
Opcode.POW_W -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
val value=second.pow(top)
evalstack.push(value)
setFlags(value)
}
Opcode.POW_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)

View File

@ -372,7 +372,8 @@ Operators
arithmetic: ``+`` ``-`` ``*`` ``/`` ``**`` ``%``
``+``, ``-``, ``*``, ``/`` are the familiar arithmetic operations.
``/`` is division (will result in integer division when using on integer operands, and a floating point division when at least one of the operands is a float)
``**`` is the power operator: ``3 ** 5`` is equal to 3*3*3*3*3 and is 243.
``**`` is the power operator: ``3 ** 5`` is equal to 3*3*3*3*3 and is 243. (certain restrictions
apply when dealing with signed or negative numbers)
``%`` is the remainder operator: ``25 % 7`` is 4. Be careful: without a space, %10 will be parsed as the binary number 2
Remainder is only supported on integer operands (not floats).

View File

@ -173,7 +173,3 @@ as a subroutine ``irq`` in the module ``irq`` so like this::
; ... irq handling here ...
}
}
.. todo::
@todo the irq handler should use its own eval-stack to avoid stack interference issues

View File

@ -17,7 +17,7 @@ Memory Block Operations integrated in language?
these should call (or emit inline) optimized pieces of assembly code, so they run as fast as possible
For now, we have the ``memcopy`` and ``memset`` builtin functions.
For now, we have the ``memcopy``, ``memset`` and ``strlen`` builtin functions.
@ -52,6 +52,7 @@ Allocate a fixed word in ZP that is the TOS so we can operate on TOS directly
without having to to index into the stack?
More flexible (non-const) arrays?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Currently, array literals can only be constants

View File

@ -1,15 +1,69 @@
%zeropage basicsafe
%option enable_floats
%import c64flt
~ main {
ubyte @zp var1
sub start() {
ubyte @zp var1
A=20
A=var1
Y=main.var1
ubyte ub=2
ubyte ub2=7
uword uw=2
uword uw2=5
float fl=2.3
float fl2=20
ub = ub ** 7
c64scr.print_ub(ub)
c64.CHROUT('\n')
uw = uw ** 5
c64scr.print_uw(uw)
c64.CHROUT('\n')
fl = fl ** 20.0
c64flt.print_f(fl)
c64.CHROUT('\n')
ub=3 ; @todo no instruction?
ub **=7 ; @todo no instruction?
c64scr.print_ub(ub)
c64.CHROUT('\n')
uw = 9 ; @todo no instruction?
uw **=5 ; @todo no instruction?
c64scr.print_uw(uw)
c64.CHROUT('\n')
fl = 2 ; @todo no instruction?
fl **=20.0 ; @todo no instruction?
c64flt.print_f(fl)
c64.CHROUT('\n')
ub=3
ub **= 7
c64scr.print_ub(ub)
c64.CHROUT('\n')
uw = 9
uw **= 5
c64scr.print_uw(uw)
c64.CHROUT('\n')
fl = 2.3
fl **= 20.0
c64flt.print_f(fl)
c64.CHROUT('\n')
ub=3
ub **= ub2
c64scr.print_ub(ub)
c64.CHROUT('\n')
uw = 9
uw **= uw2
c64scr.print_uw(uw)
c64.CHROUT('\n')
fl = 2.3
fl **= fl2
c64flt.print_f(fl)
c64.CHROUT('\n')
}
}