tweak bool type handling

This commit is contained in:
Irmen de Jong 2022-07-11 12:22:14 +02:00
parent 7a26646e1b
commit 88cbb6913d
15 changed files with 242 additions and 154 deletions

View File

@ -5,7 +5,7 @@ val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
val LogicalOperators = setOf("and", "or", "xor", "not")
val AugmentAssignmentOperators = setOf("+", "-", "/", "*", "&", "|", "^", "<<", ">>", "%")
val BitwiseOperators = setOf("&", "|", "^", "~")
val InvalidOperatorsForBoolean = setOf("-", "*", "/", "%", "<<", ">>") // TODO what about +? TODO add BitWiseOperators
// val InvalidOperatorsForBoolean = setOf("+", "-", "*", "/", "%", "<<", ">>") + BitwiseOperators
fun invertedComparisonOperator(operator: String) =
when (operator) {

View File

@ -403,16 +403,7 @@ class IntermediateAstMaker(val program: Program) {
private fun transform(srcExpr: BinaryExpression): PtBinaryExpression {
val type = srcExpr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
var actualType = type
if(type==DataType.BOOL) {
if(srcExpr.operator in LogicalOperators + ComparisonOperators) {
// a comparison or logical expression is a boolean result (0 or 1) so we can safely
// reduce that to just a UBYTE type for the vm code that doesn't know about bools.
actualType = DataType.UBYTE
} else {
throw IllegalArgumentException("Ast expression still having BOOL type: $srcExpr @${srcExpr.position}")
}
}
val actualType = if(type==DataType.BOOL) DataType.UBYTE else type
val expr = PtBinaryExpression(srcExpr.operator, actualType, srcExpr.position)
expr.add(transformExpression(srcExpr.left))
expr.add(transformExpression(srcExpr.right))

View File

@ -479,11 +479,13 @@ internal class AstChecker(private val program: Program,
if(numvalue!=null && targetDt.isKnown)
checkValueTypeAndRange(targetDt.getOr(DataType.UNDEFINED), numvalue)
if(assignment.isAugmentable && targetDt istype DataType.BOOL) {
val operator = (assignment.value as? BinaryExpression)?.operator
if(operator in InvalidOperatorsForBoolean)
errors.err("can't use boolean operand with this operator $operator", assignment.position)
}
// for now, don't enforce bool type with only logical operators...
// if(assignment.isAugmentable && targetDt istype DataType.BOOL) {
// val operator = (assignment.value as? BinaryExpression)?.operator
// if(operator in InvalidOperatorsForBoolean)
// errors.err("can't use boolean operand with this operator $operator", assignment.position)
// }
super.visit(assignment)
}
@ -918,14 +920,10 @@ internal class AstChecker(private val program: Program,
if(expr.operator in setOf("<", "<=", ">", ">=")) {
errors.err("can't use boolean operand with this comparison operator", expr.position)
}
if(expr.operator in InvalidOperatorsForBoolean && (leftDt==DataType.BOOL || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) {
errors.err("can't use boolean operand with this operator ${expr.operator}", expr.left.position)
}
if(expr.operator=="+" && (leftDt==DataType.BOOL || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) {
val rightNum = expr.right.constValue(program)?.number ?: 0.0
if(rightNum > 1.0)
errors.err("can't use boolean operand with this operator ${expr.operator}", expr.left.position)
}
// for now, don't enforce bool type with only logical operators...
// if(expr.operator in InvalidOperatorsForBoolean && (leftDt==DataType.BOOL || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) {
// errors.err("can't use boolean operand with this operator ${expr.operator}", expr.left.position)
// }
if(expr.operator == "==" || expr.operator == "!=") {
val leftNum = expr.left.constValue(program)?.number ?: 0.0
val rightNum = expr.right.constValue(program)?.number ?: 0.0

View File

@ -22,14 +22,17 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
}
internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter) {
val boolRemover = BoolRemover(this)
boolRemover.visit(this)
boolRemover.applyModifications()
val fixer = BeforeAsmAstChanger(this, compilerOptions, errors)
fixer.visit(this)
while(errors.noErrors() && fixer.applyModifications()>0) {
while (errors.noErrors() && fixer.applyModifications() > 0) {
fixer.visit(this)
}
val cleaner = BeforeAsmTypecastCleaner(this, errors)
cleaner.visit(this)
while(errors.noErrors() && cleaner.applyModifications()>0) {
while (errors.noErrors() && cleaner.applyModifications() > 0) {
cleaner.visit(this)
}
}

View File

@ -60,34 +60,6 @@ internal class BeforeAsmAstChanger(val program: Program,
throw InternalCompilerException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
}
if(decl.datatype==DataType.BOOL) {
var newvalue = decl.value
if(newvalue is NumericLiteral) {
if(newvalue.number!=0.0)
newvalue = NumericLiteral(DataType.UBYTE, 1.0, newvalue.position)
}
val ubyteDecl = VarDecl(decl.type, decl.origin, DataType.UBYTE, decl.zeropage, decl.arraysize, decl.name,
newvalue, decl.isArray, decl.sharedWithAsm, decl.subroutineParameter, decl.position)
return listOf(IAstModification.ReplaceNode(decl, ubyteDecl, parent))
}
if(decl.datatype==DataType.ARRAY_BOOL) {
var newarray = decl.value
if(decl.value is ArrayLiteral) {
val oldArray = (decl.value as ArrayLiteral).value
val convertedArray = oldArray.map {
var number: Expression = it
if (it is NumericLiteral && it.type == DataType.BOOL)
number = NumericLiteral(DataType.UBYTE, if (it.number == 0.0) 0.0 else 1.0, number.position)
number
}.toTypedArray()
newarray = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), convertedArray, decl.position)
}
val ubyteArrayDecl = VarDecl(decl.type, decl.origin, DataType.ARRAY_UB, decl.zeropage, decl.arraysize, decl.name,
newarray, true, decl.sharedWithAsm, decl.subroutineParameter, decl.position)
return listOf(IAstModification.ReplaceNode(decl, ubyteArrayDecl, parent))
}
return noModifications
}
@ -152,23 +124,6 @@ internal class BeforeAsmAstChanger(val program: Program,
}
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
// replace BOOL return type and parameters by UBYTE
if(subroutine.returntypes.any { it==DataType.BOOL } || subroutine.parameters.any {it.type==DataType.BOOL}) {
val newReturnTypes = subroutine.returntypes.map {
if(it==DataType.BOOL) DataType.UBYTE else it
}
val newParams = subroutine.parameters.map {
if(it.type==DataType.BOOL) SubroutineParameter(it.name, DataType.UBYTE, it.position) else it
}.toMutableList()
val newSubroutine = Subroutine(subroutine.name, newParams, newReturnTypes,
subroutine.asmParameterRegisters, subroutine.asmReturnvaluesRegisters, subroutine.asmClobbers,
subroutine.asmAddress, subroutine.isAsmSubroutine, subroutine.inline, subroutine.statements,
subroutine.position)
return listOf(IAstModification.ReplaceNode(subroutine, newSubroutine, parent))
}
// Most code generation targets only support subroutine inlining on asmsub subroutines
// So we reset the flag here to be sure it doesn't cause problems down the line in the codegen.
if(!subroutine.isAsmSubroutine && options.compTarget.name!=VMTarget.NAME)
@ -213,30 +168,9 @@ internal class BeforeAsmAstChanger(val program: Program,
}
}
if(subroutine.returntypes.any { it==DataType.BOOL } || subroutine.parameters.any {it.type==DataType.BOOL}) {
throw FatalAstException("boolean args and return types to ubyte should already have been done by earlier step")
}
return mods
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
// convert boolean and/or/xor/not operators to bitwise equivalents.
// so that codegen only has to work with bitwise boolean operations from now on.
if(expr.operator in setOf("and", "or", "xor")) {
expr.operator = when(expr.operator) {
"and" -> "&"
"or" -> "|"
"xor" -> "^"
else -> "invalid"
}
return listOf(
IAstModification.ReplaceNode(expr.left, wrapWithBooleanCastIfNeeded(expr.left), expr),
IAstModification.ReplaceNode(expr.right, wrapWithBooleanCastIfNeeded(expr.right), expr),)
}
return noModifications
}
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
val binExpr = ifElse.condition as? BinaryExpression
if(binExpr==null) {
@ -437,27 +371,4 @@ internal class BeforeAsmAstChanger(val program: Program,
)
return modifications
}
private fun wrapWithBooleanCastIfNeeded(expr: Expression): Expression {
fun isBoolean(expr: Expression): Boolean {
return if(expr.inferType(program) istype DataType.BOOL)
true
else if(expr is BinaryExpression && expr.operator in ComparisonOperators + LogicalOperators)
true
else if(expr is PrefixExpression && expr.operator == "not")
true
else if(expr is BinaryExpression && expr.operator in BitwiseOperators) {
if(isBoolean(expr.left) && isBoolean(expr.right))
true
else expr.operator=="&" && expr.right.constValue(program)?.number==1.0 // x & 1 is also a boolean result
}
else
false
}
return if(isBoolean(expr))
expr
else
TypecastExpression(expr, DataType.BOOL, true, expr.position)
}
}

View File

@ -15,12 +15,15 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
private val errors: IErrorReporter
) : AstWalker() {
override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
if(typecast.type==DataType.BOOL) {
override fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
if(typecast.type == DataType.BOOL) {
val notZero = BinaryExpression(typecast.expression, "!=", NumericLiteral(DataType.UBYTE, 0.0, typecast.position), typecast.position)
return listOf(IAstModification.ReplaceNode(typecast, notZero, parent))
}
return noModifications
}
override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
// see if we can remove redundant typecasts (outside of expressions)
// such as casting byte<->ubyte, word<->uword or even redundant casts (sourcetype = target type).
// the special typecast of a reference type (str, array) to an UWORD will be changed into address-of,
@ -75,7 +78,6 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
return noModifications
}
// also convert calls to builtin functions to BuiltinFunctionCall nodes to make things easier for codegen
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
@ -91,7 +93,6 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
return noModifications
}
override fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
if(functionCallExpr.target.nameInSource.size==1
&& functionCallExpr.target.nameInSource[0] in program.builtinFunctions.names) {
@ -128,5 +129,4 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
}
return noModifications
}
}

