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) {

View File

@ -38,20 +38,17 @@ class PtSub(
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
get() = children[0] as PtAssignTarget
val value: PtExpression
get() = children[1] as PtExpression
}
class PtAssignment(position: Position) : PtNode(position), IPtAssignment
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position) {
val target: PtAssignTarget
get() = children[0] as PtAssignTarget
val value: PtExpression
get() = children[1] as PtExpression
}
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position), IPtAssignment
class PtAssignTarget(position: Position) : PtNode(position) {
@ -95,7 +92,7 @@ class PtForLoop(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
val ifScope: 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),
// 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),
"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),
"len" to FSignature(true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD),
// normal functions follow:

View File

@ -21,13 +21,6 @@ class AsmGen6502: ICodeGeneratorBackend {
options: CompilationOptions,
errors: IErrorReporter
): 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)
return asmgen.compileToAssembly()
}
@ -551,28 +544,76 @@ class AsmGen6502Internal (
}
private fun translate(stmt: PtIfElse) {
val condition = stmt.condition as PtBinaryExpression
requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>'
if (stmt.elseScope.children.isEmpty()) {
val jump = stmt.ifScope.children.singleOrNull()
if (jump is PtJump) {
translateCompareAndJumpIfTrue(condition, jump)
val condition = stmt.condition as? PtBinaryExpression
if(condition!=null) {
require(!options.useNewExprCode)
requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>'
if (stmt.elseScope.children.isEmpty()) {
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 {
// both true and else parts
val elseLabel = makeLabel("if_else")
val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalse(condition, endLabel)
translateCompareOrJumpIfFalse(condition, elseLabel)
translate(stmt.ifScope)
jmp(endLabel)
out(elseLabel)
translate(stmt.elseScope)
out(endLabel)
}
} else {
// both true and else parts
val elseLabel = makeLabel("if_else")
val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalse(condition, elseLabel)
translate(stmt.ifScope)
jmp(endLabel)
out(elseLabel)
translate(stmt.elseScope)
out(endLabel)
// condition is a simple expression "if X" --> "if X!=0"
val zero = PtNumber(DataType.UBYTE,0.0, stmt.position)
val leftConst = stmt.condition as? PtNumber
if (stmt.elseScope.children.isEmpty()) {
val jump = stmt.ifScope.children.singleOrNull()
if (jump is PtJump) {
// jump somewhere if X!=0
val label = when {
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
if(!isNested && !options.useNewExprCode) {
if(!isNested) {
// 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") }
if(existingVar!=null) {
@ -987,6 +1028,7 @@ $repeatLabel lda $counterVar
val operator: String
if (pointerOffsetExpr is PtBinaryExpression) {
require(!options.useNewExprCode)
operator = pointerOffsetExpr.operator
left = pointerOffsetExpr.left
right = pointerOffsetExpr.right
@ -1132,15 +1174,16 @@ $repeatLabel lda $counterVar
jump.address!=null -> jump.address!!.toHex()
else -> throw AssemblyError("weird jump")
}
if (rightConstVal!=null && rightConstVal.number == 0.0)
testZeroAndJump(left, invertedComparisonOperator, label)
if (rightConstVal!=null && rightConstVal.number == 0.0) {
testZeroOrJumpElsewhere(left, invertedComparisonOperator, label)
}
else {
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 right = expr.right
val operator = expr.operator
@ -1148,19 +1191,19 @@ $repeatLabel lda $counterVar
val rightConstVal = right as? PtNumber
if (rightConstVal!=null && rightConstVal.number == 0.0)
testZeroAndJump(left, operator, jumpIfFalseLabel)
testZeroOrJumpElsewhere(left, operator, jumpIfFalseLabel)
else
testNonzeroComparisonAndJump(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal)
testNonzeroComparisonOrJumpElsewhere(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal)
}
private fun testZeroAndJump(
private fun testZeroOrJumpElsewhere(
left: PtExpression,
operator: String,
jumpIfFalseLabel: String
) {
val dt = left.type
if(dt in IntegerDatatypes && left is PtIdentifier)
return testVariableZeroAndJump(left, dt, operator, jumpIfFalseLabel)
return testVariableZeroOrJumpElsewhere(left, dt, operator, jumpIfFalseLabel)
when(dt) {
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)
val varname = asmVariableName(variable)
when(dt) {
@ -1306,7 +1349,7 @@ $repeatLabel lda $counterVar
}
}
internal fun testNonzeroComparisonAndJump(
internal fun testNonzeroComparisonOrJumpElsewhere(
left: PtExpression,
operator: String,
right: PtExpression,
@ -1319,70 +1362,70 @@ $repeatLabel lda $counterVar
when (operator) {
"==" -> {
when (dt) {
in ByteDatatypes -> translateByteEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringEqualsJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
in ByteDatatypes -> translateByteEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringEqualsOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
"!=" -> {
when (dt) {
in ByteDatatypes -> translateByteNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringNotEqualsJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
in ByteDatatypes -> translateByteNotEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordNotEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatNotEqualsOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringNotEqualsOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
"<" -> {
when(dt) {
DataType.UBYTE -> translateUbyteLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringLessJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
DataType.UBYTE -> translateUbyteLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatLessOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringLessOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
"<=" -> {
when(dt) {
DataType.UBYTE -> translateUbyteLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringLessOrEqualJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
DataType.UBYTE -> translateUbyteLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatLessOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringLessOrEqualOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
">" -> {
when(dt) {
DataType.UBYTE -> translateUbyteGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatGreaterJump(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringGreaterJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
DataType.UBYTE -> translateUbyteGreaterOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatGreaterOrJumpElsewhere(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringGreaterOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
">=" -> {
when(dt) {
DataType.UBYTE -> translateUbyteGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringGreaterOrEqualJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
DataType.UBYTE -> translateUbyteGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatGreaterOrEqualOrJumpElsewhere(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringGreaterOrEqualOrJumpElsewhere(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel)
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) {
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) {
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) {
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) {
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) {
out(" cmp $cmpOperand | bcs $jumpIfFalseLabel")
@ -1607,7 +1650,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -1648,7 +1691,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -1692,7 +1735,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -1738,7 +1781,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -1784,7 +1827,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -1827,7 +1870,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -1877,7 +1920,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -1928,7 +1971,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -1975,7 +2018,7 @@ $repeatLabel lda $counterVar
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) {
out("""
clc
@ -2018,7 +2061,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -2070,7 +2113,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -2125,7 +2168,7 @@ $repeatLabel lda $counterVar
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) {
out(" cmp $cmpOperand | bcc $jumpIfFalseLabel")
@ -2168,7 +2211,7 @@ $repeatLabel lda $counterVar
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) {
out("""
sec
@ -2208,7 +2251,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -2251,7 +2294,7 @@ $repeatLabel lda $counterVar
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) {
out("""
@ -2297,7 +2340,7 @@ $repeatLabel lda $counterVar
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) {
out(" cmp $cmpOperand | bne $jumpIfFalseLabel")
}
@ -2342,7 +2385,7 @@ $repeatLabel lda $counterVar
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) {
out(" cmp $cmpOperand | beq $jumpIfFalseLabel")
@ -2388,7 +2431,7 @@ $repeatLabel lda $counterVar
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(leftConstVal!=null) {
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(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(leftConstVal!=null) {
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(leftConstVal!=null) {
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 rightNam = asmVariableName(right)
out("""
@ -2740,11 +2783,10 @@ $repeatLabel lda $counterVar
lda #<$leftNam
ldy #>$leftNam
jsr prog8_lib.strcmp_mem
cmp #0
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 rightNam = asmVariableName(right)
out("""
@ -2755,11 +2797,10 @@ $repeatLabel lda $counterVar
lda #<$leftNam
ldy #>$leftNam
jsr prog8_lib.strcmp_mem
cmp #0
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 rightNam = asmVariableName(right)
out("""
@ -2773,7 +2814,7 @@ $repeatLabel lda $counterVar
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 rightNam = asmVariableName(right)
out("""
@ -2788,7 +2829,7 @@ $repeatLabel lda $counterVar
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 rightNam = asmVariableName(right)
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 rightNam = asmVariableName(right)
out("""
@ -2853,6 +2894,7 @@ $repeatLabel lda $counterVar
out(" sta P8ESTACK_LO,x | dex")
}
is PtBinaryExpression -> {
require(!options.useNewExprCode)
val addrExpr = expr.address as PtBinaryExpression
if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
if(pushResultOnEstack)

View File

@ -72,6 +72,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
"rrestorex" -> funcRrestoreX()
"cmp" -> funcCmp(fcall)
"callfar" -> funcCallFar(fcall)
"prog8_lib_stringcompare" -> funcStringCompare(fcall, resultToStack)
else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}")
}
@ -111,6 +112,14 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
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() {
if (asmgen.isTargetCpu(CpuType.CPU65c02))
asmgen.out("""
@ -697,6 +706,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
}
is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
val pointer = result?.first as? PtIdentifier
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
@ -759,6 +769,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
} else fallback()
}
is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
val pointer = result?.first as? PtIdentifier
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) {
require(!asmgen.options.useNewExprCode)
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
if(translateSomewhatOptimized(expr.left, expr.operator, expr.right))
return

View File

@ -147,6 +147,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignMemoryByte(assign.target, null, value.address as PtIdentifier)
}
is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
assignRegisterByte(assign.target, CpuRegister.A)
@ -301,6 +302,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignRegisterByte(assign.target, CpuRegister.A)
}
is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
if(!attemptAssignOptimizedBinexpr(value, assign)) {
// 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,
@ -346,6 +348,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
require(!asmgen.options.useNewExprCode)
if(expr.operator in ComparisonOperators) {
if(expr.right.asConstInteger() == 0) {
if(expr.operator == "==" || expr.operator=="!=") {
@ -728,6 +731,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
require(!asmgen.options.useNewExprCode)
when (expr.operator) {
"==" -> {
when(val dt = expr.left.type) {
@ -907,6 +911,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignMemoryByteIntoWord(target, null, value.address as PtIdentifier)
}
is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
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) {
// optimized case for float zero
when(target.kind) {
@ -2829,6 +2834,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.storeAIntoPointerVar(addressExpr)
}
addressExpr is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
storeViaExprEval()
}

View File

@ -668,43 +668,31 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
}
"<" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out("""
cmp $name
bcc +
beq +
lda #1
bne ++
+ lda #0
+ sta $name""")
if(dt==DataType.UBYTE)
TODO("ubyte <")
else
TODO("byte <")
}
"<=" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out("""
cmp $name
lda #0
adc #0
sta $name""")
if(dt==DataType.UBYTE)
TODO("ubyte <=")
else
TODO("byte <=")
}
">" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out("""
cmp $name
bcc +
lda #0
beq ++
+ lda #1
+ sta $name""")
if(dt==DataType.UBYTE)
TODO("ubyte >")
else
TODO("byte >")
}
">=" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out("""
cmp $name
bcc +
beq +
lda #0
beq ++
+ lda #1
+ sta $name""")
if(dt==DataType.UBYTE)
TODO("ubyte >=")
else
TODO("byte >=")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
@ -782,41 +770,106 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
+ sta $name""")
}
"<" -> {
asmgen.out("""
lda $name
cmp $otherName
bcs +
lda #1
bne ++
+ lda #0
+ sta $name""")
if(dt==DataType.UBYTE) {
asmgen.out("""
lda $name
cmp $otherName
bcc +
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
+ bmi +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
}
"<=" -> {
asmgen.out("""
lda $otherName
cmp $name
lda #0
adc #0
sta $name""")
if(dt==DataType.UBYTE) {
asmgen.out("""
lda $otherName
cmp $name
bcs +
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("""
lda $otherName
cmp $name
bcc +
lda #0
beq ++
+ lda #1
+ sta $name""")
if(dt==DataType.UBYTE) {
asmgen.out("""
lda $name
cmp $otherName
beq +
bcs ++
+ 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
+ bpl +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
}
">=" -> {
asmgen.out("""
lda $name
cmp $otherName
lda #0
adc #0
sta $name""")
}
if(dt==DataType.UBYTE) {
asmgen.out("""
lda $name
cmp $otherName
bcs +
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")
}
}
@ -908,40 +961,106 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
+ sta $name""")
}
"<" -> {
asmgen.out("""
lda $name
cmp #$value
bcs +
lda #1
bne ++
+ lda #0
+ sta $name""")
if(dt==DataType.UBYTE) {
asmgen.out("""
lda $name
cmp #$value
bcc +
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
+ bmi +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
}
"<=" -> {
asmgen.out("""
lda #$value
cmp $name
lda #0
adc #0
sta $name""")
if(dt==DataType.UBYTE) {
asmgen.out("""
lda #$value
cmp $name
bcs +
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("""
lda #$value
cmp $name
bcc +
lda #0
beq ++
+ lda #1
+ sta $name""")
if(dt==DataType.UBYTE) {
asmgen.out("""
lda $name
cmp #$value
beq +
bcs ++
+ 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
+ bpl +
lda #0
beq ++
+ lda #1
+ sta $name""")
}
}
">=" -> {
asmgen.out("""
lda $name
cmp #$value
lda #0
adc #0
sta $name""")
if(dt==DataType.UBYTE) {
asmgen.out("""
lda $name
cmp #$value
bcs +
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")
}
@ -1319,8 +1438,174 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
lda #0
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")
}
}
@ -1650,33 +1935,63 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
sta $name+1""")
}
"<=" -> {
val compareRoutine = if(dt==DataType.UWORD) "reg_lesseq_uw" else "reg_lesseq_w"
asmgen.out("""
if(dt==DataType.UWORD) {
asmgen.out("""
lda $otherName
ldy $otherName+1
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda $name
ldy $name+1
jsr prog8_lib.$compareRoutine
jsr prog8_lib.reg_lesseq_uw
sta $name
lda #0
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
val compareRoutine = if(dt==DataType.UWORD) "reg_lesseq_uw" else "reg_lesseq_w"
asmgen.out("""
if(dt==DataType.UWORD) {
asmgen.out("""
lda $name
ldy $name+1
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda $otherName
ldy $otherName+1
jsr prog8_lib.$compareRoutine
jsr prog8_lib.reg_lesseq_uw
sta $name
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")
}
@ -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:
"==", "!=", "<", "<=", ">", ">=" -> 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")
}
// store Fac1 back into memory
asmgen.out("""
ldx #<$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:
"==", "!=", "<", "<=", ">", ">=" -> 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")
}
// store Fac1 back into memory
@ -2129,8 +2507,67 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
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")
}
// store Fac1 back into memory

View File

@ -14,11 +14,6 @@ class ExperiCodeGen: ICodeGeneratorBackend {
errors: IErrorReporter
): 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,
// but you can also use the Intermediate Representation to build a codegen on:
val irCodeGen = IRCodeGen(program, symbolTable, options, errors)

View File

@ -93,7 +93,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} else {
require(origAssign.operator.endsWith('='))
if(codeGen.options.useNewExprCode) {
TODO("use something else than a BinExpr?")
TODO("use something else than a BinExpr")
} else {
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
val left: PtExpression = origAssign.target.children.single() as PtExpression
@ -268,7 +268,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} else {
val mult : PtExpression
if(codeGen.options.useNewExprCode) {
TODO("use something else than a BinExpr?")
TODO("use something else than a BinExpr")
} else {
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
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)
"rol2" -> funcRolRor(Opcode.ROL, call)
"ror2" -> funcRolRor(Opcode.ROR, call)
"prog8_lib_stringcompare" -> funcStringCompare(call)
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)
}
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 {
val result = mutableListOf<IRCodeChunkBase>()
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 {
require(!codeGen.options.useNewExprCode)
val vmDt = codeGen.irType(binExpr.left.type)
val signed = binExpr.left.type in SignedDatatypes
return when(binExpr.operator) {

View File

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

View File

@ -14,13 +14,6 @@ class VmCodeGen: ICodeGeneratorBackend {
options: CompilationOptions,
errors: IErrorReporter
): 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 irProgram = irCodeGen.generate()
return VmAssemblyProgram(irProgram.name, irProgram)

View File

@ -251,7 +251,7 @@ pop_float_fac1 .proc
.pend
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.
sta _target+1
sty _target+2

View File

@ -4,11 +4,12 @@ import com.github.michaelbull.result.onFailure
import prog8.ast.IBuiltinFunctions
import prog8.ast.Program
import prog8.ast.base.AstException
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.Expression
import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.Directive
import prog8.code.SymbolTableMaker
import prog8.code.ast.PtProgram
import prog8.code.ast.*
import prog8.code.core.*
import prog8.code.target.*
import prog8.codegen.vm.VmCodeGen
@ -409,6 +410,11 @@ private fun createAssemblyAndAssemble(program: PtProgram,
else
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 symbolTable = stMaker.make()
val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors)
@ -420,3 +426,188 @@ private fun createAssemblyAndAssemble(program: PtProgram,
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) {
// 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)

View File

@ -36,6 +36,19 @@ internal class BeforeAsmAstChanger(val program: Program,
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> {
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")

View File

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

View File

@ -109,6 +109,8 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
if(binExpr==null || binExpr.operator !in ComparisonOperators)
return noModifications
return noModifications // TODO tijdelijk geen simplify
// Simplify the conditional expression, introduce simple assignments if required.
// 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

View File

@ -1,12 +1,40 @@
%zeropage basicsafe
%import textio
%import floats
%import string
main {
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
ubyte ub = 20
word w = -20000
uword uw = 2000
float f = -100
txt.print("all 1: ")
txt.print_ub(b == -100)
@ -34,7 +62,15 @@ main {
txt.print_ub(uw <= 2000)
txt.print_ub(uw > 1999)
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.print("all 0: ")
txt.print_ub(b == -99)
txt.print_ub(b != -100)
@ -61,6 +97,153 @@ main {
txt.print_ub(uw <= 1999)
txt.print_ub(uw > 2000)
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()
@ -112,9 +295,311 @@ main {
txt.print_uw(uw)
txt.print(" 8000\n")
; float f
; while f<2.2 {
; f+=0.1
; }
f = 0.0
floats.print_f(f)
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
====
replace RPN by something that actually works and is efficient...
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
...