mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
tweak bool type handling
This commit is contained in:
parent
92eb3b0bf6
commit
7a26646e1b
@ -8,6 +8,12 @@ import kotlin.math.round
|
|||||||
|
|
||||||
|
|
||||||
sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) {
|
sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
if(type==DataType.BOOL)
|
||||||
|
throw java.lang.IllegalArgumentException("bool should have become ubyte @$position")
|
||||||
|
}
|
||||||
|
|
||||||
override fun printProperties() {
|
override fun printProperties() {
|
||||||
print(type)
|
print(type)
|
||||||
}
|
}
|
||||||
@ -127,10 +133,12 @@ class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position)
|
|||||||
class PtNumber(type: DataType, val number: Double, position: Position) : PtExpression(type, position) {
|
class PtNumber(type: DataType, val number: Double, position: Position) : PtExpression(type, position) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if(type==DataType.BOOL)
|
||||||
|
throw java.lang.IllegalArgumentException("bool should have become ubyte @$position")
|
||||||
if(type!=DataType.FLOAT) {
|
if(type!=DataType.FLOAT) {
|
||||||
val rounded = round(number)
|
val rounded = round(number)
|
||||||
if (rounded != number)
|
if (rounded != number)
|
||||||
throw IllegalArgumentException("refused rounding of float to avoid loss of precision")
|
throw IllegalArgumentException("refused rounding of float to avoid loss of precision @$position")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
|||||||
val LogicalOperators = setOf("and", "or", "xor", "not")
|
val LogicalOperators = setOf("and", "or", "xor", "not")
|
||||||
val AugmentAssignmentOperators = setOf("+", "-", "/", "*", "&", "|", "^", "<<", ">>", "%")
|
val AugmentAssignmentOperators = setOf("+", "-", "/", "*", "&", "|", "^", "<<", ">>", "%")
|
||||||
val BitwiseOperators = setOf("&", "|", "^", "~")
|
val BitwiseOperators = setOf("&", "|", "^", "~")
|
||||||
|
val InvalidOperatorsForBoolean = setOf("-", "*", "/", "%", "<<", ">>") // TODO what about +? TODO add BitWiseOperators
|
||||||
|
|
||||||
fun invertedComparisonOperator(operator: String) =
|
fun invertedComparisonOperator(operator: String) =
|
||||||
when (operator) {
|
when (operator) {
|
||||||
|
@ -1165,14 +1165,14 @@ $repeatLabel lda $counterVar
|
|||||||
return testVariableZeroAndJump(left, dt, operator, jumpIfFalseLabel)
|
return testVariableZeroAndJump(left, dt, operator, jumpIfFalseLabel)
|
||||||
|
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE, DataType.UWORD -> {
|
DataType.BOOL, DataType.UBYTE, DataType.UWORD -> {
|
||||||
if(operator=="<") {
|
if(operator=="<") {
|
||||||
out(" jmp $jumpIfFalseLabel")
|
out(" jmp $jumpIfFalseLabel")
|
||||||
return
|
return
|
||||||
} else if(operator==">=") {
|
} else if(operator==">=") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(dt==DataType.UBYTE) {
|
if(dt==DataType.UBYTE || dt==DataType.BOOL) {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.A, false)
|
assignExpressionToRegister(left, RegisterOrPair.A, false)
|
||||||
if (left is IFunctionCall && !left.isSimple)
|
if (left is IFunctionCall && !left.isSimple)
|
||||||
out(" cmp #0")
|
out(" cmp #0")
|
||||||
@ -1252,7 +1252,7 @@ $repeatLabel lda $counterVar
|
|||||||
// optimized code if the expression is just an identifier (variable)
|
// optimized code if the expression is just an identifier (variable)
|
||||||
val varname = asmVariableName(variable)
|
val varname = asmVariableName(variable)
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE -> when(operator) {
|
DataType.UBYTE, DataType.BOOL -> when(operator) {
|
||||||
"==" -> out(" lda $varname | bne $jumpIfFalseLabel")
|
"==" -> out(" lda $varname | bne $jumpIfFalseLabel")
|
||||||
"!=" -> out(" lda $varname | beq $jumpIfFalseLabel")
|
"!=" -> out(" lda $varname | beq $jumpIfFalseLabel")
|
||||||
">" -> out(" lda $varname | beq $jumpIfFalseLabel")
|
">" -> out(" lda $varname | beq $jumpIfFalseLabel")
|
||||||
|
@ -136,7 +136,7 @@ internal class ExpressionsAsmGen(private val program: Program,
|
|||||||
private fun translateExpression(typecast: TypecastExpression) {
|
private fun translateExpression(typecast: TypecastExpression) {
|
||||||
translateExpressionInternal(typecast.expression)
|
translateExpressionInternal(typecast.expression)
|
||||||
when(typecast.expression.inferType(program).getOr(DataType.UNDEFINED)) {
|
when(typecast.expression.inferType(program).getOr(DataType.UNDEFINED)) {
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE, DataType.BOOL -> {
|
||||||
when(typecast.type) {
|
when(typecast.type) {
|
||||||
DataType.UBYTE, DataType.BYTE -> {}
|
DataType.UBYTE, DataType.BYTE -> {}
|
||||||
DataType.UWORD, DataType.WORD -> {
|
DataType.UWORD, DataType.WORD -> {
|
||||||
|
@ -10,9 +10,7 @@ import prog8.ast.determineGosubArguments
|
|||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.*
|
||||||
import prog8.code.core.Position
|
|
||||||
import prog8.code.core.SourceCode
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.isRegularFile
|
import kotlin.io.path.isRegularFile
|
||||||
@ -405,7 +403,17 @@ class IntermediateAstMaker(val program: Program) {
|
|||||||
|
|
||||||
private fun transform(srcExpr: BinaryExpression): PtBinaryExpression {
|
private fun transform(srcExpr: BinaryExpression): PtBinaryExpression {
|
||||||
val type = srcExpr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
|
val type = srcExpr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
|
||||||
val expr = PtBinaryExpression(srcExpr.operator, type, srcExpr.position)
|
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 expr = PtBinaryExpression(srcExpr.operator, actualType, srcExpr.position)
|
||||||
expr.add(transformExpression(srcExpr.left))
|
expr.add(transformExpression(srcExpr.left))
|
||||||
expr.add(transformExpression(srcExpr.right))
|
expr.add(transformExpression(srcExpr.right))
|
||||||
return expr
|
return expr
|
||||||
|
@ -481,7 +481,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
|
|
||||||
if(assignment.isAugmentable && targetDt istype DataType.BOOL) {
|
if(assignment.isAugmentable && targetDt istype DataType.BOOL) {
|
||||||
val operator = (assignment.value as? BinaryExpression)?.operator
|
val operator = (assignment.value as? BinaryExpression)?.operator
|
||||||
if(operator in setOf("-", "*", "/", "%"))
|
if(operator in InvalidOperatorsForBoolean)
|
||||||
errors.err("can't use boolean operand with this operator $operator", assignment.position)
|
errors.err("can't use boolean operand with this operator $operator", assignment.position)
|
||||||
}
|
}
|
||||||
super.visit(assignment)
|
super.visit(assignment)
|
||||||
@ -918,7 +918,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
if(expr.operator in setOf("<", "<=", ">", ">=")) {
|
if(expr.operator in setOf("<", "<=", ">", ">=")) {
|
||||||
errors.err("can't use boolean operand with this comparison operator", expr.position)
|
errors.err("can't use boolean operand with this comparison operator", expr.position)
|
||||||
}
|
}
|
||||||
if(expr.operator in setOf("-", "*", "/", "%") && (leftDt==DataType.BOOL || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) {
|
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)
|
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)) {
|
if(expr.operator=="+" && (leftDt==DataType.BOOL || (expr.left as? TypecastExpression)?.expression?.inferType(program)?.istype(DataType.BOOL)==true)) {
|
||||||
|
@ -10,6 +10,7 @@ import prog8.ast.statements.VarDeclOrigin
|
|||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
import prog8.compiler.printProgram
|
||||||
|
|
||||||
|
|
||||||
internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) {
|
internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) {
|
||||||
|
@ -96,21 +96,6 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp
|
|||||||
return listOf(IAstModification.ReplaceNode(expr, containment, parent))
|
return listOf(IAstModification.ReplaceNode(expr, containment, parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert boolean and/or/xor/not operators to bitwise equivalents.
|
|
||||||
// the rest of the ast and 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.ReplaceNodeSafe(expr.left, wrapWithBooleanCast(expr.left), expr),
|
|
||||||
IAstModification.ReplaceNodeSafe(expr.right, wrapWithBooleanCast(expr.right), expr),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,27 +132,4 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp
|
|||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapWithBooleanCast(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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,6 @@ internal class BeforeAsmAstChanger(val program: Program,
|
|||||||
private val errors: IErrorReporter
|
private val errors: IErrorReporter
|
||||||
) : AstWalker() {
|
) : AstWalker() {
|
||||||
|
|
||||||
override fun after(numLiteral: NumericLiteral, parent: Node): Iterable<IAstModification> {
|
|
||||||
if(numLiteral.type==DataType.BOOL)
|
|
||||||
return listOf(IAstModification.ReplaceNode(numLiteral, NumericLiteral(DataType.UBYTE, numLiteral.number, numLiteral.position), parent))
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||||
throw InternalCompilerException("break should have been replaced by goto $breakStmt")
|
throw InternalCompilerException("break should have been replaced by goto $breakStmt")
|
||||||
}
|
}
|
||||||
@ -67,14 +61,30 @@ internal class BeforeAsmAstChanger(val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(decl.datatype==DataType.BOOL) {
|
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,
|
val ubyteDecl = VarDecl(decl.type, decl.origin, DataType.UBYTE, decl.zeropage, decl.arraysize, decl.name,
|
||||||
decl.value, decl.isArray, decl.sharedWithAsm, decl.subroutineParameter, decl.position)
|
newvalue, decl.isArray, decl.sharedWithAsm, decl.subroutineParameter, decl.position)
|
||||||
return listOf(IAstModification.ReplaceNode(decl, ubyteDecl, parent))
|
return listOf(IAstModification.ReplaceNode(decl, ubyteDecl, parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
if(decl.datatype==DataType.ARRAY_BOOL) {
|
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,
|
val ubyteArrayDecl = VarDecl(decl.type, decl.origin, DataType.ARRAY_UB, decl.zeropage, decl.arraysize, decl.name,
|
||||||
decl.value, decl.isArray, decl.sharedWithAsm, decl.subroutineParameter, decl.position)
|
newarray, true, decl.sharedWithAsm, decl.subroutineParameter, decl.position)
|
||||||
return listOf(IAstModification.ReplaceNode(decl, ubyteArrayDecl, parent))
|
return listOf(IAstModification.ReplaceNode(decl, ubyteArrayDecl, parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +220,23 @@ internal class BeforeAsmAstChanger(val program: Program,
|
|||||||
return mods
|
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> {
|
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
|
||||||
val binExpr = ifElse.condition as? BinaryExpression
|
val binExpr = ifElse.condition as? BinaryExpression
|
||||||
if(binExpr==null) {
|
if(binExpr==null) {
|
||||||
@ -410,4 +437,27 @@ internal class BeforeAsmAstChanger(val program: Program,
|
|||||||
)
|
)
|
||||||
return modifications
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,7 @@ internal class NotExpressionChanger(val program: Program, val errors: IErrorRepo
|
|||||||
|
|
||||||
// all other not(x) --> x==0
|
// all other not(x) --> x==0
|
||||||
// this means that "not" will never occur anywhere again in the ast after this
|
// this means that "not" will never occur anywhere again in the ast after this
|
||||||
val dt = expr.expression.inferType(program).getOr(DataType.UBYTE)
|
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral(DataType.UBYTE,0.0, expr.position), expr.position)
|
||||||
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral(dt,0.0, expr.position), expr.position)
|
|
||||||
return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent))
|
return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent))
|
||||||
}
|
}
|
||||||
return noModifications
|
return noModifications
|
||||||
|
@ -478,6 +478,11 @@ class NumericLiteral(val type: DataType, // only numerical types allowed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
if(type==DataType.BOOL)
|
||||||
|
throw FatalAstException("should not create NumericLiteral with BOOL type @$position")
|
||||||
|
}
|
||||||
|
|
||||||
val asBooleanValue: Boolean = number != 0.0
|
val asBooleanValue: Boolean = number != 0.0
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
override fun linkParents(parent: Node) {
|
||||||
|
@ -3,7 +3,8 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- fix code gen crashes in logical.p8 / testtypecasts
|
- fix vm code result of test.p8 (ftrue() not called at all!?)
|
||||||
|
- add more operators to InvalidOperatorsForBoolean
|
||||||
|
|
||||||
- have a proper option to move the evalstack rather than just assembly symbol redefine
|
- 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
|
- then make the cx16 virtual registers in syslib.p8 use that definition to be able to shift them around on non-cx16 targets
|
||||||
|
@ -3,20 +3,28 @@
|
|||||||
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
sub ftrue(ubyte arg) -> ubyte {
|
||||||
ubyte key
|
arg++
|
||||||
|
txt.print(" ftrue ")
|
||||||
sub func() -> ubyte {
|
return 1
|
||||||
return key=='a'
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub func2() -> bool {
|
|
||||||
return key==2
|
|
||||||
}
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
bool @shared z1=func()
|
bool ub1 = true
|
||||||
bool @shared z2=func2()
|
bool ub2 = true
|
||||||
|
bool ub3 = true
|
||||||
|
bool ub4 = 0
|
||||||
|
bool bvalue
|
||||||
|
|
||||||
|
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)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user