View File

@ -0,0 +1,114 @@
package prog8.compiler.astprocessing
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.expressions.*
import prog8.ast.statements.Subroutine
import prog8.ast.statements.SubroutineParameter
import prog8.ast.statements.VarDecl
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.*
internal class BoolRemover(val program: Program) : AstWalker() {
override fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
if(typecast.type == DataType.BOOL) {
val notZero = BinaryExpression(typecast.expression, "!=", NumericLiteral(DataType.UBYTE, 0.0, typecast.position), typecast.position)
return listOf(IAstModification.ReplaceNode(typecast, notZero, parent))
}
return noModifications
}
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
if(decl.datatype==DataType.BOOL) {
var newvalue = decl.value
if(newvalue is NumericLiteral) {
if(newvalue.number!=0.0)
newvalue = NumericLiteral(DataType.UBYTE, 1.0, newvalue.position)
}
val ubyteDecl = VarDecl(decl.type, decl.origin, DataType.UBYTE, decl.zeropage, decl.arraysize, decl.name,
newvalue, decl.isArray, decl.sharedWithAsm, decl.subroutineParameter, decl.position)
return listOf(IAstModification.ReplaceNode(decl, ubyteDecl, parent))
}
if(decl.datatype==DataType.ARRAY_BOOL) {
var newarray = decl.value
if(decl.value is ArrayLiteral) {
val oldArray = (decl.value as ArrayLiteral).value
val convertedArray = oldArray.map {
var number: Expression = it
if (it is NumericLiteral && it.type == DataType.BOOL)
number = NumericLiteral(DataType.UBYTE, if (it.number == 0.0) 0.0 else 1.0, number.position)
number
}.toTypedArray()
newarray = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), convertedArray, decl.position)
}
val ubyteArrayDecl = VarDecl(decl.type, decl.origin, DataType.ARRAY_UB, decl.zeropage, decl.arraysize, decl.name,
newarray, true, decl.sharedWithAsm, decl.subroutineParameter, decl.position)
return listOf(IAstModification.ReplaceNode(decl, ubyteArrayDecl, parent))
}
return noModifications
}
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
// replace BOOL return type and parameters by UBYTE
if(subroutine.returntypes.any { it==DataType.BOOL } || subroutine.parameters.any {it.type==DataType.BOOL}) {
val newReturnTypes = subroutine.returntypes.map {
if(it==DataType.BOOL) DataType.UBYTE else it
}
val newParams = subroutine.parameters.map {
if(it.type==DataType.BOOL) SubroutineParameter(it.name, DataType.UBYTE, it.position) else it
}.toMutableList()
val newSubroutine = Subroutine(subroutine.name, newParams, newReturnTypes,
subroutine.asmParameterRegisters, subroutine.asmReturnvaluesRegisters, subroutine.asmClobbers,
subroutine.asmAddress, subroutine.isAsmSubroutine, subroutine.inline, subroutine.statements,
subroutine.position)
return listOf(IAstModification.ReplaceNode(subroutine, newSubroutine, parent))
}
return noModifications
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
// convert boolean and/or/xor/not operators to bitwise equivalents.
// so that codegen only has to work with bitwise boolean operations from now on.
// note: this has to be done here and not in BeforeAsmTypecastCleaner! (code size will increase if done there...)
if(expr.operator in setOf("and", "or", "xor")) {
expr.operator = when(expr.operator) {
"and" -> "&"
"or" -> "|"
"xor" -> "^"
else -> "invalid"
}
return listOf(
IAstModification.ReplaceNodeSafe(expr.left, wrapWithBooleanCastIfNeeded(expr.left), expr),
IAstModification.ReplaceNodeSafe(expr.right, wrapWithBooleanCastIfNeeded(expr.right), expr),)
}
return noModifications
}
private fun wrapWithBooleanCastIfNeeded(expr: Expression): Expression {
fun isBoolean(expr: Expression): Boolean {
return if(expr.inferType(program) istype DataType.BOOL)
true
else if(expr is BinaryExpression && expr.operator in ComparisonOperators + LogicalOperators)
true
else if(expr is PrefixExpression && expr.operator == "not")
true
else if(expr is BinaryExpression && expr.operator in BitwiseOperators) {
if(isBoolean(expr.left) && isBoolean(expr.right))
true
else expr.operator=="&" && expr.right.constValue(program)?.number==1.0 // x & 1 is also a boolean result
}
else
false
}
return if(isBoolean(expr))
expr
else
TypecastExpression(expr, DataType.BOOL, true, expr.position)
}
}

