mirror of
https://github.com/irmen/prog8.git
synced 2025-11-01 06:16:15 +00:00
fix: boolean values of terms in logical expressions are now properly evaluated
This commit is contained in:
@@ -702,10 +702,14 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
|||||||
when (val dt = fcall.args.single().inferType(program).getOr(DataType.UNDEFINED)) {
|
when (val dt = fcall.args.single().inferType(program).getOr(DataType.UNDEFINED)) {
|
||||||
in ByteDatatypes -> {
|
in ByteDatatypes -> {
|
||||||
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.A, dt==DataType.BYTE)
|
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.A, dt==DataType.BYTE)
|
||||||
|
asmgen.out(" beq + | lda #1")
|
||||||
|
asmgen.out("+")
|
||||||
}
|
}
|
||||||
in WordDatatypes -> {
|
in WordDatatypes -> {
|
||||||
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY, dt==DataType.WORD)
|
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY, dt==DataType.WORD)
|
||||||
asmgen.out(" sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1")
|
asmgen.out(" sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1")
|
||||||
|
asmgen.out(" beq + | lda #1")
|
||||||
|
asmgen.out("+")
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.FAC1, true)
|
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.FAC1, true)
|
||||||
|
|||||||
@@ -368,12 +368,20 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
|||||||
}
|
}
|
||||||
VmDataType.WORD -> {
|
VmDataType.WORD -> {
|
||||||
val msbReg = codeGen.vmRegisters.nextFree()
|
val msbReg = codeGen.vmRegisters.nextFree()
|
||||||
|
val skipLabel = codeGen.createLabelName()
|
||||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||||
code += VmCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = msbReg, reg2=resultRegister)
|
code += VmCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = msbReg, reg2=resultRegister)
|
||||||
code += VmCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
code += VmCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||||
|
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=resultRegister, labelSymbol = skipLabel)
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value = 1)
|
||||||
|
code += VmCodeLabel(skipLabel)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
val skipLabel = codeGen.createLabelName()
|
||||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||||
|
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=resultRegister, labelSymbol = skipLabel)
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value = 1)
|
||||||
|
code += VmCodeLabel(skipLabel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ internal class StatementReorderer(val program: Program,
|
|||||||
}
|
}
|
||||||
else if(expr.operator in LogicalOperators) {
|
else if(expr.operator in LogicalOperators) {
|
||||||
fun wrapped(expr: Expression): Expression {
|
fun wrapped(expr: Expression): Expression {
|
||||||
return if(expr.inferType(program).isBytes)
|
return if(expr is IFunctionCall && expr.target.nameInSource==listOf("boolean"))
|
||||||
expr
|
expr
|
||||||
else
|
else
|
||||||
FunctionCallExpression(IdentifierReference(listOf("boolean"), expr.position), mutableListOf(expr), expr.position)
|
FunctionCallExpression(IdentifierReference(listOf("boolean"), expr.position), mutableListOf(expr), expr.position)
|
||||||
@@ -320,6 +320,17 @@ internal class StatementReorderer(val program: Program,
|
|||||||
// rewrite in-place assignment expressions a bit so that the assignment target usually is the leftmost operand
|
// rewrite in-place assignment expressions a bit so that the assignment target usually is the leftmost operand
|
||||||
val binExpr = assignment.value as? BinaryExpression
|
val binExpr = assignment.value as? BinaryExpression
|
||||||
if(binExpr!=null) {
|
if(binExpr!=null) {
|
||||||
|
// if (binExpr.operator == "and") {
|
||||||
|
// val leftBinExpr = binExpr.left as? BinaryExpression
|
||||||
|
// if (leftBinExpr?.operator == "and")
|
||||||
|
// return mcCarthyAndAssignment(binExpr, assignment, parent)
|
||||||
|
// }
|
||||||
|
// if (binExpr.operator == "or") {
|
||||||
|
// val leftBinExpr = binExpr.left as? BinaryExpression
|
||||||
|
// if (leftBinExpr?.operator == "or")
|
||||||
|
// return mcCarthyOrAssignment(binExpr, assignment, parent)
|
||||||
|
// }
|
||||||
|
|
||||||
if(binExpr.left isSameAs assignment.target) {
|
if(binExpr.left isSameAs assignment.target) {
|
||||||
// A = A <operator> 5, unchanged
|
// A = A <operator> 5, unchanged
|
||||||
return noModifications
|
return noModifications
|
||||||
@@ -425,6 +436,56 @@ internal class StatementReorderer(val program: Program,
|
|||||||
checkUnusedReturnValues(functionCallStatement, function, errors)
|
checkUnusedReturnValues(functionCallStatement, function, errors)
|
||||||
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
|
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun mcCarthyAndAssignment(andExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable<IAstModification> {
|
||||||
|
val andTerms = findTerms(andExpr, "and")
|
||||||
|
if(andTerms.any { it.constValue(program)?.asBooleanValue == false }) {
|
||||||
|
errors.warn("expression is always false", andExpr.position)
|
||||||
|
return listOf(IAstModification.ReplaceNode(andExpr, NumericLiteral.fromBoolean(false, andExpr.position), assignment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// repeat for all terms:
|
||||||
|
// assign term to target
|
||||||
|
// add if: if target==0: goto done
|
||||||
|
// done:.
|
||||||
|
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mcCarthyOrAssignment(orExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable<IAstModification> {
|
||||||
|
val andTerms = findTerms(orExpr, "or")
|
||||||
|
if(andTerms.any { it.constValue(program)?.asBooleanValue == true }) {
|
||||||
|
errors.warn("expression is always true", orExpr.position)
|
||||||
|
return listOf(IAstModification.ReplaceNode(orExpr, NumericLiteral.fromBoolean(true, orExpr.position), assignment))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// repeat for all terms:
|
||||||
|
// assign term to target
|
||||||
|
// add if: if target!=0: goto done
|
||||||
|
// done:.
|
||||||
|
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findTerms(expr: BinaryExpression, operator: String, terms: List<Expression> = emptyList()): List<Expression> {
|
||||||
|
if(expr.operator!=operator)
|
||||||
|
return listOf(expr) + terms
|
||||||
|
val leftBinExpr = expr.left as? BinaryExpression ?: return listOf(expr.left, expr.right) + terms
|
||||||
|
return findTerms(leftBinExpr, operator, listOf(expr.right)+terms)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mcCarthyAndExpression(e1: Expression, e2: Expression, e3: Expression, origAndExpression: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||||
|
// TODO
|
||||||
|
println("AND EXPRESSION:")
|
||||||
|
println(" $e1")
|
||||||
|
println(" $e2")
|
||||||
|
println(" $e3")
|
||||||
|
println(" (orig) $origAndExpression")
|
||||||
|
val replacement = NumericLiteral.fromBoolean(false, origAndExpression.position)
|
||||||
|
return listOf(IAstModification.ReplaceNode(origAndExpression, replacement, parent))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -233,14 +233,5 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
|||||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
|
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
|
||||||
if(functionCallExpr.target.nameInSource==listOf("boolean")) {
|
|
||||||
if(functionCallExpr.args[0].inferType(program).isBytes) {
|
|
||||||
return listOf(IAstModification.ReplaceNode(functionCallExpr, functionCallExpr.args[0], parent))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,17 +255,10 @@ private fun builtinBoolean(args: List<Expression>, position: Position, program:
|
|||||||
if (args.size != 1)
|
if (args.size != 1)
|
||||||
throw SyntaxError("boolean requires one argument", position)
|
throw SyntaxError("boolean requires one argument", position)
|
||||||
val constvalue = args[0].constValue(program) ?: throw NotConstArgumentException()
|
val constvalue = args[0].constValue(program) ?: throw NotConstArgumentException()
|
||||||
return if(constvalue.number==0.0)
|
return if(constvalue.type==DataType.FLOAT)
|
||||||
NumericLiteral(DataType.UBYTE, 0.0, args[0].position)
|
|
||||||
else if(constvalue.type==DataType.UBYTE)
|
|
||||||
constvalue
|
|
||||||
else if(constvalue.type==DataType.FLOAT)
|
|
||||||
NumericLiteral(DataType.UBYTE, constvalue.number.sign, args[0].position)
|
NumericLiteral(DataType.UBYTE, constvalue.number.sign, args[0].position)
|
||||||
else {
|
else
|
||||||
val value = constvalue.number.toInt()
|
NumericLiteral.fromBoolean(constvalue.number!=0.0, args[0].position)
|
||||||
val byteValue = ((value ushr 8) or value) and 255
|
|
||||||
NumericLiteral(DataType.UBYTE, byteValue.toDouble(), args[0].position)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun builtinSgn(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
private fun builtinSgn(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||||
|
|||||||
@@ -777,7 +777,7 @@ Miscellaneous
|
|||||||
|
|
||||||
boolean(x)
|
boolean(x)
|
||||||
Returns a byte value representing the boolean (truthy) value of x, where x can be any numeric type.
|
Returns a byte value representing the boolean (truthy) value of x, where x can be any numeric type.
|
||||||
This means it returns 0 (false) when x equals 0, and a value other than 0 otherwise.
|
This means it returns 0 (false) when x equals 0, and 1 otherwise.
|
||||||
|
|
||||||
cmp(x,y)
|
cmp(x,y)
|
||||||
Compare the integer value x to integer value y. Doesn't return a value or boolean result, only sets the processor's status bits!
|
Compare the integer value x to integer value y. Doesn't return a value or boolean result, only sets the processor's status bits!
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ TODO
|
|||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- add McCarthy evaluation to shortcircuit and/or expressions. Both conditional expressions and assignments!
|
- add McCarthy evaluation to shortcircuit and/or expressions. Both conditional expressions and assignments!
|
||||||
|
StatementReorder.after(assignment).
|
||||||
- add some more optimizations in vmPeepholeOptimizer
|
- add some more optimizations in vmPeepholeOptimizer
|
||||||
- vm Instruction needs to know what the read-registers/memory are, and what the write-register/memory is.
|
- vm Instruction needs to know what the read-registers/memory are, and what the write-register/memory is.
|
||||||
this info is needed for more advanced optimizations and later code generation steps.
|
this info is needed for more advanced optimizations and later code generation steps.
|
||||||
|
|||||||
@@ -48,10 +48,24 @@ main {
|
|||||||
sub start() {
|
sub start() {
|
||||||
ubyte value
|
ubyte value
|
||||||
uword wvalue
|
uword wvalue
|
||||||
byte svalue = -99
|
|
||||||
|
|
||||||
wvalue = 3*abs(svalue) +abs(svalue)+abs(svalue)+abs(svalue)
|
ubyte ub1 = 11
|
||||||
txt.print_uw(wvalue)
|
ubyte ub2 = 22
|
||||||
|
ubyte ub3 = 33
|
||||||
|
ubyte ub4 = 44
|
||||||
|
ubyte ub5 = 55
|
||||||
|
|
||||||
|
ub4 = 42
|
||||||
|
txt.print("and with bytes: ")
|
||||||
|
ub5 = ub1 and ub2 and ub3 and ub4 and ub5 ; TODO FIX !! should be True (!=0)
|
||||||
|
txt.print_ub(ub5)
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
|
ub4 = 42
|
||||||
|
txt.print("or with bytes: ")
|
||||||
|
ub5 = ub1 or ub2 or ub3 or ub4 or ub5 ; TODO FIX!! should be False (0)
|
||||||
|
txt.print_ub(ub5)
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
txt.print("short and with false (word): ")
|
txt.print("short and with false (word): ")
|
||||||
wvalue = funcw() and funcFalseWord() and funcw() and funcw()
|
wvalue = funcw() and funcFalseWord() and funcw() and funcw()
|
||||||
@@ -72,7 +86,7 @@ main {
|
|||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
txt.print("and with false: ")
|
txt.print("and with false: ")
|
||||||
value = func1(25) and func2(25) and funcFalse() and func3(25) and func4(25)
|
value = func1(25) and func2(25) and funcFalse() and false and func3(25) and func4(25)
|
||||||
txt.print_ub(value)
|
txt.print_ub(value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print("and with true: ")
|
txt.print("and with true: ")
|
||||||
@@ -80,7 +94,7 @@ main {
|
|||||||
txt.print_ub(value)
|
txt.print_ub(value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print("or with false: ")
|
txt.print("or with false: ")
|
||||||
value = func1(25) or func2(25) or funcFalse() or func3(25) or func4(25)
|
value = func1(25) or func2(25) or funcFalse() or true or func3(25) or func4(25)
|
||||||
txt.print_ub(value)
|
txt.print_ub(value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print("or with true: ")
|
txt.print("or with true: ")
|
||||||
|
|||||||
Reference in New Issue
Block a user