Merge branch 'new-expr-codegen'

# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt
#	codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt
#	examples/test.p8
This commit is contained in:
Irmen de Jong 2023-03-29 23:56:16 +02:00
commit 2d85fd093e
22 changed files with 1430 additions and 236 deletions

View File

@ -180,7 +180,13 @@ class PtFunctionCall(val name: String,
} }
class PtIdentifier(val name: String, type: DataType, position: Position) : PtExpression(type, position) class PtIdentifier(val name: String, type: DataType, position: Position) : PtExpression(type, position) {
override fun toString(): String {
return "[PtIdentifier:$name $type $position]"
}
fun copy() = PtIdentifier(name, type, position)
}
class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position) { class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position) {

View File

@ -38,20 +38,17 @@ class PtSub(
class PtSubroutineParameter(name: String, val type: DataType, position: Position): PtNamedNode(name, position) class PtSubroutineParameter(name: String, val type: DataType, position: Position): PtNamedNode(name, position)
class PtAssignment(position: Position) : PtNode(position) { sealed interface IPtAssignment {
val children: MutableList<PtNode>
val target: PtAssignTarget val target: PtAssignTarget
get() = children[0] as PtAssignTarget get() = children[0] as PtAssignTarget
val value: PtExpression val value: PtExpression
get() = children[1] as PtExpression get() = children[1] as PtExpression
} }
class PtAssignment(position: Position) : PtNode(position), IPtAssignment
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position) { class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position), IPtAssignment
val target: PtAssignTarget
get() = children[0] as PtAssignTarget
val value: PtExpression
get() = children[1] as PtExpression
}
class PtAssignTarget(position: Position) : PtNode(position) { class PtAssignTarget(position: Position) : PtNode(position) {
@ -95,7 +92,7 @@ class PtForLoop(position: Position) : PtNode(position) {
class PtIfElse(position: Position) : PtNode(position) { class PtIfElse(position: Position) : PtNode(position) {
val condition: PtExpression // either PtRpn or PtBinaryExpression val condition: PtExpression
get() = children[0] as PtExpression get() = children[0] as PtExpression
val ifScope: PtNodeGroup val ifScope: PtNodeGroup
get() = children[1] as PtNodeGroup get() = children[1] as PtNodeGroup

View File

@ -79,6 +79,7 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
"reverse" to FSignature(false, listOf(FParam("array", ArrayDatatypes)), null), "reverse" to FSignature(false, listOf(FParam("array", ArrayDatatypes)), null),
// cmp returns a status in the carry flag, but not a proper return value // cmp returns a status in the carry flag, but not a proper return value
"cmp" to FSignature(false, listOf(FParam("value1", IntegerDatatypesNoBool), FParam("value2", NumericDatatypesNoBool)), null), "cmp" to FSignature(false, listOf(FParam("value1", IntegerDatatypesNoBool), FParam("value2", NumericDatatypesNoBool)), null),
"prog8_lib_stringcompare" to FSignature(true, listOf(FParam("str1", arrayOf(DataType.STR)), FParam("str2", arrayOf(DataType.STR))), DataType.BYTE),
"abs" to FSignature(true, listOf(FParam("value", IntegerDatatypesNoBool)), DataType.UWORD), "abs" to FSignature(true, listOf(FParam("value", IntegerDatatypesNoBool)), DataType.UWORD),
"len" to FSignature(true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD), "len" to FSignature(true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD),
// normal functions follow: // normal functions follow:

View File

@ -21,13 +21,6 @@ class AsmGen6502: ICodeGeneratorBackend {
options: CompilationOptions, options: CompilationOptions,
errors: IErrorReporter errors: IErrorReporter
): IAssemblyProgram? { ): IAssemblyProgram? {
if(options.useNewExprCode) {
// TODO("transform BinExprs?")
// errors.warn("EXPERIMENTAL NEW EXPRESSION CODEGEN IS USED. CODE SIZE+SPEED POSSIBLY SUFFERS.", Position.DUMMY)
}
// printAst(program, true) { println(it) }
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors) val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
return asmgen.compileToAssembly() return asmgen.compileToAssembly()
} }
@ -551,28 +544,76 @@ class AsmGen6502Internal (
} }
private fun translate(stmt: PtIfElse) { private fun translate(stmt: PtIfElse) {
val condition = stmt.condition as PtBinaryExpression val condition = stmt.condition as? PtBinaryExpression
requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>' if(condition!=null) {
if (stmt.elseScope.children.isEmpty()) { require(!options.useNewExprCode)
val jump = stmt.ifScope.children.singleOrNull() requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>'
if (jump is PtJump) { if (stmt.elseScope.children.isEmpty()) {
translateCompareAndJumpIfTrue(condition, jump) val jump = stmt.ifScope.children.singleOrNull()
if (jump is PtJump) {
translateCompareAndJumpIfTrue(condition, jump)
} else {
val endLabel = makeLabel("if_end")
translateCompareOrJumpIfFalse(condition, endLabel)
translate(stmt.ifScope)
out(endLabel)
}
} else { } else {
// both true and else parts
val elseLabel = makeLabel("if_else")
val endLabel = makeLabel("if_end") val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalse(condition, endLabel) translateCompareOrJumpIfFalse(condition, elseLabel)
translate(stmt.ifScope) translate(stmt.ifScope)
jmp(endLabel)
out(elseLabel)
translate(stmt.elseScope)
out(endLabel) out(endLabel)
} }
} else { } else {
// both true and else parts // condition is a simple expression "if X" --> "if X!=0"
val elseLabel = makeLabel("if_else") val zero = PtNumber(DataType.UBYTE,0.0, stmt.position)
val endLabel = makeLabel("if_end") val leftConst = stmt.condition as? PtNumber
translateCompareAndJumpIfFalse(condition, elseLabel) if (stmt.elseScope.children.isEmpty()) {
translate(stmt.ifScope) val jump = stmt.ifScope.children.singleOrNull()
jmp(endLabel) if (jump is PtJump) {
out(elseLabel) // jump somewhere if X!=0
translate(stmt.elseScope) val label = when {
out(endLabel) jump.generatedLabel!=null -> jump.generatedLabel!!
jump.identifier!=null -> asmSymbolName(jump.identifier!!)
jump.address!=null -> jump.address!!.toHex()
else -> throw AssemblyError("weird jump")
}
when(stmt.condition.type) {
in WordDatatypes -> translateWordEqualsOrJumpElsewhere(stmt.condition, zero, leftConst, zero, label)
in ByteDatatypes -> translateByteEqualsOrJumpElsewhere(stmt.condition, zero, leftConst, zero, label)
else -> throw AssemblyError("weird condition dt")
}
} else {
// skip the true block (=jump to end label) if X==0
val endLabel = makeLabel("if_end")
when(stmt.condition.type) {
in WordDatatypes -> translateWordNotEqualsOrJumpElsewhere(stmt.condition, zero, leftConst, zero, endLabel)
in ByteDatatypes -> translateByteNotEqualsOrJumpElsewhere(stmt.condition, zero, leftConst, zero, endLabel)
else -> throw AssemblyError("weird condition dt")
}
translate(stmt.ifScope)
out(endLabel)
}
} else {
// both true and else parts
val elseLabel = makeLabel("if_else")
val endLabel = makeLabel("if_end")
when(stmt.condition.type) {
in WordDatatypes -> translateWordNotEqualsOrJumpElsewhere(stmt.condition, zero, leftConst, zero, elseLabel)
in ByteDatatypes -> translateByteNotEqualsOrJumpElsewhere(stmt.condition, zero, leftConst, zero, elseLabel)
else -> throw AssemblyError("weird condition dt")
}
translate(stmt.ifScope)
jmp(endLabel)
out(elseLabel)
translate(stmt.elseScope)
out(endLabel)
}
} }
} }
@ -740,7 +781,7 @@ $repeatLabel lda $counterVar
} }
val isNested = parent is PtRepeatLoop val isNested = parent is PtRepeatLoop
if(!isNested && !options.useNewExprCode) { if(!isNested) {
// we can re-use a counter var from the subroutine if it already has one for that datatype // we can re-use a counter var from the subroutine if it already has one for that datatype
val existingVar = asmInfo.extraVars.firstOrNull { it.first==dt && it.second.endsWith("counter") } val existingVar = asmInfo.extraVars.firstOrNull { it.first==dt && it.second.endsWith("counter") }
if(existingVar!=null) { if(existingVar!=null) {
@ -987,6 +1028,7 @@ $repeatLabel lda $counterVar
val operator: String val operator: String
if (pointerOffsetExpr is PtBinaryExpression) { if (pointerOffsetExpr is PtBinaryExpression) {
require(!options.useNewExprCode)
operator = pointerOffsetExpr.operator operator = pointerOffsetExpr.operator
left = pointerOffsetExpr.left left = pointerOffsetExpr.left
right = pointerOffsetExpr.right right = pointerOffsetExpr.right
@ -1132,15 +1174,16 @@ $repeatLabel lda $counterVar
jump.address!=null -> jump.address!!.toHex() jump.address!=null -> jump.address!!.toHex()
else -> throw AssemblyError("weird jump") else -> throw AssemblyError("weird jump")
} }
if (rightConstVal!=null && rightConstVal.number == 0.0) if (rightConstVal!=null && rightConstVal.number == 0.0) {
testZeroAndJump(left, invertedComparisonOperator, label) testZeroOrJumpElsewhere(left, invertedComparisonOperator, label)
}
else { else {
val leftConstVal = left as? PtNumber val leftConstVal = left as? PtNumber
testNonzeroComparisonAndJump(left, invertedComparisonOperator, right, label, leftConstVal, rightConstVal) testNonzeroComparisonOrJumpElsewhere(left, invertedComparisonOperator, right, label, leftConstVal, rightConstVal)
} }
} }
private fun translateCompareAndJumpIfFalse(expr: PtBinaryExpression, jumpIfFalseLabel: String) { private fun translateCompareOrJumpIfFalse(expr: PtBinaryExpression, jumpIfFalseLabel: String) {
val left = expr.left val left = expr.left
val right = expr.right val right = expr.right
val operator = expr.operator val operator = expr.operator
@ -1148,19 +1191,19 @@ $repeatLabel lda $counterVar
val rightConstVal = right as? PtNumber val rightConstVal = right as? PtNumber
if (rightConstVal!=null && rightConstVal.number == 0.0) if (rightConstVal!=null && rightConstVal.number == 0.0)
testZeroAndJump(left, operator, jumpIfFalseLabel) testZeroOrJumpElsewhere(left, operator, jumpIfFalseLabel)
else else
testNonzeroComparisonAndJump(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal) testNonzeroComparisonOrJumpElsewhere(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal)
} }
private fun testZeroAndJump( private fun testZeroOrJumpElsewhere(
left: PtExpression, left: PtExpression,
operator: String, operator: String,
jumpIfFalseLabel: String jumpIfFalseLabel: String
) { ) {
val dt = left.type val dt = left.type
if(dt in IntegerDatatypes && left is PtIdentifier) if(dt in IntegerDatatypes && left is PtIdentifier)
return testVariableZeroAndJump(left, dt, operator, jumpIfFalseLabel) return testVariableZeroOrJumpElsewhere(left, dt, operator, jumpIfFalseLabel)
when(dt) { when(dt) {
DataType.BOOL, DataType.UBYTE, DataType.UWORD -> { DataType.BOOL, DataType.UBYTE, DataType.UWORD -> {
@ -1246,7 +1289,7 @@ $repeatLabel lda $counterVar
} }
} }
private fun testVariableZeroAndJump(variable: PtIdentifier, dt: DataType, operator: String, jumpIfFalseLabel: String) { private fun testVariableZeroOrJumpElsewhere(variable: PtIdentifier, dt: DataType, operator: String, jumpIfFalseLabel: String) {
// 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) {
@ -1306,7 +1349,7 @@ $repeatLabel lda $counterVar
} }
} }
internal fun testNonzeroComparisonAndJump( internal fun testNonzeroComparisonOrJumpElsewhere(
left: PtExpression, left: PtExpression,
operator: String, operator: String,
right: PtExpression, right: PtExpression,
@ -1319,70 +1362,70 @@ $repeatLabel lda $counterVar
when (operator) { when (operator) {
"==" -> { "==" -> {
when (dt) { when (dt) {
in ByteDatatypes -> translateByteEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) in ByteDatatypes -> translateByteEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) in WordDatatypes -> translateWordEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.FLOAT -> translateFloatEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringEqualsJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) DataType.STR -> translateStringEqualsOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype") else -> throw AssemblyError("weird operand datatype")
} }
} }
"!=" -> { "!=" -> {
when (dt) { when (dt) {
in ByteDatatypes -> translateByteNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) in ByteDatatypes -> translateByteNotEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) in WordDatatypes -> translateWordNotEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.FLOAT -> translateFloatNotEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringNotEqualsJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) DataType.STR -> translateStringNotEqualsOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype") else -> throw AssemblyError("weird operand datatype")
} }
} }
"<" -> { "<" -> {
when(dt) { when(dt) {
DataType.UBYTE -> translateUbyteLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.UBYTE -> translateUbyteLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.BYTE -> translateByteLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.UWORD -> translateUwordLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.WORD -> translateWordLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.FLOAT -> translateFloatLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringLessJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) DataType.STR -> translateStringLessOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype") else -> throw AssemblyError("weird operand datatype")
} }
} }
"<=" -> { "<=" -> {
when(dt) { when(dt) {
DataType.UBYTE -> translateUbyteLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.UBYTE -> translateUbyteLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.BYTE -> translateByteLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.UWORD -> translateUwordLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.WORD -> translateWordLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.FLOAT -> translateFloatLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringLessOrEqualJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) DataType.STR -> translateStringLessOrEqualOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype") else -> throw AssemblyError("weird operand datatype")
} }
} }
">" -> { ">" -> {
when(dt) { when(dt) {
DataType.UBYTE -> translateUbyteGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.UBYTE -> translateUbyteGreaterOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.BYTE -> translateByteGreaterOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.UWORD -> translateUwordGreaterOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.WORD -> translateWordGreaterOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatGreaterJump(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel) DataType.FLOAT -> translateFloatGreaterOrJumpElsewhere(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringGreaterJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) DataType.STR -> translateStringGreaterOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype") else -> throw AssemblyError("weird operand datatype")
} }
} }
">=" -> { ">=" -> {
when(dt) { when(dt) {
DataType.UBYTE -> translateUbyteGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.UBYTE -> translateUbyteGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.BYTE -> translateByteGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.UWORD -> translateUwordGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.WORD -> translateWordGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) DataType.FLOAT -> translateFloatGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringGreaterOrEqualJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) DataType.STR -> translateStringGreaterOrEqualOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype") else -> throw AssemblyError("weird operand datatype")
} }
} }
} }
} }
private fun translateFloatLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateFloatLessOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
if(leftConstVal!=null && rightConstVal!=null) { if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away") throw AssemblyError("const-compare should have been optimized away")
} }
@ -1427,7 +1470,7 @@ $repeatLabel lda $counterVar
} }
} }
private fun translateFloatLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateFloatLessOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
if(leftConstVal!=null && rightConstVal!=null) { if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away") throw AssemblyError("const-compare should have been optimized away")
} }
@ -1472,7 +1515,7 @@ $repeatLabel lda $counterVar
} }
} }
private fun translateFloatGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateFloatGreaterOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
if(leftConstVal!=null && rightConstVal!=null) { if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away") throw AssemblyError("const-compare should have been optimized away")
} }
@ -1517,7 +1560,7 @@ $repeatLabel lda $counterVar
} }
} }
private fun translateFloatGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateFloatGreaterOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
if(leftConstVal!=null && rightConstVal!=null) { if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away") throw AssemblyError("const-compare should have been optimized away")
} }
@ -1562,7 +1605,7 @@ $repeatLabel lda $counterVar
} }
} }
private fun translateUbyteLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateUbyteLessOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(cmpOperand: String) { fun code(cmpOperand: String) {
out(" cmp $cmpOperand | bcs $jumpIfFalseLabel") out(" cmp $cmpOperand | bcs $jumpIfFalseLabel")
@ -1607,7 +1650,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateByteLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateByteLessOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(sbcOperand: String) { fun code(sbcOperand: String) {
out(""" out("""
@ -1648,7 +1691,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateUwordLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateUwordLessOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(msbCpyOperand: String, lsbCmpOperand: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) {
out(""" out("""
@ -1692,7 +1735,7 @@ $repeatLabel lda $counterVar
return out(" jsr prog8_lib.reg_less_uw | beq $jumpIfFalseLabel") return out(" jsr prog8_lib.reg_less_uw | beq $jumpIfFalseLabel")
} }
private fun translateWordLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateWordLessOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(msbCpyOperand: String, lsbCmpOperand: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) {
out(""" out("""
@ -1738,7 +1781,7 @@ $repeatLabel lda $counterVar
return out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel") return out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel")
} }
private fun translateUbyteGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateUbyteGreaterOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(cmpOperand: String) { fun code(cmpOperand: String) {
out(""" out("""
@ -1784,7 +1827,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateByteGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateByteGreaterOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(sbcOperand: String) { fun code(sbcOperand: String) {
out(""" out("""
@ -1827,7 +1870,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateUwordGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateUwordGreaterOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(msbCpyOperand: String, lsbCmpOperand: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) {
out(""" out("""
@ -1877,7 +1920,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_W2+1", "P8ZP_SCRATCH_W2") return code("P8ZP_SCRATCH_W2+1", "P8ZP_SCRATCH_W2")
} }
private fun translateWordGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateWordGreaterOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(msbCmpOperand: String, lsbCmpOperand: String) { fun code(msbCmpOperand: String, lsbCmpOperand: String) {
out(""" out("""
@ -1928,7 +1971,7 @@ $repeatLabel lda $counterVar
return out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel") return out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel")
} }
private fun translateUbyteLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateUbyteLessOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(cmpOperand: String) { fun code(cmpOperand: String) {
out(""" out("""
@ -1975,7 +2018,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateByteLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateByteLessOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(sbcOperand: String) { fun code(sbcOperand: String) {
out(""" out("""
clc clc
@ -2018,7 +2061,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateUwordLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateUwordLessOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(msbCpyOperand: String, lsbCmpOperand: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) {
out(""" out("""
@ -2070,7 +2113,7 @@ $repeatLabel lda $counterVar
return out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel") return out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel")
} }
private fun translateWordLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateWordLessOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(leftName: String) { fun code(leftName: String) {
out(""" out("""
@ -2125,7 +2168,7 @@ $repeatLabel lda $counterVar
return out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel") return out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel")
} }
private fun translateUbyteGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateUbyteGreaterOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(cmpOperand: String) { fun code(cmpOperand: String) {
out(" cmp $cmpOperand | bcc $jumpIfFalseLabel") out(" cmp $cmpOperand | bcc $jumpIfFalseLabel")
@ -2168,7 +2211,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateByteGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateByteGreaterOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(sbcOperand: String) { fun code(sbcOperand: String) {
out(""" out("""
sec sec
@ -2208,7 +2251,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateUwordGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateUwordGreaterOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(msbCpyOperand: String, lsbCmpOperand: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) {
out(""" out("""
@ -2251,7 +2294,7 @@ $repeatLabel lda $counterVar
return out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel") return out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel")
} }
private fun translateWordGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateWordGreaterOrEqualOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(msbCpyOperand: String, lsbCmpOperand: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) {
out(""" out("""
@ -2297,7 +2340,7 @@ $repeatLabel lda $counterVar
return out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel") return out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel")
} }
private fun translateByteEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateByteEqualsOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(cmpOperand: String) { fun code(cmpOperand: String) {
out(" cmp $cmpOperand | bne $jumpIfFalseLabel") out(" cmp $cmpOperand | bne $jumpIfFalseLabel")
} }
@ -2342,7 +2385,7 @@ $repeatLabel lda $counterVar
out(" cmp P8ZP_SCRATCH_B1 | bne $jumpIfFalseLabel") out(" cmp P8ZP_SCRATCH_B1 | bne $jumpIfFalseLabel")
} }
private fun translateByteNotEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateByteNotEqualsOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
fun code(cmpOperand: String) { fun code(cmpOperand: String) {
out(" cmp $cmpOperand | beq $jumpIfFalseLabel") out(" cmp $cmpOperand | beq $jumpIfFalseLabel")
@ -2388,7 +2431,7 @@ $repeatLabel lda $counterVar
return code("P8ZP_SCRATCH_B1") return code("P8ZP_SCRATCH_B1")
} }
private fun translateWordEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateWordEqualsOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) { if(rightConstVal!=null) {
if(leftConstVal!=null) { if(leftConstVal!=null) {
if(rightConstVal!=leftConstVal) if(rightConstVal!=leftConstVal)
@ -2472,7 +2515,7 @@ $repeatLabel lda $counterVar
} }
private fun translateWordNotEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateWordNotEqualsOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) { if(rightConstVal!=null) {
if(leftConstVal!=null) { if(leftConstVal!=null) {
@ -2560,7 +2603,7 @@ $repeatLabel lda $counterVar
} }
private fun translateFloatEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateFloatEqualsOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) { if(rightConstVal!=null) {
if(leftConstVal!=null) { if(leftConstVal!=null) {
if(rightConstVal!=leftConstVal) if(rightConstVal!=leftConstVal)
@ -2644,7 +2687,7 @@ $repeatLabel lda $counterVar
} }
} }
private fun translateFloatNotEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { private fun translateFloatNotEqualsOrJumpElsewhere(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) { if(rightConstVal!=null) {
if(leftConstVal!=null) { if(leftConstVal!=null) {
if(rightConstVal==leftConstVal) if(rightConstVal==leftConstVal)
@ -2729,7 +2772,7 @@ $repeatLabel lda $counterVar
} }
} }
private fun translateStringEqualsJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { private fun translateStringEqualsOrJumpElsewhere(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) {
val leftNam = asmVariableName(left) val leftNam = asmVariableName(left)
val rightNam = asmVariableName(right) val rightNam = asmVariableName(right)
out(""" out("""
@ -2740,11 +2783,10 @@ $repeatLabel lda $counterVar
lda #<$leftNam lda #<$leftNam
ldy #>$leftNam ldy #>$leftNam
jsr prog8_lib.strcmp_mem jsr prog8_lib.strcmp_mem
cmp #0
bne $jumpIfFalseLabel""") bne $jumpIfFalseLabel""")
} }
private fun translateStringNotEqualsJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { private fun translateStringNotEqualsOrJumpElsewhere(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) {
val leftNam = asmVariableName(left) val leftNam = asmVariableName(left)
val rightNam = asmVariableName(right) val rightNam = asmVariableName(right)
out(""" out("""
@ -2755,11 +2797,10 @@ $repeatLabel lda $counterVar
lda #<$leftNam lda #<$leftNam
ldy #>$leftNam ldy #>$leftNam
jsr prog8_lib.strcmp_mem jsr prog8_lib.strcmp_mem
cmp #0
beq $jumpIfFalseLabel""") beq $jumpIfFalseLabel""")
} }
private fun translateStringLessJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { private fun translateStringLessOrJumpElsewhere(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) {
val leftNam = asmVariableName(left) val leftNam = asmVariableName(left)
val rightNam = asmVariableName(right) val rightNam = asmVariableName(right)
out(""" out("""
@ -2773,7 +2814,7 @@ $repeatLabel lda $counterVar
bpl $jumpIfFalseLabel""") bpl $jumpIfFalseLabel""")
} }
private fun translateStringGreaterJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { private fun translateStringGreaterOrJumpElsewhere(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) {
val leftNam = asmVariableName(left) val leftNam = asmVariableName(left)
val rightNam = asmVariableName(right) val rightNam = asmVariableName(right)
out(""" out("""
@ -2788,7 +2829,7 @@ $repeatLabel lda $counterVar
bmi $jumpIfFalseLabel""") bmi $jumpIfFalseLabel""")
} }
private fun translateStringLessOrEqualJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { private fun translateStringLessOrEqualOrJumpElsewhere(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) {
val leftNam = asmVariableName(left) val leftNam = asmVariableName(left)
val rightNam = asmVariableName(right) val rightNam = asmVariableName(right)
out(""" out("""
@ -2804,7 +2845,7 @@ $repeatLabel lda $counterVar
+""") +""")
} }
private fun translateStringGreaterOrEqualJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { private fun translateStringGreaterOrEqualOrJumpElsewhere(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) {
val leftNam = asmVariableName(left) val leftNam = asmVariableName(left)
val rightNam = asmVariableName(right) val rightNam = asmVariableName(right)
out(""" out("""
@ -2853,6 +2894,7 @@ $repeatLabel lda $counterVar
out(" sta P8ESTACK_LO,x | dex") out(" sta P8ESTACK_LO,x | dex")
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!options.useNewExprCode)
val addrExpr = expr.address as PtBinaryExpression val addrExpr = expr.address as PtBinaryExpression
if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) { if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
if(pushResultOnEstack) if(pushResultOnEstack)

View File

@ -72,6 +72,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
"rrestorex" -> funcRrestoreX() "rrestorex" -> funcRrestoreX()
"cmp" -> funcCmp(fcall) "cmp" -> funcCmp(fcall)
"callfar" -> funcCallFar(fcall) "callfar" -> funcCallFar(fcall)
"prog8_lib_stringcompare" -> funcStringCompare(fcall, resultToStack)
else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}") else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}")
} }
@ -111,6 +112,14 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
sty $remainderVar+1""") sty $remainderVar+1""")
} }
private fun funcStringCompare(fcall: PtBuiltinFunctionCall, resultToStack: Boolean) {
assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", DataType.UWORD)
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY, false)
asmgen.out(" jsr prog8_lib.strcmp_mem")
if(resultToStack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
}
private fun funcRsave() { private fun funcRsave() {
if (asmgen.isTargetCpu(CpuType.CPU65c02)) if (asmgen.isTargetCpu(CpuType.CPU65c02))
asmgen.out(""" asmgen.out("""
@ -697,6 +706,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
} }
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr) val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
val pointer = result?.first as? PtIdentifier val pointer = result?.first as? PtIdentifier
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) { if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
@ -759,6 +769,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
} else fallback() } else fallback()
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr) val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
val pointer = result?.first as? PtIdentifier val pointer = result?.first as? PtIdentifier
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) { if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {

View File

@ -245,6 +245,8 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
} }
private fun translateExpression(expr: PtBinaryExpression) { private fun translateExpression(expr: PtBinaryExpression) {
require(!asmgen.options.useNewExprCode)
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED! // Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
if(translateSomewhatOptimized(expr.left, expr.operator, expr.right)) if(translateSomewhatOptimized(expr.left, expr.operator, expr.right))
return return

View File

@ -147,6 +147,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignMemoryByte(assign.target, null, value.address as PtIdentifier) assignMemoryByte(assign.target, null, value.address as PtIdentifier)
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val addrExpr = value.address as PtBinaryExpression val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) { if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
assignRegisterByte(assign.target, CpuRegister.A) assignRegisterByte(assign.target, CpuRegister.A)
@ -301,6 +302,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignRegisterByte(assign.target, CpuRegister.A) assignRegisterByte(assign.target, CpuRegister.A)
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
if(!attemptAssignOptimizedBinexpr(value, assign)) { if(!attemptAssignOptimizedBinexpr(value, assign)) {
// All remaining binary expressions just evaluate via the stack for now. // All remaining binary expressions just evaluate via the stack for now.
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here, // (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,
@ -346,6 +348,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
require(!asmgen.options.useNewExprCode)
if(expr.operator in ComparisonOperators) { if(expr.operator in ComparisonOperators) {
if(expr.right.asConstInteger() == 0) { if(expr.right.asConstInteger() == 0) {
if(expr.operator == "==" || expr.operator=="!=") { if(expr.operator == "==" || expr.operator=="!=") {
@ -728,6 +731,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
require(!asmgen.options.useNewExprCode)
when (expr.operator) { when (expr.operator) {
"==" -> { "==" -> {
when(val dt = expr.left.type) { when(val dt = expr.left.type) {
@ -907,6 +911,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignMemoryByteIntoWord(target, null, value.address as PtIdentifier) assignMemoryByteIntoWord(target, null, value.address as PtIdentifier)
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val addrExpr = value.address as PtBinaryExpression val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) { if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
asmgen.out(" ldy #0") asmgen.out(" ldy #0")
@ -2519,7 +2524,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
} }
private fun assignConstantFloat(target: AsmAssignTarget, float: Double) { internal fun assignConstantFloat(target: AsmAssignTarget, float: Double) {
if (float == 0.0) { if (float == 0.0) {
// optimized case for float zero // optimized case for float zero
when(target.kind) { when(target.kind) {
@ -2829,6 +2834,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.storeAIntoPointerVar(addressExpr) asmgen.storeAIntoPointerVar(addressExpr)
} }
addressExpr is PtBinaryExpression -> { addressExpr is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true)) if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
storeViaExprEval() storeViaExprEval()
} }

View File

@ -668,43 +668,31 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
} }
"<" -> { "<" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(""" if(dt==DataType.UBYTE)
cmp $name TODO("ubyte <")
bcc + else
beq + TODO("byte <")
lda #1
bne ++
+ lda #0
+ sta $name""")
} }
"<=" -> { "<=" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(""" if(dt==DataType.UBYTE)
cmp $name TODO("ubyte <=")
lda #0 else
adc #0 TODO("byte <=")
sta $name""")
} }
">" -> { ">" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(""" if(dt==DataType.UBYTE)
cmp $name TODO("ubyte >")
bcc + else
lda #0 TODO("byte >")
beq ++
+ lda #1
+ sta $name""")
} }
">=" -> { ">=" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(""" if(dt==DataType.UBYTE)
cmp $name TODO("ubyte >=")
bcc + else
beq + TODO("byte >=")
lda #0
beq ++
+ lda #1
+ sta $name""")
} }
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
@ -782,41 +770,106 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
+ sta $name""") + sta $name""")
} }
"<" -> { "<" -> {
asmgen.out(""" if(dt==DataType.UBYTE) {
lda $name asmgen.out("""
cmp $otherName lda $name
bcs + cmp $otherName
lda #1 bcc +
bne ++ lda #0
+ lda #0 beq ++
+ sta $name""") + lda #1
+ sta $name""")
}
else {
// see http://www.6502.org/tutorials/compare_beyond.html
asmgen.out("""
lda $name
sec
sbc $otherName
bvc +
eor #$80
+ bmi +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
} }
"<=" -> { "<=" -> {
asmgen.out(""" if(dt==DataType.UBYTE) {
lda $otherName asmgen.out("""
cmp $name lda $otherName
lda #0 cmp $name
adc #0 bcs +
sta $name""") lda #0
beq ++
+ lda #1
+ sta $name""")
} else {
// see http://www.6502.org/tutorials/compare_beyond.html
asmgen.out("""
lda $name
clc
sbc $otherName
bvc +
eor #$80
+ bmi +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
} }
">" -> { ">" -> {
asmgen.out(""" if(dt==DataType.UBYTE) {
lda $otherName asmgen.out("""
cmp $name lda $name
bcc + cmp $otherName
lda #0 beq +
beq ++ bcs ++
+ lda #1 + lda #0
+ sta $name""") beq ++
+ lda #1
+ sta $name""")
} else {
// see http://www.6502.org/tutorials/compare_beyond.html
asmgen.out("""
lda $name
clc
sbc $otherName
bvc +
eor #$80
+ bpl +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
} }
">=" -> { ">=" -> {
asmgen.out(""" if(dt==DataType.UBYTE) {
lda $name asmgen.out("""
cmp $otherName lda $name
lda #0 cmp $otherName
adc #0 bcs +
sta $name""") lda #0
} beq ++
+ lda #1
+ sta $name""")
} else {
// see http://www.6502.org/tutorials/compare_beyond.html
asmgen.out("""
lda $name
sec
sbc $otherName
bvc +
eor #$80
+ bpl +
lda #0
beq ++
+ lda #1
+ sta $name""")
} }
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
} }
@ -908,40 +961,106 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
+ sta $name""") + sta $name""")
} }
"<" -> { "<" -> {
asmgen.out(""" if(dt==DataType.UBYTE) {
lda $name asmgen.out("""
cmp #$value lda $name
bcs + cmp #$value
lda #1 bcc +
bne ++ lda #0
+ lda #0 beq ++
+ sta $name""") + lda #1
+ sta $name""")
}
else {
// see http://www.6502.org/tutorials/compare_beyond.html
asmgen.out("""
lda $name
sec
sbc #$value
bvc +
eor #$80
+ bmi +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
} }
"<=" -> { "<=" -> {
asmgen.out(""" if(dt==DataType.UBYTE) {
lda #$value asmgen.out("""
cmp $name lda #$value
lda #0 cmp $name
adc #0 bcs +
sta $name""") lda #0
beq ++
+ lda #1
+ sta $name""")
} else {
// see http://www.6502.org/tutorials/compare_beyond.html
asmgen.out("""
lda $name
clc
sbc #$value
bvc +
eor #$80
+ bmi +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
} }
">" -> { ">" -> {
asmgen.out(""" if(dt==DataType.UBYTE) {
lda #$value asmgen.out("""
cmp $name lda $name
bcc + cmp #$value
lda #0 beq +
beq ++ bcs ++
+ lda #1 + lda #0
+ sta $name""") beq ++
+ lda #1
+ sta $name""")
} else {
// see http://www.6502.org/tutorials/compare_beyond.html
asmgen.out("""
lda $name
clc
sbc #$value
bvc +
eor #$80
+ bpl +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
} }
">=" -> { ">=" -> {
asmgen.out(""" if(dt==DataType.UBYTE) {
lda $name asmgen.out("""
cmp #$value lda $name
lda #0 cmp #$value
adc #0 bcs +
sta $name""") lda #0
beq ++
+ lda #1
+ sta $name""")
} else {
// see http://www.6502.org/tutorials/compare_beyond.html
asmgen.out("""
lda $name
sec
sbc #$value
bvc +
eor #$80
+ bpl +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
} }
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
@ -1319,8 +1438,174 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
lda #0 lda #0
sta $name+1""") sta $name+1""")
} }
// pretty uncommon, who's going to assign a comparison boolean expresion to a word var?: "<" -> {
"<", "<=", ">", ">=" -> TODO("word-litval-to-var comparisons") if(dt==DataType.UWORD) {
asmgen.out("""
lda $name+1
cmp #>$value
bcc ++
bne +
lda $name
cmp #<$value
bcc ++
+ lda #0 ; false
sta $name
sta $name+1
beq ++
+ lda #1 ; true
sta $name
lda #0
sta $name+1
+""")
}
else {
// signed
asmgen.out("""
lda $name
cmp #<$value
lda $name+1
sbc #>$value
bvc +
eor #$80
+ bmi +
lda #0
sta $name
sta $name+1
beq ++
+ lda #1 ; true
sta $name
lda #0
sta $name+1
+""")
}
}
"<=" -> {
if(dt==DataType.UWORD) {
asmgen.out("""
lda $name+1
cmp #>$value
beq +
bcc ++
- lda #0 ; false
sta $name
sta $name+1
beq +++
+ lda $name ; next
cmp #<$value
bcc +
bne -
+ lda #1 ; true
sta $name
lda #0
sta $name+1
+""")
}
else {
// signed
asmgen.out("""
lda #<$value
cmp $name
lda #>$value
sbc $name+1
bvc +
eor #$80
+ bpl +
lda #0
sta $name
sta $name+1
beq ++
+ lda #1
sta $name
lda #0
sta $name+1
+""")
}
}
">" -> {
// word > value --> value < word
if(dt==DataType.UWORD) {
asmgen.out("""
lda #>$value
cmp $name+1
bcc ++
bne +
lda #<$value
cmp $name
bcc ++
+ lda #0 ; false
sta $name
sta $name+1
beq ++
+ lda #1 ; true
sta $name
lda #0
sta $name+1
+""")
}
else {
// signed
asmgen.out("""
lda #<$value
cmp $name
lda #>$value
sbc $name+1
bvc +
eor #$80
+ bmi +
lda #0
sta $name
sta $name+1
beq ++
+ lda #1 ; true
sta $name
lda #0
sta $name+1
+""")
}
}
">=" -> {
// word >= value --> value <= word
if(dt==DataType.UWORD) {
asmgen.out("""
lda #>$value
cmp $name+1
beq +
bcc ++
- lda #0 ; false
sta $name
sta $name+1
beq +++
+ lda #<$value ; next
cmp $name
bcc +
bne -
+ lda #1 ; true
sta $name
lda #0
sta $name+1
+""")
}
else {
// signed
asmgen.out("""
lda $name
cmp #<$value
lda $name+1
sbc #>$value
bvc +
eor #$80
+ bpl +
lda #0
sta $name
sta $name+1
beq ++
+ lda #1
sta $name
lda #0
sta $name+1
+""")
}
}
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
} }
@ -1650,33 +1935,63 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
sta $name+1""") sta $name+1""")
} }
"<=" -> { "<=" -> {
val compareRoutine = if(dt==DataType.UWORD) "reg_lesseq_uw" else "reg_lesseq_w" if(dt==DataType.UWORD) {
asmgen.out(""" asmgen.out("""
lda $otherName lda $otherName
ldy $otherName+1 ldy $otherName+1
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1
lda $name lda $name
ldy $name+1 ldy $name+1
jsr prog8_lib.$compareRoutine jsr prog8_lib.reg_lesseq_uw
sta $name sta $name
lda #0 lda #0
sta $name+1""") sta $name+1""")
} else {
// note: reg_lesseq_w routine takes the arguments in reverse order
asmgen.out("""
lda $name
ldy $name+1
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda $otherName
ldy $otherName+1
jsr prog8_lib.reg_lesseq_w
sta $name
lda #0
sta $name+1""")
}
} }
">=" -> { ">=" -> {
// a>=b --> b<=a // a>=b --> b<=a
val compareRoutine = if(dt==DataType.UWORD) "reg_lesseq_uw" else "reg_lesseq_w" if(dt==DataType.UWORD) {
asmgen.out(""" asmgen.out("""
lda $name lda $name
ldy $name+1 ldy $name+1
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1
lda $otherName lda $otherName
ldy $otherName+1 ldy $otherName+1
jsr prog8_lib.$compareRoutine jsr prog8_lib.reg_lesseq_uw
sta $name sta $name
lda #0 lda #0
sta $name+1""") sta $name+1"""
)
} else {
// note: reg_lesseq_w routine takes the arguments in reverse order
asmgen.out("""
lda $otherName
ldy $otherName+1
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda $name
ldy $name+1
jsr prog8_lib.reg_lesseq_w
sta $name
lda #0
sta $name+1"""
)
}
} }
else -> throw AssemblyError("invalid operator for in-place modification $operator") else -> throw AssemblyError("invalid operator for in-place modification $operator")
} }
@ -2011,9 +2326,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
""") """)
} }
// pretty uncommon, who's going to assign a comparison boolean expresion to a float var: // pretty uncommon, who's going to assign a comparison boolean expresion to a float var:
"==", "!=", "<", "<=", ">", ">=" -> TODO("float-value-to-var comparisons") "==" -> TODO("float-value-to-var comparison ==")
"!=" -> TODO("float-value-to-var comparison !=")
"<", "<=", ">", ">=" -> TODO("float-value-to-var comparisons")
else -> throw AssemblyError("invalid operator for in-place float modification $operator") else -> throw AssemblyError("invalid operator for in-place float modification $operator")
} }
// store Fac1 back into memory
asmgen.out(""" asmgen.out("""
ldx #<$name ldx #<$name
ldy #>$name ldy #>$name
@ -2066,7 +2384,67 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
""") """)
} }
// pretty uncommon, who's going to assign a comparison boolean expresion to a float var: // pretty uncommon, who's going to assign a comparison boolean expresion to a float var:
"==", "!=", "<", "<=", ">", ">=" -> TODO("float-var-to-var comparisons") "==" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$otherName
ldy #>$otherName
jsr floats.var_fac1_notequal_f
eor #1
jsr floats.FREADSA""")
}
"!=" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$otherName
ldy #>$otherName
jsr floats.var_fac1_notequal_f
jsr floats.FREADSA""")
}
"<" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$otherName
ldy #>$otherName
jsr floats.var_fac1_less_f
jsr floats.FREADSA""")
}
"<=" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$otherName
ldy #>$otherName
jsr floats.var_fac1_lesseq_f
jsr floats.FREADSA""")
}
">" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$otherName
ldy #>$otherName
jsr floats.var_fac1_greater_f
jsr floats.FREADSA""")
}
">=" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$otherName
ldy #>$otherName
jsr floats.var_fac1_greatereq_f
jsr floats.FREADSA""")
}
else -> throw AssemblyError("invalid operator for in-place float modification $operator") else -> throw AssemblyError("invalid operator for in-place float modification $operator")
} }
// store Fac1 back into memory // store Fac1 back into memory
@ -2129,8 +2507,67 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
jsr floats.FDIV jsr floats.FDIV
""") """)
} }
// pretty uncommon, who's going to assign a comparison boolean expresion to a float var: "==" -> {
"==", "!=", "<", "<=", ">", ">=" -> TODO("float-litval-to-var comparisons") asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$constValueName
ldy #>$constValueName
jsr floats.var_fac1_notequal_f
eor #1
jsr floats.FREADSA""")
}
"!=" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$constValueName
ldy #>$constValueName
jsr floats.var_fac1_notequal_f
jsr floats.FREADSA""")
}
"<" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$constValueName
ldy #>$constValueName
jsr floats.var_fac1_less_f
jsr floats.FREADSA""")
}
"<=" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$constValueName
ldy #>$constValueName
jsr floats.var_fac1_lesseq_f
jsr floats.FREADSA""")
}
">" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$constValueName
ldy #>$constValueName
jsr floats.var_fac1_greater_f
jsr floats.FREADSA""")
}
">=" -> {
asmgen.out("""
lda #<$name
ldy #>$name
jsr floats.MOVFM
lda #<$constValueName
ldy #>$constValueName
jsr floats.var_fac1_greatereq_f
jsr floats.FREADSA""")
}
else -> throw AssemblyError("invalid operator for in-place float modification $operator") else -> throw AssemblyError("invalid operator for in-place float modification $operator")
} }
// store Fac1 back into memory // store Fac1 back into memory

View File

@ -14,11 +14,6 @@ class ExperiCodeGen: ICodeGeneratorBackend {
errors: IErrorReporter errors: IErrorReporter
): IAssemblyProgram? { ): IAssemblyProgram? {
if(options.useNewExprCode) {
// TODO("transform BinExprs?")
// errors.warn("EXPERIMENTAL NEW EXPRESSION CODEGEN IS USED. CODE SIZE+SPEED POSSIBLY SUFFERS.", Position.DUMMY)
}
// you could write a code generator directly on the PtProgram AST, // you could write a code generator directly on the PtProgram AST,
// but you can also use the Intermediate Representation to build a codegen on: // but you can also use the Intermediate Representation to build a codegen on:
val irCodeGen = IRCodeGen(program, symbolTable, options, errors) val irCodeGen = IRCodeGen(program, symbolTable, options, errors)

View File

@ -93,7 +93,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} else { } else {
require(origAssign.operator.endsWith('=')) require(origAssign.operator.endsWith('='))
if(codeGen.options.useNewExprCode) { if(codeGen.options.useNewExprCode) {
TODO("use something else than a BinExpr?") TODO("use something else than a BinExpr")
} else { } else {
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position) value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
val left: PtExpression = origAssign.target.children.single() as PtExpression val left: PtExpression = origAssign.target.children.single() as PtExpression
@ -268,7 +268,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} else { } else {
val mult : PtExpression val mult : PtExpression
if(codeGen.options.useNewExprCode) { if(codeGen.options.useNewExprCode) {
TODO("use something else than a BinExpr?") TODO("use something else than a BinExpr")
} else { } else {
mult = PtBinaryExpression("*", DataType.UBYTE, array.position) mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
mult.children += array.index mult.children += array.index

View File

@ -43,6 +43,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
"ror" -> funcRolRor(Opcode.ROXR, call) "ror" -> funcRolRor(Opcode.ROXR, call)
"rol2" -> funcRolRor(Opcode.ROL, call) "rol2" -> funcRolRor(Opcode.ROL, call)
"ror2" -> funcRolRor(Opcode.ROR, call) "ror2" -> funcRolRor(Opcode.ROR, call)
"prog8_lib_stringcompare" -> funcStringCompare(call)
else -> throw AssemblyError("missing builtinfunc for ${call.name}") else -> throw AssemblyError("missing builtinfunc for ${call.name}")
} }
} }
@ -68,6 +69,18 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
return ExpressionCodeResult(result, type, -1, -1) return ExpressionCodeResult(result, type, -1, -1)
} }
private fun funcStringCompare(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val left = exprGen.translateExpression(call.args[0])
val right = exprGen.translateExpression(call.args[1])
val targetReg = codeGen.registers.nextFree()
addToResult(result, left, 65500, -1)
addToResult(result, right, 65501, -1)
addInstr(result, IRInstruction(Opcode.SYSCALL, value=IMSyscall.COMPARE_STRINGS.number), null)
addInstr(result, IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=targetReg, reg2=0), null)
return ExpressionCodeResult(result, IRDataType.BYTE, targetReg, -1)
}
private fun funcCmp(call: PtBuiltinFunctionCall): ExpressionCodeResult { private fun funcCmp(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
val leftTr = exprGen.translateExpression(call.args[0]) val leftTr = exprGen.translateExpression(call.args[0])

View File

@ -320,6 +320,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} }
private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult { private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult {
require(!codeGen.options.useNewExprCode)
val vmDt = codeGen.irType(binExpr.left.type) val vmDt = codeGen.irType(binExpr.left.type)
val signed = binExpr.left.type in SignedDatatypes val signed = binExpr.left.type in SignedDatatypes
return when(binExpr.operator) { return when(binExpr.operator) {

View File

@ -899,6 +899,7 @@ class IRCodeGen(
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
when (condition) { when (condition) {
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!options.useNewExprCode)
if(condition.operator !in ComparisonOperators) if(condition.operator !in ComparisonOperators)
throw AssemblyError("if condition should only be a binary comparison expression") throw AssemblyError("if condition should only be a binary comparison expression")

View File

@ -14,13 +14,6 @@ class VmCodeGen: ICodeGeneratorBackend {
options: CompilationOptions, options: CompilationOptions,
errors: IErrorReporter errors: IErrorReporter
): IAssemblyProgram? { ): IAssemblyProgram? {
if(options.useNewExprCode) {
// TODO("transform BinExprs?")
// errors.warn("EXPERIMENTAL NEW EXPRESSION CODEGEN IS USED. CODE SIZE+SPEED POSSIBLY SUFFERS.", Position.DUMMY)
}
val irCodeGen = IRCodeGen(program, symbolTable, options, errors) val irCodeGen = IRCodeGen(program, symbolTable, options, errors)
val irProgram = irCodeGen.generate() val irProgram = irCodeGen.generate()
return VmAssemblyProgram(irProgram.name, irProgram) return VmAssemblyProgram(irProgram.name, irProgram)

View File

@ -251,7 +251,7 @@ pop_float_fac1 .proc
.pend .pend
copy_float .proc copy_float .proc
; -- copies the 5 bytes of the mflt value pointed to by SCRATCH_ZPWORD1, ; -- copies the 5 bytes of the mflt value pointed to by SCRATCH_W1,
; into the 5 bytes pointed to by A/Y. Clobbers A,Y. ; into the 5 bytes pointed to by A/Y. Clobbers A,Y.
sta _target+1 sta _target+1
sty _target+2 sty _target+2

View File

@ -4,11 +4,12 @@ import com.github.michaelbull.result.onFailure
import prog8.ast.IBuiltinFunctions import prog8.ast.IBuiltinFunctions
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.AstException import prog8.ast.base.AstException
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.Expression import prog8.ast.expressions.Expression
import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.Directive import prog8.ast.statements.Directive
import prog8.code.SymbolTableMaker import prog8.code.SymbolTableMaker
import prog8.code.ast.PtProgram import prog8.code.ast.*
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.* import prog8.code.target.*
import prog8.codegen.vm.VmCodeGen import prog8.codegen.vm.VmCodeGen
@ -409,6 +410,11 @@ private fun createAssemblyAndAssemble(program: PtProgram,
else else
throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.machine.cpu}") throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.machine.cpu}")
if(compilerOptions.useNewExprCode)
transformNewExpressions(program)
// printAst(program, true) { println(it) }
val stMaker = SymbolTableMaker(program, compilerOptions) val stMaker = SymbolTableMaker(program, compilerOptions)
val symbolTable = stMaker.make() val symbolTable = stMaker.make()
val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors) val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors)
@ -420,3 +426,188 @@ private fun createAssemblyAndAssemble(program: PtProgram,
false false
} }
} }
private fun transformNewExpressions(program: PtProgram) {
val newVariables = mutableMapOf<PtSub, MutableList<PtVariable>>()
var countByteVars = 0
var countWordVars = 0
var countFloatVars = 0
// TODO: find a reliable way to reuse the temp vars across expressions
fun getExprVar(type: DataType, pos: Position, scope: PtSub): PtIdentifier {
val count = when(type) {
in ByteDatatypes -> {
countByteVars++
countByteVars
}
in WordDatatypes -> {
countWordVars++
countWordVars
}
DataType.FLOAT -> {
countFloatVars++
countFloatVars
}
else -> throw FatalAstException("weird dt")
}
val name = "p8p_exprvar_${count}_${type.toString().lowercase()}"
var subVars = newVariables[scope]
if(subVars==null) {
subVars = mutableListOf()
newVariables[scope] = subVars
}
if(subVars.all { it.name!=name }) {
subVars.add(PtVariable(name, type, ZeropageWish.DONTCARE, null, null, pos))
}
return PtIdentifier("${scope.scopedName}.$name", type, pos)
}
fun transformExpr(expr: PtBinaryExpression): Pair<PtExpression, List<IPtAssignment>> {
// depth first process the expression tree
val scope = expr.definingSub()!!
val assignments = mutableListOf<IPtAssignment>()
fun transformOperand(node: PtExpression): PtNode {
return when(node) {
is PtNumber, is PtIdentifier, is PtArray, is PtString, is PtMachineRegister -> node
is PtBinaryExpression -> {
val (replacement, subAssigns) = transformExpr(node)
assignments.addAll(subAssigns)
replacement
}
else -> {
val variable = getExprVar(node.type, node.position, scope)
val assign = PtAssignment(node.position)
val target = PtAssignTarget(variable.position)
target.add(variable)
assign.add(target)
assign.add(node)
assignments.add(assign)
variable
}
}
}
val newLeft = transformOperand(expr.left)
val newRight = transformOperand(expr.right)
// process the binexpr
val resultVar =
if(expr.type == expr.left.type) {
getExprVar(expr.type, expr.position, scope)
} else {
if(expr.operator in ComparisonOperators && expr.type in ByteDatatypes) {
// this is very common and should be dealth with correctly; byte==0, word>42
val varType = if(expr.left.type in PassByReferenceDatatypes) DataType.UWORD else expr.left.type
getExprVar(varType, expr.position, scope)
}
else if(expr.left.type in PassByReferenceDatatypes && expr.type==DataType.UBYTE) {
// this is common and should be dealth with correctly; for instance "name"=="john"
val varType = if (expr.left.type in PassByReferenceDatatypes) DataType.UWORD else expr.left.type
getExprVar(varType, expr.position, scope)
} else if(expr.left.type equalsSize expr.type) {
getExprVar(expr.type, expr.position, scope)
} else {
TODO("expression type differs from left operand type! got ${expr.left.type} expected ${expr.type} ${expr.position}")
}
}
if(resultVar.name!=(newLeft as? PtIdentifier)?.name) {
// resultvar = left
val assign1 = PtAssignment(newLeft.position)
val target1 = PtAssignTarget(resultVar.position)
target1.add(resultVar)
assign1.add(target1)
assign1.add(newLeft)
assignments.add(assign1)
}
// resultvar {oper}= right
val operator = if(expr.operator in ComparisonOperators) expr.operator else expr.operator+'='
val assign2 = PtAugmentedAssign(operator, newRight.position)
val target2 = PtAssignTarget(resultVar.position)
target2.add(resultVar.copy())
assign2.add(target2)
assign2.add(newRight)
assignments.add(assign2)
return Pair(resultVar, assignments)
}
fun isProperStatement(node: PtNode): Boolean {
return when(node) {
is PtAssignment -> true
is PtAugmentedAssign -> true
is PtBreakpoint -> true
is PtConditionalBranch -> true
is PtForLoop -> true
is PtIfElse -> true
is PtIncludeBinary -> true
is PtInlineAssembly -> true
is PtJump -> true
is PtAsmSub -> true
is PtLabel -> true
is PtSub -> true
is PtVariable -> true
is PtNop -> true
is PtPostIncrDecr -> true
is PtRepeatLoop -> true
is PtReturn -> true
is PtWhen -> true
is PtBuiltinFunctionCall -> node.void
is PtFunctionCall -> node.void
else -> false
}
}
fun transform(node: PtNode, parent: PtNode) {
if(node is PtBinaryExpression) {
node.children.toTypedArray().forEach {
transform(it, node)
}
val (rep, assignments) = transformExpr(node)
var replacement = rep
if(!(rep.type equalsSize node.type)) {
if(rep.type in NumericDatatypes && node.type in ByteDatatypes) {
replacement = PtTypeCast(node.type, node.position)
replacement.add(rep)
} else
TODO("cast replacement type ${rep.type} -> ${node.type}")
}
var idx = parent.children.indexOf(node)
parent.children[idx] = replacement
replacement.parent = parent
// find the statement above which we should insert the assignments
var stmt = node
while(!isProperStatement(stmt))
stmt = stmt.parent
idx = stmt.parent.children.indexOf(stmt)
assignments.reversed().forEach {
stmt.parent.add(idx, it as PtNode)
}
} else {
node.children.toTypedArray().forEach { child -> transform(child, node) }
}
}
program.allBlocks().forEach { block ->
block.children.toTypedArray().forEach {
transform(it, block)
}
}
// add the new variables
newVariables.forEach { (sub, vars) ->
vars.forEach {
sub.add(0, it)
}
}
// extra check to see that all PtBinaryExpressions have been transformed
fun binExprCheck(node: PtNode) {
if(node is PtBinaryExpression)
throw IllegalArgumentException("still got binexpr $node ${node.position}")
node.children.forEach { binExprCheck(it) }
}
binExprCheck(program)
}

View File

@ -958,7 +958,11 @@ internal class AstChecker(private val program: Program,
} }
} }
if(expr.operator !in ComparisonOperators) { if(expr.operator in ComparisonOperators) {
if(leftDt!=rightDt && !(leftDt in ByteDatatypes && rightDt in ByteDatatypes)) {
throw FatalAstException("got comparison with different operand types: $leftDt ${expr.operator} $rightDt ${expr.position}")
}
} else {
if (leftDt == DataType.STR && rightDt == DataType.STR || leftDt in ArrayDatatypes && rightDt in ArrayDatatypes) { if (leftDt == DataType.STR && rightDt == DataType.STR || leftDt in ArrayDatatypes && rightDt in ArrayDatatypes) {
// str+str and str*number have already been const evaluated before we get here. // str+str and str*number have already been const evaluated before we get here.
errors.err("no computational or logical expressions with strings or arrays are possible", expr.position) errors.err("no computational or logical expressions with strings or arrays are possible", expr.position)

View File

@ -36,6 +36,19 @@ internal class BeforeAsmAstChanger(val program: Program,
return noModifications return noModifications
} }
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
if(expr.operator in ComparisonOperators && expr.left.inferType(program) istype DataType.STR && expr.right.inferType(program) istype DataType.STR) {
// replace string comparison expressions with calls to string.compare()
val stringCompare = BuiltinFunctionCall(
IdentifierReference(listOf("prog8_lib_stringcompare"), expr.position),
mutableListOf(expr.left.copy(), expr.right.copy()), expr.position)
val zero = NumericLiteral.optimalInteger(0, expr.position)
val comparison = BinaryExpression(stringCompare, expr.operator, zero, expr.position)
return listOf(IAstModification.ReplaceNode(expr, comparison, parent))
}
return noModifications
}
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> { override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
if (decl.type == VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes) if (decl.type == VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
throw InternalCompilerException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl") throw InternalCompilerException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")

View File

@ -79,7 +79,7 @@ if CONDITION==0
while CONDITION { STUFF } while CONDITION { STUFF }
==> ==>
_whileloop: _whileloop:
if CONDITION==0 goto _after if INVERTED-CONDITION goto _after
STUFF STUFF
goto _whileloop goto _whileloop
_after: _after:

View File

@ -109,6 +109,8 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
if(binExpr==null || binExpr.operator !in ComparisonOperators) if(binExpr==null || binExpr.operator !in ComparisonOperators)
return noModifications return noModifications
return noModifications // TODO tijdelijk geen simplify
// Simplify the conditional expression, introduce simple assignments if required. // Simplify the conditional expression, introduce simple assignments if required.
// This is REQUIRED for correct code generation on 6502 because evaluating certain expressions // This is REQUIRED for correct code generation on 6502 because evaluating certain expressions
// clobber the handful of temporary variables in the zeropage and leaving everything in one // clobber the handful of temporary variables in the zeropage and leaving everything in one

View File

@ -1,12 +1,40 @@
%zeropage basicsafe %zeropage basicsafe
%import textio %import textio
%import floats
%import string
main { main {
sub start() { sub start() {
test_string()
txt.nl()
test_compare_variable()
txt.nl()
test_compare_literal()
}
sub test_string() {
str name="john"
if (string.compare(name, "aaa")==0) or (string.compare(name, "john")==0) or (string.compare(name, "bbb")==0) {
txt.print("name1 ok\n")
}
if (string.compare(name, "aaa")==0) or (string.compare(name, "zzz")==0) or (string.compare(name, "bbb")==0) {
txt.print("name2 fail!\n")
}
if name=="aaa" or name=="john" or name=="bbb"
txt.print("name1b ok\n")
if name=="aaa" or name=="zzz" or name=="bbb"
txt.print("name2b fail!\n")
}
sub test_compare_literal() {
byte b = -100 byte b = -100
ubyte ub = 20 ubyte ub = 20
word w = -20000 word w = -20000
uword uw = 2000 uword uw = 2000
float f = -100
txt.print("all 1: ") txt.print("all 1: ")
txt.print_ub(b == -100) txt.print_ub(b == -100)
@ -34,7 +62,15 @@ main {
txt.print_ub(uw <= 2000) txt.print_ub(uw <= 2000)
txt.print_ub(uw > 1999) txt.print_ub(uw > 1999)
txt.print_ub(uw >= 2000) txt.print_ub(uw >= 2000)
txt.spc()
txt.print_ub(f == -100.0)
txt.print_ub(f != -99.0)
txt.print_ub(f < -99.0)
txt.print_ub(f <= -100.0)
txt.print_ub(f > -101.0)
txt.print_ub(f >= -100.0)
txt.nl() txt.nl()
txt.print("all 0: ") txt.print("all 0: ")
txt.print_ub(b == -99) txt.print_ub(b == -99)
txt.print_ub(b != -100) txt.print_ub(b != -100)
@ -61,6 +97,153 @@ main {
txt.print_ub(uw <= 1999) txt.print_ub(uw <= 1999)
txt.print_ub(uw > 2000) txt.print_ub(uw > 2000)
txt.print_ub(uw >= 2001) txt.print_ub(uw >= 2001)
txt.spc()
txt.print_ub(f == -99.0)
txt.print_ub(f != -100.0)
txt.print_ub(f < -100.0)
txt.print_ub(f <= -101.0)
txt.print_ub(f > -100.0)
txt.print_ub(f >= -99.0)
txt.nl()
txt.print("all .: ")
if b == -100 txt.chrout('.')
if b != -99 txt.chrout('.')
if b < -99 txt.chrout('.')
if b <= -100 txt.chrout('.')
if b > -101 txt.chrout('.')
if b >= -100 txt.chrout('.')
if ub ==20 txt.chrout('.')
if ub !=19 txt.chrout('.')
if ub <21 txt.chrout('.')
if ub <=20 txt.chrout('.')
if ub>19 txt.chrout('.')
if ub>=20 txt.chrout('.')
txt.spc()
if w == -20000 txt.chrout('.')
if w != -19999 txt.chrout('.')
if w < -19999 txt.chrout('.')
if w <= -20000 txt.chrout('.')
if w > -20001 txt.chrout('.')
if w >= -20000 txt.chrout('.')
if uw == 2000 txt.chrout('.')
if uw != 2001 txt.chrout('.')
if uw < 2001 txt.chrout('.')
if uw <= 2000 txt.chrout('.')
if uw > 1999 txt.chrout('.')
if uw >= 2000 txt.chrout('.')
txt.spc()
if f == -100.0 txt.chrout('.')
if f != -99.0 txt.chrout('.')
if f < -99.0 txt.chrout('.')
if f <= -100.0 txt.chrout('.')
if f > -101.0 txt.chrout('.')
if f >= -100.0 txt.chrout('.')
txt.nl()
txt.print(" no !: ")
if b == -99 txt.chrout('!')
if b != -100 txt.chrout('!')
if b < -100 txt.chrout('!')
if b <= -101 txt.chrout('!')
if b > -100 txt.chrout('!')
if b >= -99 txt.chrout('!')
if ub ==21 txt.chrout('!')
if ub !=20 txt.chrout('!')
if ub <20 txt.chrout('!')
if ub <=19 txt.chrout('!')
if ub>20 txt.chrout('!')
if ub>=21 txt.chrout('!')
txt.spc()
if w == -20001 txt.chrout('!')
if w != -20000 txt.chrout('!')
if w < -20000 txt.chrout('!')
if w <= -20001 txt.chrout('!')
if w > -20000 txt.chrout('!')
if w >= -19999 txt.chrout('!')
if uw == 1999 txt.chrout('!')
if uw != 2000 txt.chrout('!')
if uw < 2000 txt.chrout('!')
if uw <= 1999 txt.chrout('!')
if uw > 2000 txt.chrout('!')
if uw >= 2001 txt.chrout('!')
txt.spc()
if f == -99.0 txt.chrout('!')
if f != -100.0 txt.chrout('!')
if f < -100.0 txt.chrout('!')
if f <= -101.0 txt.chrout('!')
if f > -100.0 txt.chrout('!')
if f >= -99.0 txt.chrout('!')
txt.nl()
txt.print("all .: ")
if b == -100 txt.chrout('.') else txt.chrout('!')
if b != -99 txt.chrout('.') else txt.chrout('!')
if b < -99 txt.chrout('.') else txt.chrout('!')
if b <= -100 txt.chrout('.') else txt.chrout('!')
if b > -101 txt.chrout('.') else txt.chrout('!')
if b >= -100 txt.chrout('.') else txt.chrout('!')
if ub ==20 txt.chrout('.') else txt.chrout('!')
if ub !=19 txt.chrout('.') else txt.chrout('!')
if ub <21 txt.chrout('.') else txt.chrout('!')
if ub <=20 txt.chrout('.') else txt.chrout('!')
if ub>19 txt.chrout('.') else txt.chrout('!')
if ub>=20 txt.chrout('.') else txt.chrout('!')
txt.spc()
if w == -20000 txt.chrout('.') else txt.chrout('!')
if w != -19999 txt.chrout('.') else txt.chrout('!')
if w < -19999 txt.chrout('.') else txt.chrout('!')
if w <= -20000 txt.chrout('.') else txt.chrout('!')
if w > -20001 txt.chrout('.') else txt.chrout('!')
if w >= -20000 txt.chrout('.') else txt.chrout('!')
if uw == 2000 txt.chrout('.') else txt.chrout('!')
if uw != 2001 txt.chrout('.') else txt.chrout('!')
if uw < 2001 txt.chrout('.') else txt.chrout('!')
if uw <= 2000 txt.chrout('.') else txt.chrout('!')
if uw > 1999 txt.chrout('.') else txt.chrout('!')
if uw >= 2000 txt.chrout('.') else txt.chrout('!')
txt.spc()
if f == -100.0 txt.chrout('.') else txt.chrout('!')
if f != -99.0 txt.chrout('.') else txt.chrout('!')
if f < -99.0 txt.chrout('.') else txt.chrout('!')
if f <= -100.0 txt.chrout('.') else txt.chrout('!')
if f > -101.0 txt.chrout('.') else txt.chrout('!')
if f >= -100.0 txt.chrout('.') else txt.chrout('!')
txt.nl()
txt.print("all .: ")
if b == -99 txt.chrout('!') else txt.chrout('.')
if b != -100 txt.chrout('!') else txt.chrout('.')
if b < -100 txt.chrout('!') else txt.chrout('.')
if b <= -101 txt.chrout('!') else txt.chrout('.')
if b > -100 txt.chrout('!') else txt.chrout('.')
if b >= -99 txt.chrout('!') else txt.chrout('.')
if ub ==21 txt.chrout('!') else txt.chrout('.')
if ub !=20 txt.chrout('!') else txt.chrout('.')
if ub <20 txt.chrout('!') else txt.chrout('.')
if ub <=19 txt.chrout('!') else txt.chrout('.')
if ub>20 txt.chrout('!') else txt.chrout('.')
if ub>=21 txt.chrout('!') else txt.chrout('.')
txt.spc()
if w == -20001 txt.chrout('!') else txt.chrout('.')
if w != -20000 txt.chrout('!') else txt.chrout('.')
if w < -20000 txt.chrout('!') else txt.chrout('.')
if w <= -20001 txt.chrout('!') else txt.chrout('.')
if w > -20000 txt.chrout('!') else txt.chrout('.')
if w >= -19999 txt.chrout('!') else txt.chrout('.')
if uw == 1999 txt.chrout('!') else txt.chrout('.')
if uw != 2000 txt.chrout('!') else txt.chrout('.')
if uw < 2000 txt.chrout('!') else txt.chrout('.')
if uw <= 1999 txt.chrout('!') else txt.chrout('.')
if uw > 2000 txt.chrout('!') else txt.chrout('.')
if uw >= 2001 txt.chrout('!') else txt.chrout('.')
txt.spc()
if f == -99.0 txt.chrout('!') else txt.chrout('.')
if f != -100.0 txt.chrout('!') else txt.chrout('.')
if f < -100.0 txt.chrout('!') else txt.chrout('.')
if f <= -101.0 txt.chrout('!') else txt.chrout('.')
if f > -100.0 txt.chrout('!') else txt.chrout('.')
if f >= -99.0 txt.chrout('!') else txt.chrout('.')
txt.nl() txt.nl()
@ -112,9 +295,311 @@ main {
txt.print_uw(uw) txt.print_uw(uw)
txt.print(" 8000\n") txt.print(" 8000\n")
; float f f = 0.0
; while f<2.2 { floats.print_f(f)
; f+=0.1 while f<2.2 {
; } f+=0.1
floats.print_f(f)
}
floats.print_f(f)
txt.print(" 2.2\n")
}
sub test_compare_variable() {
byte b = -100
ubyte ub = 20
word w = -20000
uword uw = 2000
float f = -100
byte minus_100 = -100
byte minus_99 = -99
byte minus_20 = -20
byte minus_101 = -101
ubyte nineteen = 19
ubyte twenty = 20
ubyte twenty1 = 21
ubyte twohundred = 200
float f_minus_100 = -100.0
float f_minus_101 = -101.0
float f_minus_99 = -99.0
float twodottwo = 2.2
word minus8000 = -8000
word eightthousand = 8000
word w_min_20000 = -20000
word w_min_19999 = -19999
word w_min_20001 = -20001
uword twothousand = 2000
uword twothousand1 = 2001
uword nineteen99 = 1999
txt.print("all 1: ")
txt.print_ub(b == minus_100)
txt.print_ub(b != minus_99)
txt.print_ub(b < minus_99)
txt.print_ub(b <= minus_100)
txt.print_ub(b > minus_101)
txt.print_ub(b >= minus_100)
txt.print_ub(ub ==twenty)
txt.print_ub(ub !=nineteen)
txt.print_ub(ub <twenty1)
txt.print_ub(ub <=twenty)
txt.print_ub(ub>nineteen)
txt.print_ub(ub>=twenty)
txt.spc()
txt.print_ub(w == w_min_20000)
txt.print_ub(w != w_min_19999)
txt.print_ub(w < w_min_19999)
txt.print_ub(w <= w_min_20000)
txt.print_ub(w > w_min_20001)
txt.print_ub(w >= w_min_20000)
txt.print_ub(uw == twothousand)
txt.print_ub(uw != twothousand1)
txt.print_ub(uw < twothousand1)
txt.print_ub(uw <= twothousand)
txt.print_ub(uw > nineteen99)
txt.print_ub(uw >= twothousand)
txt.spc()
txt.print_ub(f == f_minus_100)
txt.print_ub(f != f_minus_99)
txt.print_ub(f < f_minus_99)
txt.print_ub(f <= f_minus_100)
txt.print_ub(f > f_minus_101)
txt.print_ub(f >= f_minus_100)
txt.nl()
txt.print("all 0: ")
txt.print_ub(b == minus_99)
txt.print_ub(b != minus_100)
txt.print_ub(b < minus_100)
txt.print_ub(b <= minus_101)
txt.print_ub(b > minus_100)
txt.print_ub(b >= minus_99)
txt.print_ub(ub ==twenty1)
txt.print_ub(ub !=twenty)
txt.print_ub(ub <twenty)
txt.print_ub(ub <=nineteen)
txt.print_ub(ub>twenty)
txt.print_ub(ub>=twenty1)
txt.spc()
txt.print_ub(w == w_min_20001)
txt.print_ub(w != w_min_20000)
txt.print_ub(w < w_min_20000)
txt.print_ub(w <= w_min_20001)
txt.print_ub(w > w_min_20000)
txt.print_ub(w >= w_min_19999)
txt.print_ub(uw == nineteen99)
txt.print_ub(uw != twothousand)
txt.print_ub(uw < twothousand)
txt.print_ub(uw <= nineteen99)
txt.print_ub(uw > twothousand)
txt.print_ub(uw >= twothousand1)
txt.spc()
txt.print_ub(f == f_minus_99)
txt.print_ub(f != f_minus_100)
txt.print_ub(f < f_minus_100)
txt.print_ub(f <= f_minus_101)
txt.print_ub(f > f_minus_100)
txt.print_ub(f >= f_minus_99)
txt.nl()
txt.print("all .: ")
if b == minus_100 txt.chrout('.')
if b != minus_99 txt.chrout('.')
if b < minus_99 txt.chrout('.')
if b <= minus_100 txt.chrout('.')
if b > minus_101 txt.chrout('.')
if b >= minus_100 txt.chrout('.')
if ub == twenty txt.chrout('.')
if ub != nineteen txt.chrout('.')
if ub < twenty1 txt.chrout('.')
if ub <= twenty txt.chrout('.')
if ub> nineteen txt.chrout('.')
if ub>= twenty txt.chrout('.')
txt.spc()
if w == w_min_20000 txt.chrout('.')
if w != w_min_19999 txt.chrout('.')
if w < w_min_19999 txt.chrout('.')
if w <= w_min_20000 txt.chrout('.')
if w > w_min_20001 txt.chrout('.')
if w >= w_min_20000 txt.chrout('.')
if uw == twothousand txt.chrout('.')
if uw != twothousand1 txt.chrout('.')
if uw < twothousand1 txt.chrout('.')
if uw <= twothousand txt.chrout('.')
if uw > nineteen99 txt.chrout('.')
if uw >= twothousand txt.chrout('.')
txt.spc()
if f == f_minus_100 txt.chrout('.')
if f != f_minus_99 txt.chrout('.')
if f < f_minus_99 txt.chrout('.')
if f <= f_minus_100 txt.chrout('.')
if f > f_minus_101 txt.chrout('.')
if f >= f_minus_100 txt.chrout('.')
txt.nl()
txt.print(" no !: ")
if b == minus_99 txt.chrout('!')
if b != minus_100 txt.chrout('!')
if b < minus_100 txt.chrout('!')
if b <= minus_101 txt.chrout('!')
if b > minus_100 txt.chrout('!')
if b >= minus_99 txt.chrout('!')
if ub == twenty1 txt.chrout('!')
if ub != twenty txt.chrout('!')
if ub < twenty txt.chrout('!')
if ub <= nineteen txt.chrout('!')
if ub> twenty txt.chrout('!')
if ub>= twenty1 txt.chrout('!')
txt.spc()
if w == w_min_20001 txt.chrout('!')
if w != w_min_20000 txt.chrout('!')
if w < w_min_20000 txt.chrout('!')
if w <= w_min_20001 txt.chrout('!')
if w > w_min_20000 txt.chrout('!')
if w >= w_min_19999 txt.chrout('!')
if uw == nineteen99 txt.chrout('!')
if uw != twothousand txt.chrout('!')
if uw < twothousand txt.chrout('!')
if uw <= nineteen99 txt.chrout('!')
if uw > twothousand txt.chrout('!')
if uw >= twothousand1 txt.chrout('!')
txt.spc()
if f == f_minus_99 txt.chrout('!')
if f != f_minus_100 txt.chrout('!')
if f < f_minus_100 txt.chrout('!')
if f <= f_minus_101 txt.chrout('!')
if f > f_minus_100 txt.chrout('!')
if f >= f_minus_99 txt.chrout('!')
txt.nl()
txt.print("all .: ")
if b == minus_100 txt.chrout('.') else txt.chrout('!')
if b != minus_99 txt.chrout('.') else txt.chrout('!')
if b < minus_99 txt.chrout('.') else txt.chrout('!')
if b <= minus_100 txt.chrout('.') else txt.chrout('!')
if b > minus_101 txt.chrout('.') else txt.chrout('!')
if b >= minus_100 txt.chrout('.') else txt.chrout('!')
if ub == twenty txt.chrout('.') else txt.chrout('!')
if ub != nineteen txt.chrout('.') else txt.chrout('!')
if ub < twenty1 txt.chrout('.') else txt.chrout('!')
if ub <= twenty txt.chrout('.') else txt.chrout('!')
if ub> nineteen txt.chrout('.') else txt.chrout('!')
if ub>=twenty txt.chrout('.') else txt.chrout('!')
txt.spc()
if w == w_min_20000 txt.chrout('.') else txt.chrout('!')
if w != w_min_19999 txt.chrout('.') else txt.chrout('!')
if w < w_min_19999 txt.chrout('.') else txt.chrout('!')
if w <= w_min_20000 txt.chrout('.') else txt.chrout('!')
if w > w_min_20001 txt.chrout('.') else txt.chrout('!')
if w >= w_min_20000 txt.chrout('.') else txt.chrout('!')
if uw == twothousand txt.chrout('.') else txt.chrout('!')
if uw != twothousand1 txt.chrout('.') else txt.chrout('!')
if uw < twothousand1 txt.chrout('.') else txt.chrout('!')
if uw <= twothousand txt.chrout('.') else txt.chrout('!')
if uw > nineteen99 txt.chrout('.') else txt.chrout('!')
if uw >= twothousand txt.chrout('.') else txt.chrout('!')
txt.spc()
if f == f_minus_100 txt.chrout('.') else txt.chrout('!')
if f != f_minus_99 txt.chrout('.') else txt.chrout('!')
if f < f_minus_99 txt.chrout('.') else txt.chrout('!')
if f <= f_minus_100 txt.chrout('.') else txt.chrout('!')
if f > f_minus_101 txt.chrout('.') else txt.chrout('!')
if f >= f_minus_100 txt.chrout('.') else txt.chrout('!')
txt.nl()
txt.print("all .: ")
if b == minus_99 txt.chrout('!') else txt.chrout('.')
if b != minus_100 txt.chrout('!') else txt.chrout('.')
if b < minus_100 txt.chrout('!') else txt.chrout('.')
if b <= minus_101 txt.chrout('!') else txt.chrout('.')
if b > minus_100 txt.chrout('!') else txt.chrout('.')
if b >= minus_99 txt.chrout('!') else txt.chrout('.')
if ub == twenty1 txt.chrout('!') else txt.chrout('.')
if ub !=twenty txt.chrout('!') else txt.chrout('.')
if ub <twenty txt.chrout('!') else txt.chrout('.')
if ub <=nineteen txt.chrout('!') else txt.chrout('.')
if ub>twenty txt.chrout('!') else txt.chrout('.')
if ub>= twenty1 txt.chrout('!') else txt.chrout('.')
txt.spc()
if w == w_min_20001 txt.chrout('!') else txt.chrout('.')
if w != w_min_20000 txt.chrout('!') else txt.chrout('.')
if w < w_min_20000 txt.chrout('!') else txt.chrout('.')
if w <= w_min_20001 txt.chrout('!') else txt.chrout('.')
if w > w_min_20000 txt.chrout('!') else txt.chrout('.')
if w >= w_min_19999 txt.chrout('!') else txt.chrout('.')
if uw == nineteen99 txt.chrout('!') else txt.chrout('.')
if uw != twothousand txt.chrout('!') else txt.chrout('.')
if uw < twothousand txt.chrout('!') else txt.chrout('.')
if uw <= nineteen99 txt.chrout('!') else txt.chrout('.')
if uw > twothousand txt.chrout('!') else txt.chrout('.')
if uw >= twothousand1 txt.chrout('!') else txt.chrout('.')
txt.spc()
if f == f_minus_99 txt.chrout('!') else txt.chrout('.')
if f != f_minus_100 txt.chrout('!') else txt.chrout('.')
if f < f_minus_100 txt.chrout('!') else txt.chrout('.')
if f <= f_minus_101 txt.chrout('!') else txt.chrout('.')
if f > f_minus_100 txt.chrout('!') else txt.chrout('.')
if f >= f_minus_99 txt.chrout('!') else txt.chrout('.')
txt.nl()
b = minus_100
while b <= minus_20
b++
txt.print_b(b)
txt.print(" -19\n")
b = minus_100
while b < -minus_20
b++
txt.print_b(b)
txt.print(" -20\n")
ub = 20
while ub <= twohundred
ub++
txt.print_ub(ub)
txt.print(" 201\n")
ub = 20
while ub < twohundred
ub++
txt.print_ub(ub)
txt.print(" 200\n")
w = w_min_20000
while w <= minus8000 {
w++
}
txt.print_w(w)
txt.print(" -7999\n")
w = w_min_20000
while w < minus8000 {
w++
}
txt.print_w(w)
txt.print(" -8000\n")
uw = 2000
while uw <= eightthousand {
uw++
}
txt.print_uw(uw)
txt.print(" 8001\n")
uw = 2000
while uw < eightthousand {
uw++
}
txt.print_uw(uw)
txt.print(" 8000\n")
f = 0.0
floats.print_f(f)
while f<twodottwo {
f+=0.1
floats.print_f(f)
}
floats.print_f(f)
txt.print(" 2.2\n")
} }
} }

View File

@ -1,15 +1,9 @@
TODO TODO
==== ====
replace RPN by something that actually works and is efficient...
For next minor release For next minor release
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
- ubyte fits = cx<numCellsHoriz-1 much larger code than when declared as bool ????
- if fits and @(celladdr(cx+1)) much larger code than if fits and not @(celladdr(cx+1)) ????
- @($5000 + c<<$0003) = 22 why is 22 pushed on the stack first and then popped after the address is calculated
... ...