View File

@ -84,7 +84,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
// but only if the containment check is the top-level expression.
if(parent is BinaryExpression)
return noModifications
if(expr.operator == "|") {
if(expr.operator == "|" || expr.operator=="or") {
val leftBinExpr1 = expr.left as? BinaryExpression
val rightBinExpr1 = expr.right as? BinaryExpression
@ -100,7 +100,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
}
return false
}
if(expr.operator!="|")
if(expr.operator!="|" && expr.operator!="or")
return false
val leftBinExpr = expr.left as? BinaryExpression
val rightBinExpr = expr.right as? BinaryExpression

View File

@ -263,10 +263,10 @@ class TestOptimization: FunSpec({
}
}
"""
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
val result = compileText(C64Target(), false, src, writeAssembly = true)!!
printProgram(result.program)
val stmts = result.program.entrypoint.statements
stmts.size shouldBe 7
stmts.size shouldBe 8
val value1 = (stmts[4] as Assignment).value as BinaryExpression
val value2 = (stmts[5] as Assignment).value as BinaryExpression

View File

@ -14,11 +14,67 @@ import prog8.ast.statements.VarDecl
import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.code.target.C64Target
import prog8.code.target.VMTarget
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
class TestTypecasts: FunSpec({
test("bool expressions with functioncalls") {
val text="""
main {
sub ftrue(ubyte arg) -> ubyte {
arg++
return 64
}
sub start() {
bool ub1 = true
bool ub2 = true
bool ub3 = true
bool ub4 = 0
bool @shared bvalue
bvalue = ub1 xor ub2 xor ub3 xor true
bvalue = ub1 xor ub2 xor ub3 xor ftrue(99)
bvalue = ub1 and ub2 and ftrue(99)
}
}"""
val result = compileText(C64Target(), true, text, writeAssembly = true)!!
val stmts = result.program.entrypoint.statements
/*
ubyte ub1
ub1 = 1
ubyte ub2
ub2 = 1
ubyte ub3
ub3 = 1
ubyte @shared bvalue
bvalue = (((ub1^ub2)^ub3)^(1!=0))
bvalue = (((ub1^ub2)^ub3)^(ftrue(99)!=0))
bvalue = ((ub1&ub2)&(ftrue(99)!=0))
return
*/
stmts.size shouldBe 11
val assignValue1 = (stmts[7] as Assignment).value as BinaryExpression
val assignValue2 = (stmts[8] as Assignment).value as BinaryExpression
val assignValue3 = (stmts[9] as Assignment).value as BinaryExpression
assignValue1.operator shouldBe "^"
assignValue2.operator shouldBe "^"
assignValue3.operator shouldBe "&"
val right1 = assignValue1.right as BinaryExpression
val right2 = assignValue2.right as BinaryExpression
val right3 = assignValue3.right as BinaryExpression
right1.operator shouldBe "!="
right2.operator shouldBe "!="
right3.operator shouldBe "!="
right1.left shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
right1.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
right2.left shouldBe instanceOf<IFunctionCall>()
right2.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
right3.left shouldBe instanceOf<IFunctionCall>()
right3.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
}
test("logical with byte instead of bool") {
val text="""
@ -504,7 +560,7 @@ main {
(fcall2.args[0] as TypecastExpression).type shouldBe DataType.BOOL
(fcall2.args[1] as TypecastExpression).type shouldBe DataType.BOOL
val ifCond = (stmts[8] as IfElse).condition as BinaryExpression
ifCond.operator shouldBe "&"
ifCond.operator shouldBe "and" // no asm writing so logical expressions haven't been replaced with bitwise equivalents yet
(ifCond.left as IdentifierReference).nameInSource shouldBe listOf("boolvalue1")
(ifCond.right as IdentifierReference).nameInSource shouldBe listOf("boolvalue2")
}
@ -523,11 +579,13 @@ main {
ww = (camg & ${'$'}0004)
ww++
ww = (${'$'}0004 & camg)
ubyte @shared wordNr2 = (interlaced >= ${'$'}33) + (interlaced >= ${'$'}66) + (interlaced >= ${'$'}99) + (interlaced >= ${'$'}CC)
}
}"""
val result = compileText(C64Target(), false, text, writeAssembly = false)!!
val result = compileText(VMTarget(), false, text, writeAssembly = true)!!
val stmts = result.program.entrypoint.statements
stmts.size shouldBe 11
stmts.size shouldBe 14
}
test("word to byte casts") {

View File

@ -51,7 +51,9 @@ class TestIntermediateAst: FunSpec({
arraydecl.name shouldBe "array"
arraydecl.type shouldBe DataType.ARRAY_UB
val containment = (entry.children[2] as PtAssignment).value as PtContainmentCheck
val containmentCast = (entry.children[2] as PtAssignment).value as PtTypeCast
containmentCast.type shouldBe DataType.UBYTE
val containment = containmentCast.value as PtContainmentCheck
(containment.element as PtNumber).number shouldBe 11.0
val fcall = (entry.children[3] as PtAssignment).value as PtFunctionCall
fcall.void shouldBe false

View File

@ -786,7 +786,7 @@ class TestProg8Parser: FunSpec( {
val left = zz2.left as TypecastExpression
val right = zz2.right as PrefixExpression
left.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD
right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD
right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.BOOL
zz2.inferType(program).getOrElse { fail("dt") } shouldBe DataType.BOOL
}
@ -885,6 +885,7 @@ class TestProg8Parser: FunSpec( {
str string = "hello"
ubyte[] array = [1,2,3,4]
bool bb
ubyte cc
if cc in [' ', '@', 0] {
}
@ -892,8 +893,8 @@ class TestProg8Parser: FunSpec( {
if cc in "email" {
}
cc = 99 in array
cc = '@' in string
bb = 99 in array
bb = '@' in string
}
}
"""

View File

@ -124,7 +124,8 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
val inferred = expression.inferType(program)
return when(operator) {
"+" -> inferred
"~", "not" -> {
"not" -> InferredTypes.knownFor(DataType.BOOL)
"~" -> {
when(inferred.getOr(DataType.UNDEFINED)) {
in ByteDatatypes -> InferredTypes.knownFor(DataType.UBYTE)
in WordDatatypes -> InferredTypes.knownFor(DataType.UWORD)
@ -1108,7 +1109,7 @@ class ContainmentCheck(var element: Expression,
return iterable.referencesIdentifier(nameInSource)
}
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE)
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.BOOL)
override fun replaceChildNode(node: Node, replacement: Node) {
if(replacement !is Expression)

View File

@ -3,8 +3,9 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- fix vm code result of test.p8 (ftrue() not called at all!?)
- add more operators to InvalidOperatorsForBoolean
- petaxian has become larger (18630) why so much larger. problematic lines:
gun.p8 95,110 if ( x <= GUN_MAX_LEFT and leftmost ) ...
enemy.p8 456 + bombs.p8 33 (while i<value)...
- have a proper option to move the evalstack rather than just assembly symbol redefine
- then make the cx16 virtual registers in syslib.p8 use that definition to be able to shift them around on non-cx16 targets

View File

@ -3,28 +3,36 @@
main {
sub ftrue(ubyte arg) -> ubyte {
arg++
txt.print(" ftrue ")
return 1
}
ubyte key
sub pushing_fire() -> ubyte {
return key == 'z'
}
sub pushing_left() -> ubyte {
return key == 'k' or key == 157
}
sub pushing_right() -> ubyte {
return key == 'l' or key == 29
}
sub start() {
bool ub1 = true
bool ub2 = true
bool ub3 = true
bool ub4 = 0
bool bvalue
void pushing_fire()
void pushing_left()
void pushing_right()
txt.print("expected output: 0 ftrue 0 ftrue 1\n")
bvalue = ub1 xor ub2 xor ub3 xor true
txt.print_ub(bvalue)
txt.spc()
bvalue = ub1 xor ub2 xor ub3 xor ftrue(99)
txt.print_ub(bvalue)
txt.spc()
bvalue = ub1 and ub2 and ftrue(99)
txt.print_ub(bvalue)
ubyte rnr = $99
ubyte wordNr = ((rnr >= $33) as ubyte) +
((rnr >= $66) as ubyte) +
((rnr >= $99) as ubyte) +
((rnr >= $CC) as ubyte)
ubyte wordNr2 = (rnr >= $33) as ubyte + (rnr >= $66) as ubyte + (rnr >= $99) as ubyte + (rnr >= $CC) as ubyte
txt.print_uw(wordNr)
txt.nl()
txt.print_uw(wordNr2)
txt.nl()
}
}