From 5e8f767642ea2f9658dd30d4cb48eb86ff4e310a Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 4 Jan 2023 22:55:05 +0100 Subject: [PATCH] 6502 codegen on new Pt-AST. --- codeCore/src/prog8/code/ast/AstExpressions.kt | 11 + codeCore/src/prog8/code/ast/AstStatements.kt | 6 +- codeGenCpu6502/build.gradle | 1 - codeGenCpu6502/codeGenCpu6502.iml | 1 - .../src/prog8/codegen/cpu6502/AsmGen.kt | 758 ++++++++---------- .../src/prog8/codegen/cpu6502/AsmOptimizer.kt | 25 +- .../prog8/codegen/cpu6502/AsmsubHelpers.kt | 27 +- .../prog8/codegen/cpu6502/AssemblyProgram.kt | 3 +- .../codegen/cpu6502/BuiltinFunctionsAsmGen.kt | 412 +++++----- .../codegen/cpu6502/ExpressionsAsmGen.kt | 131 ++- .../src/prog8/codegen/cpu6502/Extensions.kt | 91 +++ .../prog8/codegen/cpu6502/ForLoopsAsmGen.kt | 160 ++-- .../codegen/cpu6502/FunctionCallAsmGen.kt | 115 ++- .../codegen/cpu6502/PostIncrDecrAsmGen.kt | 32 +- .../codegen/cpu6502/ProgramAndVarsGen.kt | 227 +++--- .../codegen/cpu6502/VariableAllocator.kt | 2 +- .../cpu6502/assignment/AsmAssignment.kt | 86 +- .../cpu6502/assignment/AssignmentAsmGen.kt | 380 ++++----- .../assignment/AugmentableAssignmentAsmGen.kt | 276 ++++--- compiler/src/prog8/compiler/Compiler.kt | 21 +- compilerAst/src/prog8/ast/Program.kt | 5 +- .../src/prog8/ast/statements/AstStatements.kt | 17 - docs/source/todo.rst | 16 +- 23 files changed, 1351 insertions(+), 1452 deletions(-) create mode 100644 codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt diff --git a/codeCore/src/prog8/code/ast/AstExpressions.kt b/codeCore/src/prog8/code/ast/AstExpressions.kt index 1e1cbe084..417fd0d6c 100644 --- a/codeCore/src/prog8/code/ast/AstExpressions.kt +++ b/codeCore/src/prog8/code/ast/AstExpressions.kt @@ -43,6 +43,10 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit else -> false } } + + infix fun isSameAs(target: PtAssignTarget): Boolean { + TODO() + } } class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) { @@ -66,6 +70,8 @@ class PtArray(type: DataType, position: Position): PtExpression(type, position) return false return type==other.type && children == other.children } + + val size: Int = children.size } @@ -141,6 +147,11 @@ class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position) class PtNumber(type: DataType, val number: Double, position: Position) : PtExpression(type, position) { + companion object { + fun fromBoolean(bool: Boolean, position: Position): PtNumber = + PtNumber(DataType.UBYTE, if(bool) 1.0 else 0.0, position) + } + init { if(type==DataType.BOOL) throw IllegalArgumentException("bool should have become ubyte @$position") diff --git a/codeCore/src/prog8/code/ast/AstStatements.kt b/codeCore/src/prog8/code/ast/AstStatements.kt index 94a7cf328..753e4fc27 100644 --- a/codeCore/src/prog8/code/ast/AstStatements.kt +++ b/codeCore/src/prog8/code/ast/AstStatements.kt @@ -3,6 +3,8 @@ package prog8.code.ast import prog8.code.core.* +interface IPtSubroutine + class PtAsmSub( name: String, val address: UInt?, @@ -12,7 +14,7 @@ class PtAsmSub( val retvalRegisters: List, val inline: Boolean, position: Position -) : PtNamedNode(name, position) { +) : PtNamedNode(name, position), IPtSubroutine { override fun printProperties() { print("$name inline=$inline") } @@ -25,7 +27,7 @@ class PtSub( val returntype: DataType?, val inline: Boolean, position: Position -) : PtNamedNode(name, position) { +) : PtNamedNode(name, position), IPtSubroutine { override fun printProperties() { print(name) } diff --git a/codeGenCpu6502/build.gradle b/codeGenCpu6502/build.gradle index 4d3442e25..96b17d79c 100644 --- a/codeGenCpu6502/build.gradle +++ b/codeGenCpu6502/build.gradle @@ -25,7 +25,6 @@ compileTestKotlin { dependencies { implementation project(':codeCore') - implementation project(':compilerAst') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" // implementation "org.jetbrains.kotlin:kotlin-reflect" implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16" diff --git a/codeGenCpu6502/codeGenCpu6502.iml b/codeGenCpu6502/codeGenCpu6502.iml index 4e52dfb59..ea1d940e1 100644 --- a/codeGenCpu6502/codeGenCpu6502.iml +++ b/codeGenCpu6502/codeGenCpu6502.iml @@ -10,7 +10,6 @@ - \ No newline at end of file diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index fe9bf79fd..ba1e0b4a0 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -1,20 +1,11 @@ package prog8.codegen.cpu6502 import com.github.michaelbull.result.fold -import prog8.ast.IFunctionCall -import prog8.ast.Node -import prog8.ast.ParentSentinel -import prog8.ast.Program -import prog8.ast.base.FatalAstException -import prog8.ast.expressions.* -import prog8.ast.statements.* import prog8.code.SymbolTable +import prog8.code.ast.* import prog8.code.core.* import prog8.codegen.cpu6502.assignment.* -import prog8.compiler.BuiltinFunctions -import prog8.compiler.builtinFunctionReturnType import java.util.* -import kotlin.io.path.Path import kotlin.io.path.writeLines @@ -22,7 +13,7 @@ internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1" internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2" -class AsmGen(internal val program: Program, +class AsmGen(internal val program: PtProgram, internal val symbolTable: SymbolTable, internal val options: CompilationOptions, internal val errors: IErrorReporter @@ -72,7 +63,7 @@ class AsmGen(internal val program: Program, internal fun isTargetCpu(cpu: CpuType) = options.compTarget.machine.cpu == cpu - internal fun outputSourceLine(node: Node) { + internal fun outputSourceLine(node: PtNode) { out(" ;\tsrc line: ${node.position.file}:${node.position.line}") } @@ -97,8 +88,8 @@ class AsmGen(internal val program: Program, fun asmVariableName(name: String) = fixNameSymbols(name) fun asmSymbolName(name: Iterable) = fixNameSymbols(name.joinToString(".")) fun asmVariableName(name: Iterable) = fixNameSymbols(name.joinToString(".")) - fun asmSymbolName(identifier: IdentifierReference) = asmSymbolName(identifier.nameInSource) - fun asmVariableName(identifier: IdentifierReference) = asmVariableName(identifier.nameInSource) + fun asmSymbolName(identifier: PtIdentifier) = asmSymbolName(identifier.name) + fun asmVariableName(identifier: PtIdentifier) = asmVariableName(identifier.name) internal fun getTempVarName(dt: DataType): String { return when(dt) { @@ -107,23 +98,23 @@ class AsmGen(internal val program: Program, DataType.UWORD -> "cx16.r9" DataType.WORD -> "cx16.r9s" DataType.FLOAT -> TODO("no temporary float var available") - else -> throw FatalAstException("invalid dt $dt") + else -> throw AssemblyError("invalid dt $dt") } } - internal fun loadByteFromPointerIntoA(pointervar: IdentifierReference): String { + internal fun loadByteFromPointerIntoA(pointervar: PtIdentifier): String { // returns the source name of the zero page pointervar if it's already in the ZP, // otherwise returns "P8ZP_SCRATCH_W1" which is the intermediary when (val target = pointervar.targetStatement(program)) { - is Label -> { + is PtLabel -> { val sourceName = asmSymbolName(pointervar) out(" lda $sourceName") return sourceName } - is VarDecl -> { + is PtVariable -> { val sourceName = asmVariableName(pointervar) if (isTargetCpu(CpuType.CPU65c02)) { - return if (allocator.isZpVar(target.scopedName)) { + return if (allocator.isZpVar(target.scopedName.split('.'))) { // TODO dotted string // pointervar is already in the zero page, no need to copy out(" lda ($sourceName)") sourceName @@ -137,7 +128,7 @@ class AsmGen(internal val program: Program, "P8ZP_SCRATCH_W1" } } else { - return if (allocator.isZpVar(target.scopedName)) { + return if (allocator.isZpVar(target.scopedName.split('.'))) { // TODO dotted string // pointervar is already in the zero page, no need to copy out(" ldy #0 | lda ($sourceName),y") sourceName @@ -157,11 +148,10 @@ class AsmGen(internal val program: Program, } } - internal fun storeAIntoPointerVar(pointervar: IdentifierReference) { + internal fun storeAIntoPointerVar(pointervar: PtIdentifier) { val sourceName = asmVariableName(pointervar) - val vardecl = pointervar.targetVarDecl(program)!! if (isTargetCpu(CpuType.CPU65c02)) { - if (allocator.isZpVar(vardecl.scopedName)) { + if (allocator.isZpVar(pointervar.name.split('.'))) { // TODO dotted string // pointervar is already in the zero page, no need to copy out(" sta ($sourceName)") } else { @@ -173,7 +163,7 @@ class AsmGen(internal val program: Program, sta (P8ZP_SCRATCH_W2)""") } } else { - if (allocator.isZpVar(vardecl.scopedName)) { + if (allocator.isZpVar(pointervar.name.split('.'))) { // TODO dotted string // pointervar is already in the zero page, no need to copy out(" ldy #0 | sta ($sourceName),y") } else { @@ -207,7 +197,7 @@ class AsmGen(internal val program: Program, return name2.replace("prog8_lib.P8ZP_SCRATCH_", "P8ZP_SCRATCH_") // take care of the 'hooks' to the temp vars -> reference zp symbols directly } - internal fun saveRegisterLocal(register: CpuRegister, scope: Subroutine) { + internal fun saveRegisterLocal(register: CpuRegister, scope: PtSub) { if (isTargetCpu(CpuType.CPU65c02)) { // just use the cpu's stack for all registers, shorter code when (register) { @@ -303,54 +293,53 @@ class AsmGen(internal val program: Program, } } - internal fun translate(stmt: Statement) { + internal fun translate(stmt: PtNode) { outputSourceLine(stmt) when(stmt) { - is Directive -> translate(stmt) - is Return -> translate(stmt) - is Subroutine -> programGen.translateSubroutine(stmt) - is InlineAssembly -> translate(stmt) - is BuiltinFunctionCallStatement -> builtinFunctionsAsmGen.translateFunctioncallStatement(stmt) - is FunctionCallStatement -> functioncallAsmGen.translateFunctionCallStatement(stmt) - is Assignment -> assignmentAsmGen.translate(stmt) - is Jump -> { + is PtReturn -> translate(stmt) + is PtSub -> programGen.translateSubroutine(stmt) + is PtAsmSub -> programGen.translateAsmSubroutine(stmt) + is PtInlineAssembly -> translate(stmt) + is PtBuiltinFunctionCall -> builtinFunctionsAsmGen.translateFunctioncallStatement(stmt) + is PtFunctionCall -> functioncallAsmGen.translateFunctionCallStatement(stmt) + is PtAssignment -> assignmentAsmGen.translate(stmt) + is PtJump -> { val (asmLabel, indirect) = getJumpTarget(stmt) jmp(asmLabel, indirect) } - is PostIncrDecr -> postincrdecrAsmGen.translate(stmt) - is Label -> translate(stmt) - is ConditionalBranch -> translate(stmt) - is IfElse -> translate(stmt) - is ForLoop -> forloopsAsmGen.translate(stmt) - is RepeatLoop -> translate(stmt) - is When -> translate(stmt) - is AnonymousScope -> translate(stmt) - is VarDecl -> { /* do nothing; variables are handled elsewhere */ } - is BuiltinFunctionPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore") - is UntilLoop -> throw AssemblyError("do..until should have been converted to jumps") - is WhileLoop -> throw AssemblyError("while should have been converted to jumps") - is Block -> throw AssemblyError("block should have been handled elsewhere") - is Break -> throw AssemblyError("break should have been replaced by goto") + is PtPostIncrDecr -> postincrdecrAsmGen.translate(stmt) + is PtLabel -> translate(stmt) + is PtConditionalBranch -> translate(stmt) + is PtIfElse -> translate(stmt) + is PtForLoop -> forloopsAsmGen.translate(stmt) + is PtRepeatLoop -> translate(stmt) + is PtWhen -> translate(stmt) + is PtIncludeBinary -> TODO() + is PtBreakpoint -> TODO() + is PtVariable -> { /* do nothing; variables are handled elsewhere */ } + is PtBlock -> throw AssemblyError("block should have been handled elsewhere") + is PtNodeGroup -> TODO() + is PtNop -> {} else -> throw AssemblyError("missing asm translation for $stmt") } } internal fun loadScaledArrayIndexIntoRegister( - expr: ArrayIndexedExpression, + expr: PtArrayIndexer, elementDt: DataType, register: CpuRegister, addOneExtra: Boolean = false ) { val reg = register.toString().lowercase() - val indexnum = expr.indexer.constIndex() + val indexnum = expr.index.asConstInteger() if (indexnum != null) { val indexValue = indexnum * options.compTarget.memorySize(elementDt) + if (addOneExtra) 1 else 0 out(" ld$reg #$indexValue") return } - val indexVar = expr.indexer.indexExpr as? IdentifierReference - ?: throw AssemblyError("array indexer should have been replaced with a temp var @ ${expr.indexer.position}") + val indexVar = expr.index as? PtIdentifier + ?: throw AssemblyError("array indexer should have been replaced with a temp var @ ${expr.index.position}") val indexName = asmVariableName(indexVar) if (addOneExtra) { @@ -428,28 +417,28 @@ class AsmGen(internal val program: Program, } @Deprecated("avoid calling this as it generates slow evalstack based code") - internal fun translateExpression(expression: Expression) = + internal fun translateExpression(expression: PtExpression) = expressionsAsmGen.translateExpression(expression) - internal fun translateBuiltinFunctionCallExpression(bfc: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) = + internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) = builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultToStack, resultRegister) - internal fun translateFunctionCall(functionCallExpr: FunctionCallExpression, isExpression: Boolean) = + internal fun translateFunctionCall(functionCallExpr: PtFunctionCall, isExpression: Boolean) = functioncallAsmGen.translateFunctionCall(functionCallExpr, isExpression) - internal fun saveXbeforeCall(functionCall: IFunctionCall) = + internal fun saveXbeforeCall(functionCall: PtFunctionCall) = functioncallAsmGen.saveXbeforeCall(functionCall) - internal fun restoreXafterCall(functionCall: IFunctionCall) = + internal fun restoreXafterCall(functionCall: PtFunctionCall) = functioncallAsmGen.restoreXafterCall(functionCall) internal fun translateNormalAssignment(assign: AsmAssignment) = assignmentAsmGen.translateNormalAssignment(assign) - internal fun assignExpressionToRegister(expr: Expression, register: RegisterOrPair, signed: Boolean=false) = + internal fun assignExpressionToRegister(expr: PtExpression, register: RegisterOrPair, signed: Boolean=false) = assignmentAsmGen.assignExpressionToRegister(expr, register, signed) - internal fun assignExpressionToVariable(expr: Expression, asmVarName: String, dt: DataType, scope: Subroutine?) = + internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType, scope: IPtSubroutine?) = assignmentAsmGen.assignExpressionToVariable(expr, asmVarName, dt, scope) internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, signed: Boolean=false) = @@ -470,7 +459,7 @@ class AsmGen(internal val program: Program, } } - internal fun assignExpressionTo(value: Expression, target: AsmAssignTarget) { + internal fun assignExpressionTo(value: PtExpression, target: AsmAssignTarget) { // don't use translateExpression() to avoid evalstack when (target.datatype) { in ByteDatatypes -> { @@ -519,59 +508,58 @@ class AsmGen(internal val program: Program, } } - private fun translate(stmt: IfElse) { + private fun translate(stmt: PtIfElse) { requireComparisonExpression(stmt.condition) // IfStatement: condition must be of form 'x ' - val booleanCondition = stmt.condition as BinaryExpression + val booleanCondition = stmt.condition - if (stmt.elsepart.isEmpty()) { - val jump = stmt.truepart.statements.singleOrNull() - if(jump is Jump) { + if (stmt.elseScope.children.isEmpty()) { + val jump = stmt.ifScope.children.singleOrNull() + if(jump is PtJump) { translateCompareAndJumpIfTrue(booleanCondition, jump) } else { - val endLabel = program.makeLabel("if_end") + val endLabel = makeLabel("if_end") translateCompareAndJumpIfFalse(booleanCondition, endLabel) - translate(stmt.truepart) + translate(stmt.ifScope) out(endLabel) } } else { // both true and else parts - val elseLabel = program.makeLabel("if_else") - val endLabel = program.makeLabel("if_end") + val elseLabel = makeLabel("if_else") + val endLabel = makeLabel("if_end") translateCompareAndJumpIfFalse(booleanCondition, elseLabel) - translate(stmt.truepart) + translate(stmt.ifScope) jmp(endLabel) out(elseLabel) - translate(stmt.elsepart) + translate(stmt.elseScope) out(endLabel) } } - private fun requireComparisonExpression(condition: Expression) { - if(condition !is BinaryExpression || condition.operator !in ComparisonOperators) + private fun requireComparisonExpression(condition: PtExpression) { + if(condition !is PtBinaryExpression || condition.operator !in ComparisonOperators) throw AssemblyError("expected boolean comparison expression $condition") } - private fun translate(stmt: RepeatLoop) { - val endLabel = program.makeLabel("repeatend") + private fun translate(stmt: PtRepeatLoop) { + val endLabel = makeLabel("repeatend") loopEndLabels.push(endLabel) - when (stmt.iterations) { - null -> throw AssemblyError("repeat-forever loop should have been replaced by label+jump") - is NumericLiteral -> { - val iterations = (stmt.iterations as NumericLiteral).number.toInt() + when (stmt.count) { + is PtNumber -> { + val iterations = (stmt.count as PtNumber).number.toInt() when { iterations == 0 -> {} - iterations == 1 -> translate(stmt.body) + iterations == 1 -> translate(stmt.statements) iterations<0 || iterations>65535 -> throw AssemblyError("invalid number of iterations") iterations <= 256 -> repeatByteCount(iterations, stmt) else -> repeatWordCount(iterations, stmt) } } - is IdentifierReference -> { - val vardecl = (stmt.iterations as IdentifierReference).targetStatement(program) as VarDecl - val name = asmVariableName(stmt.iterations as IdentifierReference) - when(vardecl.datatype) { + is PtIdentifier -> { + val vardecl = (stmt.count as PtIdentifier).targetStatement(program) as PtVariable + val name = asmVariableName(stmt.count as PtIdentifier) + when(vardecl.type) { DataType.UBYTE, DataType.BYTE -> { assignVariableToRegister(name, RegisterOrPair.Y) repeatCountInY(stmt, endLabel) @@ -584,19 +572,16 @@ class AsmGen(internal val program: Program, } } else -> { - val dt = stmt.iterations!!.inferType(program) - if(!dt.isKnown) - throw AssemblyError("unknown dt") - when (dt.getOr(DataType.UNDEFINED)) { + when (stmt.count.type) { in ByteDatatypes -> { - assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.Y) + assignExpressionToRegister(stmt.count, RegisterOrPair.Y) repeatCountInY(stmt, endLabel) } in WordDatatypes -> { - assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.AY) + assignExpressionToRegister(stmt.count, RegisterOrPair.AY) repeatWordCountInAY(endLabel, stmt) } - else -> throw AssemblyError("invalid loop expression datatype $dt") + else -> throw AssemblyError("invalid loop expression datatype ${stmt.count.type}") } } } @@ -604,9 +589,9 @@ class AsmGen(internal val program: Program, loopEndLabels.pop() } - private fun repeatWordCount(count: Int, stmt: RepeatLoop) { + private fun repeatWordCount(count: Int, stmt: PtRepeatLoop) { require(count in 257..65535) { "invalid repeat count ${stmt.position}" } - val repeatLabel = program.makeLabel("repeat") + val repeatLabel = makeLabel("repeat") if(isTargetCpu(CpuType.CPU65c02)) { val counterVar = createRepeatCounterVar(DataType.UWORD, true, stmt) out(""" @@ -615,7 +600,7 @@ class AsmGen(internal val program: Program, sta $counterVar sty $counterVar+1 $repeatLabel""") - translate(stmt.body) + translate(stmt.statements) out(""" lda $counterVar bne + @@ -632,7 +617,7 @@ $repeatLabel""") sta $counterVar sty $counterVar+1 $repeatLabel""") - translate(stmt.body) + translate(stmt.statements) out(""" lda $counterVar bne + @@ -644,10 +629,10 @@ $repeatLabel""") } } - private fun repeatWordCountInAY(endLabel: String, stmt: RepeatLoop) { + private fun repeatWordCountInAY(endLabel: String, stmt: PtRepeatLoop) { // note: A/Y must have been loaded with the number of iterations! // no need to explicitly test for 0 iterations as this is done in the countdown logic below - val repeatLabel = program.makeLabel("repeat") + val repeatLabel = makeLabel("repeat") val counterVar = createRepeatCounterVar(DataType.UWORD, false, stmt) out(""" sta $counterVar @@ -661,58 +646,58 @@ $repeatLabel lda $counterVar dec $counterVar+1 + dec $counterVar """) - translate(stmt.body) + translate(stmt.statements) jmp(repeatLabel) out(endLabel) } - private fun repeatByteCount(count: Int, stmt: RepeatLoop) { + private fun repeatByteCount(count: Int, stmt: PtRepeatLoop) { require(count in 2..256) { "invalid repeat count ${stmt.position}" } - val repeatLabel = program.makeLabel("repeat") + val repeatLabel = makeLabel("repeat") if(isTargetCpu(CpuType.CPU65c02)) { val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt) out(" lda #${count and 255} | sta $counterVar") out(repeatLabel) - translate(stmt.body) + translate(stmt.statements) out(" dec $counterVar | bne $repeatLabel") } else { val counterVar = createRepeatCounterVar(DataType.UBYTE, false, stmt) out(" lda #${count and 255} | sta $counterVar") out(repeatLabel) - translate(stmt.body) + translate(stmt.statements) out(" dec $counterVar | bne $repeatLabel") } } - private fun repeatCountInY(stmt: RepeatLoop, endLabel: String) { + private fun repeatCountInY(stmt: PtRepeatLoop, endLabel: String) { // note: Y must just have been loaded with the (variable) number of loops to be performed! - val repeatLabel = program.makeLabel("repeat") + val repeatLabel = makeLabel("repeat") if(isTargetCpu(CpuType.CPU65c02)) { val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt) out(" beq $endLabel | sty $counterVar") out(repeatLabel) - translate(stmt.body) + translate(stmt.statements) out(" dec $counterVar | bne $repeatLabel") } else { val counterVar = createRepeatCounterVar(DataType.UBYTE, false, stmt) out(" beq $endLabel | sty $counterVar") out(repeatLabel) - translate(stmt.body) + translate(stmt.statements) out(" dec $counterVar | bne $repeatLabel") } out(endLabel) } - private fun createRepeatCounterVar(dt: DataType, preferZeropage: Boolean, stmt: RepeatLoop): String { - val scope = stmt.definingSubroutine!! + private fun createRepeatCounterVar(dt: DataType, preferZeropage: Boolean, stmt: PtRepeatLoop): String { + val scope = stmt.definingSub()!! val asmInfo = subroutineExtra(scope) var parent = stmt.parent - while(parent !is ParentSentinel) { - if(parent is RepeatLoop) + while(parent !is PtProgram) { + if(parent is PtRepeatLoop) break parent = parent.parent } - val isNested = parent is RepeatLoop + val isNested = parent is PtRepeatLoop if(!isNested) { // we can re-use a counter var from the subroutine if it already has one for that datatype @@ -723,7 +708,7 @@ $repeatLabel lda $counterVar } } - val counterVar = program.makeLabel("counter") + val counterVar = makeLabel("counter") when(dt) { DataType.UBYTE, DataType.UWORD -> { val result = zeropage.allocate(listOf(counterVar), dt, null, stmt.position, errors) @@ -737,27 +722,25 @@ $repeatLabel lda $counterVar } } - private fun translate(stmt: When) { - val endLabel = program.makeLabel("choice_end") - val choiceBlocks = mutableListOf>() - val conditionDt = stmt.condition.inferType(program) - if(!conditionDt.isKnown) - throw AssemblyError("unknown condition dt") - if(conditionDt.getOr(DataType.BYTE) in ByteDatatypes) - assignExpressionToRegister(stmt.condition, RegisterOrPair.A) + private fun translate(stmt: PtWhen) { + val endLabel = makeLabel("choice_end") + val choiceBlocks = mutableListOf>() + val conditionDt = stmt.value.type + if(conditionDt in ByteDatatypes) + assignExpressionToRegister(stmt.value, RegisterOrPair.A) else - assignExpressionToRegister(stmt.condition, RegisterOrPair.AY) + assignExpressionToRegister(stmt.value, RegisterOrPair.AY) - for(choice in stmt.choices) { - val choiceLabel = program.makeLabel("choice") - if(choice.values==null) { - // the else choice + for(choiceNode in stmt.choices.children) { + val choice = choiceNode as PtWhenChoice + val choiceLabel = makeLabel("choice") + if(choice.isElse) { translate(choice.statements) } else { choiceBlocks.add(choiceLabel to choice.statements) - for (cv in choice.values!!) { - val value = (cv as NumericLiteral).number.toInt() - if(conditionDt.getOr(DataType.BYTE) in ByteDatatypes) { + for (cv in choice.values.children) { + val value = (cv as PtNumber).number.toInt() + if(conditionDt in ByteDatatypes) { out(" cmp #${value.toHex()} | beq $choiceLabel") } else { out(""" @@ -781,20 +764,15 @@ $repeatLabel lda $counterVar out(endLabel) } - private fun translate(stmt: Label) { + private fun translate(stmt: PtLabel) { out(stmt.name) } - private fun translate(scope: AnonymousScope) { - // note: the variables defined in an anonymous scope have been moved to their defining subroutine's scope - scope.statements.forEach{ translate(it) } - } - - private fun translate(stmt: ConditionalBranch) { - if(stmt.truepart.isEmpty() && stmt.elsepart.isNotEmpty()) + private fun translate(stmt: PtConditionalBranch) { + if(stmt.trueScope.children.isEmpty() && stmt.falseScope.children.isNotEmpty()) throw AssemblyError("only else part contains code, shoud have been switched already") - val jump = stmt.truepart.statements.firstOrNull() as? Jump + val jump = stmt.trueScope.children.firstOrNull() as? PtJump if(jump!=null) { // branch with only a jump (goto) val instruction = branchInstruction(stmt.condition, false) @@ -809,65 +787,31 @@ $repeatLabel lda $counterVar else { out(" $instruction $asmLabel") } - translate(stmt.elsepart) + translate(stmt.falseScope) } else { - if(stmt.elsepart.isEmpty()) { - if(stmt.truepart.isNotEmpty()) { + if(stmt.falseScope.children.isEmpty()) { + if(stmt.trueScope.children.isNotEmpty()) { val instruction = branchInstruction(stmt.condition, true) - val elseLabel = program.makeLabel("branch_else") + val elseLabel = makeLabel("branch_else") out(" $instruction $elseLabel") - translate(stmt.truepart) + translate(stmt.trueScope) out(elseLabel) } } else { val instruction = branchInstruction(stmt.condition, true) - val elseLabel = program.makeLabel("branch_else") - val endLabel = program.makeLabel("branch_end") + val elseLabel = makeLabel("branch_else") + val endLabel = makeLabel("branch_end") out(" $instruction $elseLabel") - translate(stmt.truepart) + translate(stmt.trueScope) jmp(endLabel) out(elseLabel) - translate(stmt.elsepart) + translate(stmt.falseScope) out(endLabel) } } } - private fun translate(stmt: Directive) { - when(stmt.directive) { - "%asminclude" -> { - val includedName = stmt.args[0].str!! - if(stmt.definingModule.source is SourceCode.Generated) - throw AssemblyError("%asminclude inside non-library/non-filesystem module not yet supported") - loadAsmIncludeFile(includedName, stmt.definingModule.source).fold( - success = { assemblyLines.add(it.trimEnd().trimStart('\r', '\n')) }, - failure = { errors.err(it.toString(), stmt.position) } - ) - } - "%asmbinary" -> { - val includedName = stmt.args[0].str!! - val offset = if(stmt.args.size>1) ", ${stmt.args[1].int}" else "" - val length = if(stmt.args.size>2) ", ${stmt.args[2].int}" else "" - if(stmt.definingModule.source is SourceCode.Generated) - throw AssemblyError("%asmbinary inside non-library/non-filesystem module not yet supported") - val sourcePath = Path(stmt.definingModule.source.origin) - val includedPath = sourcePath.resolveSibling(includedName) - val pathForAssembler = options.outputDir // #54: 64tass needs the path *relative to the .asm file* - .toAbsolutePath() - .relativize(includedPath.toAbsolutePath()) - .normalize() // avoid assembler warnings (-Wportable; only some, not all) - .toString().replace('\\', '/') - out(" .binary \"$pathForAssembler\" $offset $length") - } - "%breakpoint" -> { - val label = "_prog8_breakpoint_${breakpointLabels.size+1}" - breakpointLabels.add(label) - out(label) - } - } - } - - private fun getJumpTarget(jump: Jump): Pair { + private fun getJumpTarget(jump: PtJump): Pair { val ident = jump.identifier val label = jump.generatedLabel val addr = jump.address @@ -886,21 +830,18 @@ $repeatLabel lda $counterVar } } - private fun translate(ret: Return, withRts: Boolean=true) { + private fun translate(ret: PtReturn, withRts: Boolean=true) { ret.value?.let { returnvalue -> - val sub = ret.definingSubroutine!! - val returnType = sub.returntypes.single() - val returnReg = sub.asmReturnvaluesRegisters.single() - if(returnReg.registerOrPair==null) - throw AssemblyError("normal subroutines can't return value in status register directly") - - when (returnType) { + val sub = ret.definingSub()!! + val returnReg = RegisterOrStatusflag(RegisterOrPair.A, null) // TODO("what is returnReg of the sub?") + when (sub.returntype) { in NumericDatatypes -> { assignExpressionToRegister(returnvalue, returnReg.registerOrPair!!) } else -> { // all else take its address and assign that also to AY register pair - val addrofValue = AddressOf(returnvalue as IdentifierReference, returnvalue.position) + val addrofValue = PtAddressOf(returnvalue.position) + addrofValue.add(returnvalue as PtIdentifier) assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair!!, false) } } @@ -910,33 +851,10 @@ $repeatLabel lda $counterVar out(" rts") } - private fun translate(asm: InlineAssembly) { + private fun translate(asm: PtInlineAssembly) { assemblyLines.add(asm.assembly.trimEnd().trimStart('\r', '\n')) } - internal fun returnRegisterOfFunction(it: IdentifierReference): RegisterOrPair { - return when (val targetRoutine = it.targetStatement(program)!!) { - is BuiltinFunctionPlaceholder -> { - val func = BuiltinFunctions.getValue(targetRoutine.name) - when (func.returnType) { - in ByteDatatypes -> RegisterOrPair.A - in WordDatatypes -> RegisterOrPair.AY - DataType.FLOAT -> RegisterOrPair.FAC1 - else -> { - when(builtinFunctionReturnType(func.name).getOrElse { DataType.UNDEFINED }) { - in ByteDatatypes -> RegisterOrPair.A - in WordDatatypes -> RegisterOrPair.AY - DataType.FLOAT -> RegisterOrPair.FAC1 - else -> throw AssemblyError("weird returntype") - } - } - } - } - is Subroutine -> targetRoutine.asmReturnvaluesRegisters.single().registerOrPair!! - else -> throw AssemblyError("invalid call target") - } - } - internal fun signExtendAYlsb(valueDt: DataType) { // sign extend signed byte in A to full word in AY when(valueDt) { @@ -987,8 +905,7 @@ $repeatLabel lda $counterVar } } - internal fun isZpVar(variable: IdentifierReference): Boolean = - allocator.isZpVar(variable.targetVarDecl(program)!!.scopedName) + internal fun isZpVar(variable: PtIdentifier): Boolean = allocator.isZpVar(variable.name.split('.')) // TODO as dotted string internal fun jmp(asmLabel: String, indirect: Boolean=false) { if(indirect) { @@ -1001,45 +918,45 @@ $repeatLabel lda $counterVar } } - internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: Expression): Pair? { - if(pointerOffsetExpr is BinaryExpression && pointerOffsetExpr.operator=="+") { - val leftDt = pointerOffsetExpr.left.inferType(program) - val rightDt = pointerOffsetExpr.left.inferType(program) - if(leftDt istype DataType.UWORD && rightDt istype DataType.UBYTE) + internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: PtExpression): Pair? { + if(pointerOffsetExpr is PtBinaryExpression && pointerOffsetExpr.operator=="+") { + val leftDt = pointerOffsetExpr.left.type + val rightDt = pointerOffsetExpr.left.type + if(leftDt == DataType.UWORD && rightDt == DataType.UBYTE) return Pair(pointerOffsetExpr.left, pointerOffsetExpr.right) - if(leftDt istype DataType.UBYTE && rightDt istype DataType.UWORD) + if(leftDt == DataType.UBYTE && rightDt == DataType.UWORD) return Pair(pointerOffsetExpr.right, pointerOffsetExpr.left) - if(leftDt istype DataType.UWORD && rightDt istype DataType.UWORD) { + if(leftDt == DataType.UWORD && rightDt == DataType.UWORD) { // could be that the index was a constant numeric byte but converted to word, check that - val constIdx = pointerOffsetExpr.right.constValue(program) + val constIdx = pointerOffsetExpr.right as? PtNumber if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) { - return Pair(pointerOffsetExpr.left, NumericLiteral(DataType.UBYTE, constIdx.number, constIdx.position)) + return Pair(pointerOffsetExpr.left, PtNumber(DataType.UBYTE, constIdx.number, constIdx.position)) } // could be that the index was typecasted into uword, check that - val rightTc = pointerOffsetExpr.right as? TypecastExpression - if(rightTc!=null && rightTc.expression.inferType(program) istype DataType.UBYTE) - return Pair(pointerOffsetExpr.left, rightTc.expression) - val leftTc = pointerOffsetExpr.left as? TypecastExpression - if(leftTc!=null && leftTc.expression.inferType(program) istype DataType.UBYTE) - return Pair(pointerOffsetExpr.right, leftTc.expression) + val rightTc = pointerOffsetExpr.right as? PtTypeCast + if(rightTc!=null && rightTc.value.type == DataType.UBYTE) + return Pair(pointerOffsetExpr.left, rightTc.value) + val leftTc = pointerOffsetExpr.left as? PtTypeCast + if(leftTc!=null && leftTc.value.type == DataType.UBYTE) + return Pair(pointerOffsetExpr.right, leftTc.value) } } return null } - internal fun tryOptimizedPointerAccessWithA(expr: BinaryExpression, write: Boolean): Boolean { + internal fun tryOptimizedPointerAccessWithA(expr: PtBinaryExpression, write: Boolean): Boolean { // optimize pointer,indexregister if possible - fun evalBytevalueWillClobberA(expr: Expression): Boolean { - val dt = expr.inferType(program) - if(dt isnot DataType.UBYTE && dt isnot DataType.BYTE) + fun evalBytevalueWillClobberA(expr: PtExpression): Boolean { + val dt = expr.type + if(dt != DataType.UBYTE && dt != DataType.BYTE) return true return when(expr) { - is IdentifierReference -> false - is NumericLiteral -> false - is DirectMemoryRead -> expr.addressExpression !is IdentifierReference && expr.addressExpression !is NumericLiteral - is TypecastExpression -> evalBytevalueWillClobberA(expr.expression) + is PtIdentifier -> false + is PtNumber -> false + is PtMemoryByte -> expr.address !is PtIdentifier && expr.address !is PtNumber + is PtTypeCast -> evalBytevalueWillClobberA(expr.value) else -> true } } @@ -1048,14 +965,14 @@ $repeatLabel lda $counterVar if(expr.operator=="+") { val ptrAndIndex = pointerViaIndexRegisterPossible(expr) if(ptrAndIndex!=null) { - val pointervar = ptrAndIndex.first as? IdentifierReference + val pointervar = ptrAndIndex.first as? PtIdentifier when(pointervar?.targetStatement(program)) { - is Label -> { + is PtLabel -> { assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) - out(" lda ${asmSymbolName(pointervar)},y") + out(" lda ${asmSymbolName(pointervar!!)},y") return true } - is VarDecl, null -> { + is PtVariable, null -> { if(write) { if(pointervar!=null && isZpVar(pointervar)) { val saveA = evalBytevalueWillClobberA(ptrAndIndex.second) @@ -1070,7 +987,7 @@ $repeatLabel lda $counterVar val saveA = evalBytevalueWillClobberA(ptrAndIndex.first) || evalBytevalueWillClobberA(ptrAndIndex.second) if(saveA) out(" pha") - if(ptrAndIndex.second.isSimple) { + if(ptrAndIndex.second.isSimple()) { assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) if(saveA) @@ -1091,7 +1008,7 @@ $repeatLabel lda $counterVar out(" lda (${asmSymbolName(pointervar)}),y") } else { // copy the pointer var to zp first - if(ptrAndIndex.second.isSimple) { + if(ptrAndIndex.second.isSimple()) { assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) out(" lda (P8ZP_SCRATCH_W2),y") @@ -1112,7 +1029,7 @@ $repeatLabel lda $counterVar return false } - private fun translateCompareAndJumpIfTrue(expr: BinaryExpression, jump: Jump) { + private fun translateCompareAndJumpIfTrue(expr: PtBinaryExpression, jump: PtJump) { if(expr.operator !in ComparisonOperators) throw AssemblyError("must be comparison expression") @@ -1122,7 +1039,7 @@ $repeatLabel lda $counterVar val left = expr.left val right = expr.right - val rightConstVal = right.constValue(program) + val rightConstVal = right as? PtNumber val label = when { jump.generatedLabel!=null -> jump.generatedLabel!! @@ -1133,17 +1050,17 @@ $repeatLabel lda $counterVar if (rightConstVal!=null && rightConstVal.number == 0.0) testZeroAndJump(left, invertedComparisonOperator, label) else { - val leftConstVal = left.constValue(program) + val leftConstVal = left as? PtNumber testNonzeroComparisonAndJump(left, invertedComparisonOperator, right, label, leftConstVal, rightConstVal) } } - private fun translateCompareAndJumpIfFalse(expr: BinaryExpression, jumpIfFalseLabel: String) { + private fun translateCompareAndJumpIfFalse(expr: PtBinaryExpression, jumpIfFalseLabel: String) { val left = expr.left val right = expr.right val operator = expr.operator - val leftConstVal = left.constValue(program) - val rightConstVal = right.constValue(program) + val leftConstVal = left as? PtNumber + val rightConstVal = right as? PtNumber if (rightConstVal!=null && rightConstVal.number == 0.0) testZeroAndJump(left, operator, jumpIfFalseLabel) @@ -1152,12 +1069,12 @@ $repeatLabel lda $counterVar } private fun testZeroAndJump( - left: Expression, + left: PtExpression, operator: String, jumpIfFalseLabel: String ) { - val dt = left.inferType(program).getOr(DataType.UNDEFINED) - if(dt in IntegerDatatypes && left is IdentifierReference) + val dt = left.type + if(dt in IntegerDatatypes && left is PtIdentifier) return testVariableZeroAndJump(left, dt, operator, jumpIfFalseLabel) when(dt) { @@ -1170,7 +1087,7 @@ $repeatLabel lda $counterVar } if(dt==DataType.UBYTE || dt==DataType.BOOL) { assignExpressionToRegister(left, RegisterOrPair.A, false) - if (left is IFunctionCall && !left.isSimple) + if (left is PtFunctionCall && !left.isSimple()) out(" cmp #0") } else { assignExpressionToRegister(left, RegisterOrPair.AY, false) @@ -1186,7 +1103,7 @@ $repeatLabel lda $counterVar } DataType.BYTE -> { assignExpressionToRegister(left, RegisterOrPair.A, true) - if (left is IFunctionCall && !left.isSimple) + if (left is PtFunctionCall && !left.isSimple()) out(" cmp #0") when (operator) { "==" -> out(" bne $jumpIfFalseLabel") @@ -1244,7 +1161,7 @@ $repeatLabel lda $counterVar } } - private fun testVariableZeroAndJump(variable: IdentifierReference, dt: DataType, operator: String, jumpIfFalseLabel: String) { + private fun testVariableZeroAndJump(variable: PtIdentifier, dt: DataType, operator: String, jumpIfFalseLabel: String) { // optimized code if the expression is just an identifier (variable) val varname = asmVariableName(variable) when(dt) { @@ -1305,14 +1222,14 @@ $repeatLabel lda $counterVar } private fun testNonzeroComparisonAndJump( - left: Expression, + left: PtExpression, operator: String, - right: Expression, + right: PtExpression, jumpIfFalseLabel: String, - leftConstVal: NumericLiteral?, - rightConstVal: NumericLiteral? + leftConstVal: PtNumber?, + rightConstVal: PtNumber? ) { - val dt = left.inferType(program).getOrElse { throw AssemblyError("unknown dt") } + val dt = left.type when (operator) { "==" -> { @@ -1320,7 +1237,7 @@ $repeatLabel lda $counterVar 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 IdentifierReference, right as IdentifierReference, jumpIfFalseLabel) + DataType.STR -> translateStringEqualsJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) else -> throw AssemblyError("weird operand datatype") } } @@ -1329,7 +1246,7 @@ $repeatLabel lda $counterVar 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 IdentifierReference, right as IdentifierReference, jumpIfFalseLabel) + DataType.STR -> translateStringNotEqualsJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) else -> throw AssemblyError("weird operand datatype") } } @@ -1340,7 +1257,7 @@ $repeatLabel lda $counterVar 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 IdentifierReference, right as IdentifierReference, jumpIfFalseLabel) + DataType.STR -> translateStringLessJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) else -> throw AssemblyError("weird operand datatype") } } @@ -1351,7 +1268,7 @@ $repeatLabel lda $counterVar 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 IdentifierReference, right as IdentifierReference, jumpIfFalseLabel) + DataType.STR -> translateStringLessOrEqualJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) else -> throw AssemblyError("weird operand datatype") } } @@ -1362,7 +1279,7 @@ $repeatLabel lda $counterVar 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 IdentifierReference, right as IdentifierReference, jumpIfFalseLabel) + DataType.STR -> translateStringGreaterJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) else -> throw AssemblyError("weird operand datatype") } } @@ -1373,21 +1290,21 @@ $repeatLabel lda $counterVar 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 IdentifierReference, right as IdentifierReference, jumpIfFalseLabel) + DataType.STR -> translateStringGreaterOrEqualJump(left as PtIdentifier, right as PtIdentifier, jumpIfFalseLabel) else -> throw AssemblyError("weird operand datatype") } } } } - private fun translateFloatLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateFloatLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { if(leftConstVal!=null && rightConstVal!=null) { throw AssemblyError("const-compare should have been optimized away") } - else if(leftConstVal!=null && right is IdentifierReference) { + else if(leftConstVal!=null && right is PtIdentifier) { throw AssemblyError("const-compare should have been optimized to have const as right operand") } - else if(left is IdentifierReference && rightConstVal!=null) { + else if(left is PtIdentifier && rightConstVal!=null) { val leftName = asmVariableName(left) val rightName = allocator.getFloatAsmConst(rightConstVal.number) out(""" @@ -1400,7 +1317,7 @@ $repeatLabel lda $counterVar jsr floats.vars_less_f beq $jumpIfFalseLabel""") } - else if(left is IdentifierReference && right is IdentifierReference) { + else if(left is PtIdentifier && right is PtIdentifier) { val leftName = asmVariableName(left) val rightName = asmVariableName(right) out(""" @@ -1413,7 +1330,7 @@ $repeatLabel lda $counterVar jsr floats.vars_less_f beq $jumpIfFalseLabel""") } else { - val subroutine = left.definingSubroutine!! + val subroutine = left.definingSub()!! subroutineExtra(subroutine).usedFloatEvalResultVar1 = true assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToRegister(left, RegisterOrPair.FAC1) @@ -1425,14 +1342,14 @@ $repeatLabel lda $counterVar } } - private fun translateFloatLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateFloatLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { if(leftConstVal!=null && rightConstVal!=null) { throw AssemblyError("const-compare should have been optimized away") } - else if(leftConstVal!=null && right is IdentifierReference) { + else if(leftConstVal!=null && right is PtIdentifier) { throw AssemblyError("const-compare should have been optimized to have const as right operand") } - else if(left is IdentifierReference && rightConstVal!=null) { + else if(left is PtIdentifier && rightConstVal!=null) { val leftName = asmVariableName(left) val rightName = allocator.getFloatAsmConst(rightConstVal.number) out(""" @@ -1445,7 +1362,7 @@ $repeatLabel lda $counterVar jsr floats.vars_lesseq_f beq $jumpIfFalseLabel""") } - else if(left is IdentifierReference && right is IdentifierReference) { + else if(left is PtIdentifier && right is PtIdentifier) { val leftName = asmVariableName(left) val rightName = asmVariableName(right) out(""" @@ -1458,7 +1375,7 @@ $repeatLabel lda $counterVar jsr floats.vars_lesseq_f beq $jumpIfFalseLabel""") } else { - val subroutine = left.definingSubroutine!! + val subroutine = left.definingSub()!! subroutineExtra(subroutine).usedFloatEvalResultVar1 = true assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToRegister(left, RegisterOrPair.FAC1) @@ -1470,11 +1387,11 @@ $repeatLabel lda $counterVar } } - private fun translateFloatGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateFloatGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { if(leftConstVal!=null && rightConstVal!=null) { throw AssemblyError("const-compare should have been optimized away") } - else if(left is IdentifierReference && rightConstVal!=null) { + else if(left is PtIdentifier && rightConstVal!=null) { val leftName = asmVariableName(left) val rightName = allocator.getFloatAsmConst(rightConstVal.number) out(""" @@ -1487,10 +1404,10 @@ $repeatLabel lda $counterVar jsr floats.vars_less_f beq $jumpIfFalseLabel""") } - else if(leftConstVal!=null && right is IdentifierReference) { + else if(leftConstVal!=null && right is PtIdentifier) { throw AssemblyError("const-compare should have been optimized to have const as right operand") } - else if(left is IdentifierReference && right is IdentifierReference) { + else if(left is PtIdentifier && right is PtIdentifier) { val leftName = asmVariableName(left) val rightName = asmVariableName(right) out(""" @@ -1503,7 +1420,7 @@ $repeatLabel lda $counterVar jsr floats.vars_less_f beq $jumpIfFalseLabel""") } else { - val subroutine = left.definingSubroutine!! + val subroutine = left.definingSub()!! subroutineExtra(subroutine).usedFloatEvalResultVar1 = true assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToRegister(left, RegisterOrPair.FAC1) @@ -1515,11 +1432,11 @@ $repeatLabel lda $counterVar } } - private fun translateFloatGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateFloatGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { if(leftConstVal!=null && rightConstVal!=null) { throw AssemblyError("const-compare should have been optimized away") } - else if(left is IdentifierReference && rightConstVal!=null) { + else if(left is PtIdentifier && rightConstVal!=null) { val leftName = asmVariableName(left) val rightName = allocator.getFloatAsmConst(rightConstVal.number) out(""" @@ -1532,10 +1449,10 @@ $repeatLabel lda $counterVar jsr floats.vars_lesseq_f beq $jumpIfFalseLabel""") } - else if(leftConstVal!=null && right is IdentifierReference) { + else if(leftConstVal!=null && right is PtIdentifier) { throw AssemblyError("const-compare should have been optimized to have const as right operand") } - else if(left is IdentifierReference && right is IdentifierReference) { + else if(left is PtIdentifier && right is PtIdentifier) { val leftName = asmVariableName(left) val rightName = asmVariableName(right) out(""" @@ -1548,7 +1465,7 @@ $repeatLabel lda $counterVar jsr floats.vars_lesseq_f beq $jumpIfFalseLabel""") } else { - val subroutine = left.definingSubroutine!! + val subroutine = left.definingSub()!! subroutineExtra(subroutine).usedFloatEvalResultVar1 = true assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToRegister(left, RegisterOrPair.FAC1) @@ -1560,7 +1477,7 @@ $repeatLabel lda $counterVar } } - private fun translateUbyteLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateUbyteLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(cmpOperand: String) { out(" cmp $cmpOperand | bcs $jumpIfFalseLabel") @@ -1572,7 +1489,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { return if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(left, RegisterOrPair.A) code("#${rightConstVal.number.toInt()}") @@ -1580,7 +1497,7 @@ $repeatLabel lda $counterVar else jmp(jumpIfFalseLabel) } - else if (left is DirectMemoryRead) { + else if (left is PtMemoryByte) { return if(rightConstVal.number.toInt()!=0) { translateDirectMemReadExpressionToRegAorStack(left, false) code("#${rightConstVal.number.toInt()}") @@ -1594,7 +1511,7 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) } else { @@ -1605,7 +1522,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateByteLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateByteLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(sbcOperand: String) { out(""" @@ -1622,7 +1539,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number}") @@ -1635,7 +1552,7 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) } else { @@ -1646,7 +1563,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateUwordLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateUwordLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) { out(""" @@ -1664,7 +1581,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { return if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(left, RegisterOrPair.AY) code("#>${rightConstVal.number.toInt()}", "#<${rightConstVal.number.toInt()}") @@ -1678,7 +1595,7 @@ $repeatLabel lda $counterVar if(wordJumpForSimpleRightOperands(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(left, RegisterOrPair.AY) } else { @@ -1690,7 +1607,7 @@ $repeatLabel lda $counterVar return out(" jsr prog8_lib.reg_less_uw | beq $jumpIfFalseLabel") } - private fun translateWordLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateWordLessJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) { out(""" @@ -1708,7 +1625,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { return if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(left, RegisterOrPair.AY) code("#>${rightConstVal.number.toInt()}", "#<${rightConstVal.number.toInt()}") @@ -1724,7 +1641,7 @@ $repeatLabel lda $counterVar if(wordJumpForSimpleRightOperands(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD, null) assignExpressionToRegister(left, RegisterOrPair.AY) } else { @@ -1736,7 +1653,7 @@ $repeatLabel lda $counterVar return out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel") } - private fun translateUbyteGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateUbyteGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(cmpOperand: String) { out(""" @@ -1751,14 +1668,14 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") else out(" beq $jumpIfFalseLabel") } - else if (left is DirectMemoryRead) { + else if (left is PtMemoryByte) { translateDirectMemReadExpressionToRegAorStack(left, false) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") @@ -1771,7 +1688,7 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) } else { @@ -1782,7 +1699,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateByteGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateByteGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(sbcOperand: String) { out(""" @@ -1801,7 +1718,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number}") @@ -1814,7 +1731,7 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) } else { @@ -1825,7 +1742,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateUwordGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateUwordGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) { out(""" @@ -1844,7 +1761,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { return if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(left, RegisterOrPair.AY) code("#>${rightConstVal.number.toInt()}", "#<${rightConstVal.number.toInt()}") @@ -1863,7 +1780,7 @@ $repeatLabel lda $counterVar if(wordJumpForSimpleRightOperands(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(left, RegisterOrPair.AY) } else { @@ -1875,7 +1792,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_W2+1", "P8ZP_SCRATCH_W2") } - private fun translateWordGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateWordGreaterJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(msbCmpOperand: String, lsbCmpOperand: String) { out(""" @@ -1893,7 +1810,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { return if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(right, RegisterOrPair.AY) val varname = asmVariableName(left) @@ -1914,7 +1831,7 @@ $repeatLabel lda $counterVar if(wordJumpForSimpleLeftOperand(left, right, ::code)) return - if(right.isSimple) { + if(right.isSimple()) { assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD, null) assignExpressionToRegister(right, RegisterOrPair.AY) } else { @@ -1926,7 +1843,7 @@ $repeatLabel lda $counterVar return out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel") } - private fun translateUbyteLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateUbyteLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(cmpOperand: String) { out(""" @@ -1942,14 +1859,14 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") else out(" bne $jumpIfFalseLabel") } - else if (left is DirectMemoryRead) { + else if (left is PtMemoryByte) { translateDirectMemReadExpressionToRegAorStack(left, false) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") @@ -1962,7 +1879,7 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) } else { @@ -1973,7 +1890,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateByteLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateByteLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(sbcOperand: String) { out(""" clc @@ -1989,7 +1906,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number}") @@ -2005,7 +1922,7 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) } else { @@ -2016,7 +1933,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateUwordLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateUwordLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) { out(""" @@ -2037,7 +1954,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { return if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(left, RegisterOrPair.AY) code("#>${rightConstVal.number.toInt()}", "#<${rightConstVal.number.toInt()}") @@ -2056,7 +1973,7 @@ $repeatLabel lda $counterVar if(wordJumpForSimpleRightOperands(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(left, RegisterOrPair.AY) } else { @@ -2068,7 +1985,7 @@ $repeatLabel lda $counterVar return out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel") } - private fun translateWordLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateWordLessOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(leftName: String) { out(""" @@ -2087,7 +2004,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { return if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(right, RegisterOrPair.AY) code(asmVariableName(left)) @@ -2106,12 +2023,12 @@ $repeatLabel lda $counterVar } } - if(left is IdentifierReference) { + if(left is PtIdentifier) { assignExpressionToRegister(right, RegisterOrPair.AY) return code(asmVariableName(left)) } - if(right.isSimple) { + if(right.isSimple()) { assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.WORD, null) assignExpressionToRegister(right, RegisterOrPair.AY) } else { @@ -2123,7 +2040,7 @@ $repeatLabel lda $counterVar return out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel") } - private fun translateUbyteGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateUbyteGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(cmpOperand: String) { out(" cmp $cmpOperand | bcc $jumpIfFalseLabel") @@ -2135,14 +2052,14 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(left, RegisterOrPair.A) code("#${rightConstVal.number.toInt()}") } return } - else if (left is DirectMemoryRead) { + else if (left is PtMemoryByte) { if(rightConstVal.number.toInt()!=0) { translateDirectMemReadExpressionToRegAorStack(left, false) code("#${rightConstVal.number.toInt()}") @@ -2155,7 +2072,7 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) } else { @@ -2166,7 +2083,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateByteGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateByteGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(sbcOperand: String) { out(""" sec @@ -2182,7 +2099,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number}") @@ -2195,7 +2112,7 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.BYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) } else { @@ -2206,7 +2123,7 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateUwordGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateUwordGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) { out(""" @@ -2224,7 +2141,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(left, RegisterOrPair.AY) code("#>${rightConstVal.number.toInt()}", "#<${rightConstVal.number.toInt()}") @@ -2237,7 +2154,7 @@ $repeatLabel lda $counterVar if(wordJumpForSimpleRightOperands(left, right, ::code)) return - if(right.isSimple) { + if(right.isSimple()) { assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(right, RegisterOrPair.AY) } else { @@ -2249,7 +2166,7 @@ $repeatLabel lda $counterVar return out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel") } - private fun translateWordGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateWordGreaterOrEqualJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(msbCpyOperand: String, lsbCmpOperand: String) { out(""" @@ -2267,7 +2184,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { return if(rightConstVal.number.toInt()!=0) { assignExpressionToRegister(left, RegisterOrPair.AY) code("#>${rightConstVal.number.toInt()}", "#<${rightConstVal.number.toInt()}") @@ -2283,7 +2200,7 @@ $repeatLabel lda $counterVar if(wordJumpForSimpleRightOperands(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.WORD, null) assignExpressionToRegister(left, RegisterOrPair.AY) } else { @@ -2295,7 +2212,7 @@ $repeatLabel lda $counterVar return out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel") } - private fun translateByteEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateByteEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(cmpOperand: String) { out(" cmp $cmpOperand | bne $jumpIfFalseLabel") } @@ -2306,14 +2223,14 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") else out(" bne $jumpIfFalseLabel") } - else if (left is DirectMemoryRead) { + else if (left is PtMemoryByte) { translateDirectMemReadExpressionToRegAorStack(left, false) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") @@ -2326,10 +2243,10 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) - } else if(right.isSimple) { + } else if(right.isSimple()) { assignExpressionToVariable(left, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(right, RegisterOrPair.A) } else { @@ -2340,7 +2257,7 @@ $repeatLabel lda $counterVar out(" cmp P8ZP_SCRATCH_B1 | bne $jumpIfFalseLabel") } - private fun translateByteNotEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateByteNotEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { fun code(cmpOperand: String) { out(" cmp $cmpOperand | beq $jumpIfFalseLabel") @@ -2352,14 +2269,14 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") else out(" beq $jumpIfFalseLabel") } - else if (left is DirectMemoryRead) { + else if (left is PtMemoryByte) { translateDirectMemReadExpressionToRegAorStack(left, false) return if(rightConstVal.number.toInt()!=0) code("#${rightConstVal.number.toInt()}") @@ -2372,10 +2289,10 @@ $repeatLabel lda $counterVar if(byteJumpForSimpleRightOperand(left, right, ::code)) return - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(left, RegisterOrPair.A) - } else if(right.isSimple) { + } else if(right.isSimple()) { assignExpressionToVariable(left, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) assignExpressionToRegister(right, RegisterOrPair.A) } else { @@ -2386,14 +2303,14 @@ $repeatLabel lda $counterVar return code("P8ZP_SCRATCH_B1") } - private fun translateWordEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateWordEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { if(rightConstVal!=null) { if(leftConstVal!=null) { if(rightConstVal!=leftConstVal) jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { val name = asmVariableName(left) if(rightConstVal.number!=0.0) { val rightNum = rightConstVal.number.toHex() @@ -2418,7 +2335,7 @@ $repeatLabel lda $counterVar } when (right) { - is NumericLiteral -> { + is PtNumber -> { assignExpressionToRegister(left, RegisterOrPair.AY) val number = right.number.toHex() out(""" @@ -2428,7 +2345,7 @@ $repeatLabel lda $counterVar bne $jumpIfFalseLabel """) } - is IdentifierReference -> { + is PtIdentifier -> { assignExpressionToRegister(left, RegisterOrPair.AY) out(""" cmp ${asmVariableName(right)} @@ -2437,7 +2354,7 @@ $repeatLabel lda $counterVar bne $jumpIfFalseLabel """) } - is AddressOf -> { + is PtAddressOf -> { assignExpressionToRegister(left, RegisterOrPair.AY) val name = asmSymbolName(right.identifier) out(""" @@ -2448,10 +2365,10 @@ $repeatLabel lda $counterVar """) } else -> { - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(left, RegisterOrPair.AY) - } else if(right.isSimple) { + } else if(right.isSimple()) { assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(right, RegisterOrPair.AY) } else { @@ -2470,7 +2387,7 @@ $repeatLabel lda $counterVar } - private fun translateWordNotEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateWordNotEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { if(rightConstVal!=null) { if(leftConstVal!=null) { @@ -2478,7 +2395,7 @@ $repeatLabel lda $counterVar jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { val name = asmVariableName(left) if(rightConstVal.number.toInt()!=0) { val number = rightConstVal.number.toHex() @@ -2504,7 +2421,7 @@ $repeatLabel lda $counterVar } when (right) { - is NumericLiteral -> { + is PtNumber -> { assignExpressionToRegister(left, RegisterOrPair.AY) val number = right.number.toHex() out(""" @@ -2514,7 +2431,7 @@ $repeatLabel lda $counterVar beq $jumpIfFalseLabel +""") } - is IdentifierReference -> { + is PtIdentifier -> { assignExpressionToRegister(left, RegisterOrPair.AY) out(""" cmp ${asmVariableName(right)} @@ -2523,7 +2440,7 @@ $repeatLabel lda $counterVar beq $jumpIfFalseLabel +""") } - is AddressOf -> { + is PtAddressOf -> { assignExpressionToRegister(left, RegisterOrPair.AY) val name = asmSymbolName(right.identifier) out(""" @@ -2534,10 +2451,10 @@ $repeatLabel lda $counterVar +""") } else -> { - if(left.isSimple) { + if(left.isSimple()) { assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(left, RegisterOrPair.AY) - } else if (right.isSimple) { + } else if (right.isSimple()) { assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null) assignExpressionToRegister(right, RegisterOrPair.AY) } else { @@ -2558,14 +2475,14 @@ $repeatLabel lda $counterVar } - private fun translateFloatEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateFloatEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { if(rightConstVal!=null) { if(leftConstVal!=null) { if(rightConstVal!=leftConstVal) jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { val name = asmVariableName(left) when(rightConstVal.number) { @@ -2601,10 +2518,10 @@ $repeatLabel lda $counterVar if(leftConstVal!=null && rightConstVal!=null) { throw AssemblyError("const-compare should have been optimized away") } - else if(leftConstVal!=null && right is IdentifierReference) { + else if(leftConstVal!=null && right is PtIdentifier) { throw AssemblyError("const-compare should have been optimized to have const as right operand") } - else if(left is IdentifierReference && rightConstVal!=null) { + else if(left is PtIdentifier && rightConstVal!=null) { val leftName = asmVariableName(left) val rightName = allocator.getFloatAsmConst(rightConstVal.number) out(""" @@ -2617,7 +2534,7 @@ $repeatLabel lda $counterVar jsr floats.vars_equal_f beq $jumpIfFalseLabel""") } - else if(left is IdentifierReference && right is IdentifierReference) { + else if(left is PtIdentifier && right is PtIdentifier) { val leftName = asmVariableName(left) val rightName = asmVariableName(right) out(""" @@ -2630,7 +2547,7 @@ $repeatLabel lda $counterVar jsr floats.vars_equal_f beq $jumpIfFalseLabel""") } else { - val subroutine = left.definingSubroutine!! + val subroutine = left.definingSub()!! subroutineExtra(subroutine).usedFloatEvalResultVar1 = true assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToRegister(left, RegisterOrPair.FAC1) @@ -2642,14 +2559,14 @@ $repeatLabel lda $counterVar } } - private fun translateFloatNotEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteral?, rightConstVal: NumericLiteral?, jumpIfFalseLabel: String) { + private fun translateFloatNotEqualsJump(left: PtExpression, right: PtExpression, leftConstVal: PtNumber?, rightConstVal: PtNumber?, jumpIfFalseLabel: String) { if(rightConstVal!=null) { if(leftConstVal!=null) { if(rightConstVal==leftConstVal) jmp(jumpIfFalseLabel) return } else { - if (left is IdentifierReference) { + if (left is PtIdentifier) { val name = asmVariableName(left) when(rightConstVal.number) { @@ -2686,10 +2603,10 @@ $repeatLabel lda $counterVar if(leftConstVal!=null && rightConstVal!=null) { throw AssemblyError("const-compare should have been optimized away") } - else if(leftConstVal!=null && right is IdentifierReference) { + else if(leftConstVal!=null && right is PtIdentifier) { throw AssemblyError("const-compare should have been optimized to have const as right operand") } - else if(left is IdentifierReference && rightConstVal!=null) { + else if(left is PtIdentifier && rightConstVal!=null) { val leftName = asmVariableName(left) val rightName = allocator.getFloatAsmConst(rightConstVal.number) out(""" @@ -2702,7 +2619,7 @@ $repeatLabel lda $counterVar jsr floats.vars_equal_f bne $jumpIfFalseLabel""") } - else if(left is IdentifierReference && right is IdentifierReference) { + else if(left is PtIdentifier && right is PtIdentifier) { val leftName = asmVariableName(left) val rightName = asmVariableName(right) out(""" @@ -2715,7 +2632,7 @@ $repeatLabel lda $counterVar jsr floats.vars_equal_f bne $jumpIfFalseLabel""") } else { - val subroutine = left.definingSubroutine!! + val subroutine = left.definingSub()!! subroutineExtra(subroutine).usedFloatEvalResultVar1 = true assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToRegister(left, RegisterOrPair.FAC1) @@ -2727,7 +2644,7 @@ $repeatLabel lda $counterVar } } - private fun translateStringEqualsJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) { + private fun translateStringEqualsJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { val leftNam = asmVariableName(left) val rightNam = asmVariableName(right) out(""" @@ -2742,7 +2659,7 @@ $repeatLabel lda $counterVar bne $jumpIfFalseLabel""") } - private fun translateStringNotEqualsJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) { + private fun translateStringNotEqualsJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { val leftNam = asmVariableName(left) val rightNam = asmVariableName(right) out(""" @@ -2757,7 +2674,7 @@ $repeatLabel lda $counterVar beq $jumpIfFalseLabel""") } - private fun translateStringLessJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) { + private fun translateStringLessJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { val leftNam = asmVariableName(left) val rightNam = asmVariableName(right) out(""" @@ -2771,7 +2688,7 @@ $repeatLabel lda $counterVar bpl $jumpIfFalseLabel""") } - private fun translateStringGreaterJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) { + private fun translateStringGreaterJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { val leftNam = asmVariableName(left) val rightNam = asmVariableName(right) out(""" @@ -2786,7 +2703,7 @@ $repeatLabel lda $counterVar bmi $jumpIfFalseLabel""") } - private fun translateStringLessOrEqualJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) { + private fun translateStringLessOrEqualJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { val leftNam = asmVariableName(left) val rightNam = asmVariableName(right) out(""" @@ -2802,7 +2719,7 @@ $repeatLabel lda $counterVar +""") } - private fun translateStringGreaterOrEqualJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) { + private fun translateStringGreaterOrEqualJump(left: PtIdentifier, right: PtIdentifier, jumpIfFalseLabel: String) { val leftNam = asmVariableName(left) val rightNam = asmVariableName(right) out(""" @@ -2818,10 +2735,10 @@ $repeatLabel lda $counterVar +""") } - internal fun translateDirectMemReadExpressionToRegAorStack(expr: DirectMemoryRead, pushResultOnEstack: Boolean) { + internal fun translateDirectMemReadExpressionToRegAorStack(expr: PtMemoryByte, pushResultOnEstack: Boolean) { fun assignViaExprEval() { - assignExpressionToVariable(expr.addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD, null) + assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.UWORD, null) if (isTargetCpu(CpuType.CPU65c02)) { if (pushResultOnEstack) { out(" lda (P8ZP_SCRATCH_W2) | dex | sta P8ESTACK_LO+1,x") @@ -2837,21 +2754,21 @@ $repeatLabel lda $counterVar } } - when(expr.addressExpression) { - is NumericLiteral -> { - val address = (expr.addressExpression as NumericLiteral).number.toInt() + when(expr.address) { + is PtNumber -> { + val address = (expr.address as PtNumber).number.toInt() out(" lda ${address.toHex()}") if(pushResultOnEstack) out(" sta P8ESTACK_LO,x | dex") } - is IdentifierReference -> { + is PtIdentifier -> { // the identifier is a pointer variable, so read the value from the address in it - loadByteFromPointerIntoA(expr.addressExpression as IdentifierReference) + loadByteFromPointerIntoA(expr.address as PtIdentifier) if(pushResultOnEstack) out(" sta P8ESTACK_LO,x | dex") } - is BinaryExpression -> { - if(tryOptimizedPointerAccessWithA(expr.addressExpression as BinaryExpression, false)) { + is PtBinaryExpression -> { + if(tryOptimizedPointerAccessWithA(expr.address as PtBinaryExpression, false)) { if(pushResultOnEstack) out(" sta P8ESTACK_LO,x | dex") } else { @@ -2862,21 +2779,21 @@ $repeatLabel lda $counterVar } } - private fun wordJumpForSimpleLeftOperand(left: Expression, right: Expression, code: (String, String)->Unit): Boolean { + private fun wordJumpForSimpleLeftOperand(left: PtExpression, right: PtExpression, code: (String, String)->Unit): Boolean { when (left) { - is NumericLiteral -> { + is PtNumber -> { assignExpressionToRegister(right, RegisterOrPair.AY) val number = left.number.toHex() code("#>$number", "#<$number") return true } - is AddressOf -> { + is PtAddressOf -> { assignExpressionToRegister(right, RegisterOrPair.AY) val name = asmSymbolName(left.identifier) code("#>$name", "#<$name") return true } - is IdentifierReference -> { + is PtIdentifier -> { assignExpressionToRegister(right, RegisterOrPair.AY) val varname = asmVariableName(left) code("$varname+1", varname) @@ -2886,22 +2803,22 @@ $repeatLabel lda $counterVar } } - private fun byteJumpForSimpleRightOperand(left: Expression, right: Expression, code: (String)->Unit): Boolean { - if(right is NumericLiteral) { + private fun byteJumpForSimpleRightOperand(left: PtExpression, right: PtExpression, code: (String)->Unit): Boolean { + if(right is PtNumber) { assignExpressionToRegister(left, RegisterOrPair.A) code("#${right.number.toHex()}") return true } - if(right is IdentifierReference) { + if(right is PtIdentifier) { assignExpressionToRegister(left, RegisterOrPair.A) code(asmVariableName(right)) return true } - var memread = right as? DirectMemoryRead - if(memread==null && right is TypecastExpression) - memread = right.expression as? DirectMemoryRead + var memread = right as? PtMemoryByte + if(memread==null && right is PtTypeCast) + memread = right.value as? PtMemoryByte if(memread!=null) { - val address = memread.addressExpression as? NumericLiteral + val address = memread.address as? PtNumber if(address!=null) { assignExpressionToRegister(left, RegisterOrPair.A) code(address.number.toHex()) @@ -2911,21 +2828,21 @@ $repeatLabel lda $counterVar return false } - private fun wordJumpForSimpleRightOperands(left: Expression, right: Expression, code: (String, String)->Unit): Boolean { + private fun wordJumpForSimpleRightOperands(left: PtExpression, right: PtExpression, code: (String, String)->Unit): Boolean { when (right) { - is NumericLiteral -> { + is PtNumber -> { assignExpressionToRegister(left, RegisterOrPair.AY) val number = right.number.toHex() code("#>$number", "#<$number") return true } - is AddressOf -> { + is PtAddressOf -> { assignExpressionToRegister(left, RegisterOrPair.AY) val name = asmSymbolName(right.identifier) code("#>$name", "#<$name") return true } - is IdentifierReference -> { + is PtIdentifier -> { assignExpressionToRegister(left, RegisterOrPair.AY) val varname = asmVariableName(right) code("$varname+1", varname) @@ -2935,11 +2852,11 @@ $repeatLabel lda $counterVar } } - internal fun popCpuStack(dt: DataType, target: VarDecl, scope: Subroutine?) { + internal fun popCpuStack(dt: DataType, target: PtVariable, scope: PtSub?) { // note: because A is pushed first so popped last, saving A is often not required here. val parameter = target.subroutineParameter if(parameter!=null) { - val sub = parameter.definingSubroutine!! + val sub = parameter.definingSub()!! require(sub.isAsmSubroutine) { "push/pop arg passing only supported on asmsubs ${sub.position}" } val shouldKeepA = sub.asmParameterRegisters.any { it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.AY } val reg = sub.asmParameterRegisters[sub.parameters.indexOf(parameter)] @@ -3012,7 +2929,7 @@ $repeatLabel lda $counterVar } } } else { - val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, this, target.datatype, scope, variableAsmName = asmVariableName(target.scopedName)) + val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, this, target.type, scope, variableAsmName = asmVariableName(target.scopedName)) if (dt in ByteDatatypes) { out(" pla") assignRegister(RegisterOrPair.A, tgt) @@ -3034,8 +2951,8 @@ $repeatLabel lda $counterVar } } - internal fun pushCpuStack(dt: DataType, value: Expression) { - val signed = value.inferType(program).oneOf(DataType.BYTE, DataType.WORD) + internal fun pushCpuStack(dt: DataType, value: PtExpression) { + val signed = value.type.oneOf(DataType.BYTE, DataType.WORD) if(dt in ByteDatatypes) { assignExpressionToRegister(value, RegisterOrPair.A, signed) out(" pha") @@ -3050,12 +2967,12 @@ $repeatLabel lda $counterVar } } - internal fun needAsaveForExpr(arg: Expression): Boolean = - arg !is NumericLiteral && arg !is IdentifierReference && (arg !is DirectMemoryRead || !arg.isSimple) + internal fun needAsaveForExpr(arg: PtExpression): Boolean = + arg !is PtNumber && arg !is PtIdentifier && (arg !is PtMemoryByte || !arg.isSimple()) - private val subroutineExtrasCache = mutableMapOf() + private val subroutineExtrasCache = mutableMapOf() - internal fun subroutineExtra(sub: Subroutine): SubroutineExtraAsmInfo { + internal fun subroutineExtra(sub: IPtSubroutine): SubroutineExtraAsmInfo { var extra = subroutineExtrasCache[sub] return if(extra==null) { extra = SubroutineExtraAsmInfo() @@ -3065,8 +2982,15 @@ $repeatLabel lda $counterVar else extra } -} + private var generatedLabelSequenceNumber: Int = 0 + + internal fun makeLabel(postfix: String): String { + generatedLabelSequenceNumber++ + return "prog8_label_asm_${generatedLabelSequenceNumber}_$postfix" + } + +} /** * Contains various attributes that influence the assembly code generator. diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt index 41cd9a00e..e50c17c6f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt @@ -1,16 +1,13 @@ package prog8.codegen.cpu6502 -import prog8.ast.Program -import prog8.ast.expressions.NumericLiteral -import prog8.ast.statements.VarDecl -import prog8.ast.statements.VarDeclType +import prog8.code.ast.PtProgram import prog8.code.core.IMachineDefinition // note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations -internal fun optimizeAssembly(lines: MutableList, machine: IMachineDefinition, program: Program): Int { +internal fun optimizeAssembly(lines: MutableList, machine: IMachineDefinition, program: PtProgram): Int { var numberOfOptimizations = 0 @@ -129,7 +126,7 @@ private fun optimizeUselessStackByteWrites(linesByFour: List>>, machine: IMachineDefinition, program: Program): List { +private fun optimizeSameAssignments(linesByFourteen: List>>, machine: IMachineDefinition, program: PtProgram): List { // Optimize sequential assignments of the same value to various targets (bytes, words, floats) // the float one is the one that requires 2*7=14 lines of code to check... @@ -327,7 +324,7 @@ private fun optimizeSameAssignments(linesByFourteen: List>>, machine: IMachineDefinition, program: Program): List { +private fun optimizeSamePointerIndexing(linesByFourteen: List>>, machine: IMachineDefinition, program: PtProgram): List { // Optimize same pointer indexing where for instance we load and store to the same ptr index in Y // if Y isn't modified in between we can omit the second LDY: @@ -369,7 +366,7 @@ private fun optimizeSamePointerIndexing(linesByFourteen: List>>, machine: IMachineDefinition, program: Program): List { +private fun optimizeStoreLoadSame(linesByFour: List>>, machine: IMachineDefinition, program: PtProgram): List { // sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can OFTEN be eliminated val mods = mutableListOf() for (lines in linesByFour) { @@ -439,7 +436,7 @@ private fun optimizeStoreLoadSame(linesByFour: List>>, private val identifierRegex = Regex("""^([a-zA-Z_$][a-zA-Z\d_\.$]*)""") -private fun getAddressArg(line: String, program: Program): UInt? { +private fun getAddressArg(line: String, program: PtProgram): UInt? { val loadArg = line.trimStart().substring(3).trim() return when { loadArg.startsWith('$') -> loadArg.substring(1).toUIntOrNull(16) @@ -450,15 +447,7 @@ private fun getAddressArg(line: String, program: Program): UInt? { val identMatch = identifierRegex.find(loadArg) if(identMatch!=null) { val identifier = identMatch.value - val decl = program.toplevelModule.lookup(identifier.split('.')) as? VarDecl - if(decl!=null) { - when(decl.type){ - VarDeclType.VAR -> null - VarDeclType.CONST, - VarDeclType.MEMORY -> (decl.value as NumericLiteral).number.toUInt() - } - } - else null + TODO("lookup symbol's value $identifier") } else null } else -> loadArg.substring(1).toUIntOrNull() diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt index 8f5d0f54f..2860955fc 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt @@ -1,15 +1,12 @@ package prog8.codegen.cpu6502 -import prog8.ast.expressions.ArrayIndexedExpression -import prog8.ast.expressions.BuiltinFunctionCall -import prog8.ast.expressions.Expression -import prog8.ast.statements.Subroutine +import prog8.code.ast.* import prog8.code.core.Cx16VirtualRegisters import prog8.code.core.RegisterOrPair import prog8.code.core.RegisterOrStatusflag -fun asmsub6502ArgsEvalOrder(sub: Subroutine): List { +fun asmsub6502ArgsEvalOrder(sub: PtAsmSub): List { val order = mutableListOf() // order is: // 1) cx16 virtual word registers, @@ -17,7 +14,7 @@ fun asmsub6502ArgsEvalOrder(sub: Subroutine): List { // 3) single CPU registers (X last), except A, // 4) CPU Carry status flag // 5) the A register itself last (so everything before it can use the accumulator without having to save its value) - val args = sub.parameters.zip(sub.asmParameterRegisters).withIndex() + val args = sub.parameters.withIndex() val (cx16regs, args2) = args.partition { it.value.second.registerOrPair in Cx16VirtualRegisters } val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY) val (pairedRegs , args3) = args2.partition { it.value.second.registerOrPair in pairedRegisters } @@ -37,23 +34,25 @@ fun asmsub6502ArgsEvalOrder(sub: Subroutine): List { return order } -fun asmsub6502ArgsHaveRegisterClobberRisk(args: List, - paramRegisters: List): Boolean { - fun isClobberRisk(expr: Expression): Boolean { +fun asmsub6502ArgsHaveRegisterClobberRisk( + args: List, + paramRegisters: List> +): Boolean { + fun isClobberRisk(expr: PtExpression): Boolean { when (expr) { - is ArrayIndexedExpression -> { + is PtArrayIndexer -> { return paramRegisters.any { - it.registerOrPair in listOf(RegisterOrPair.Y, RegisterOrPair.AY, RegisterOrPair.XY) + it.second.registerOrPair in listOf(RegisterOrPair.Y, RegisterOrPair.AY, RegisterOrPair.XY) } } - is BuiltinFunctionCall -> { + is PtBuiltinFunctionCall -> { if (expr.name == "lsb" || expr.name == "msb") return isClobberRisk(expr.args[0]) if (expr.name == "mkword") return isClobberRisk(expr.args[0]) && isClobberRisk(expr.args[1]) - return !expr.isSimple + return !expr.isSimple() } - else -> return !expr.isSimple + else -> return !expr.isSimple() } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt index 5c48f045c..54877f8dc 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt @@ -3,7 +3,6 @@ package prog8.codegen.cpu6502 import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Result import com.github.michaelbull.result.mapError -import prog8.ast.generatedLabelPrefix import prog8.code.core.* import java.io.File import java.nio.file.Path @@ -104,7 +103,7 @@ internal class AssemblyProgram( } private fun removeGeneratedLabelsFromMonlist() { - val pattern = Regex("""al (\w+) \S+${generatedLabelPrefix}.+?""") + val pattern = Regex("""al (\w+) \S+prog8_label_.+?""") val lines = viceMonListFile.toFile().readLines() viceMonListFile.toFile().outputStream().bufferedWriter().use { for (line in lines) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 12ab41db1..4542f3546 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -1,49 +1,39 @@ package prog8.codegen.cpu6502 -import prog8.ast.IFunctionCall -import prog8.ast.Node -import prog8.ast.Program -import prog8.ast.expressions.* -import prog8.ast.statements.ArrayIndex -import prog8.ast.statements.BuiltinFunctionCallStatement -import prog8.ast.statements.Subroutine +import prog8.code.ast.* import prog8.code.core.* import prog8.codegen.cpu6502.assignment.* -import prog8.compiler.BuiltinFunctions -import prog8.compiler.FSignature -internal class BuiltinFunctionsAsmGen(private val program: Program, +internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) { - internal fun translateFunctioncallExpression(fcall: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { - val func = BuiltinFunctions.getValue(fcall.target.nameInSource.single()) - translateFunctioncall(fcall, func, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister) + internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + translateFunctioncall(fcall, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister) } - internal fun translateFunctioncallStatement(fcall: BuiltinFunctionCallStatement) { - val func = BuiltinFunctions.getValue(fcall.name) - translateFunctioncall(fcall, func, discardResult = true, resultToStack = false, resultRegister = null) + internal fun translateFunctioncallStatement(fcall: PtBuiltinFunctionCall) { + translateFunctioncall(fcall, discardResult = true, resultToStack = false, resultRegister = null) } - private fun translateFunctioncall(fcall: IFunctionCall, func: FSignature, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) { - if (discardResult && func.pure) + private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + if (discardResult && fcall.hasNoSideEffects) return // can just ignore the whole function call altogether if(discardResult && resultToStack) throw AssemblyError("cannot both discard the result AND put it onto stack") - val sscope = (fcall as Node).definingSubroutine + val sscope = fcall.definingSub()!! - when (func.name) { + when (fcall.name) { "msb" -> funcMsb(fcall, resultToStack, resultRegister) "lsb" -> funcLsb(fcall, resultToStack, resultRegister) "mkword" -> funcMkword(fcall, resultToStack, resultRegister) - "abs" -> funcAbs(fcall, func, resultToStack, resultRegister, sscope) - "any", "all" -> funcAnyAll(fcall, func, resultToStack, resultRegister, sscope) - "sgn" -> funcSgn(fcall, func, resultToStack, resultRegister, sscope) - "sqrt16" -> funcSqrt16(fcall, func, resultToStack, resultRegister, sscope) + "abs" -> funcAbs(fcall, resultToStack, resultRegister, sscope) + "any", "all" -> funcAnyAll(fcall, resultToStack, resultRegister, sscope) + "sgn" -> funcSgn(fcall, resultToStack, resultRegister, sscope) + "sqrt16" -> funcSqrt16(fcall, resultToStack, resultRegister, sscope) "rol" -> funcRol(fcall) "rol2" -> funcRol2(fcall) "ror" -> funcRor(fcall) @@ -59,16 +49,16 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, "push" -> asmgen.pushCpuStack(DataType.UBYTE, fcall.args[0]) "pushw" -> asmgen.pushCpuStack(DataType.UWORD, fcall.args[0]) "pop" -> { - require(fcall.args[0] is IdentifierReference) { - "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${(fcall as Node).position}" + require(fcall.args[0] is PtIdentifier) { + "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}" } - asmgen.popCpuStack(DataType.UBYTE, (fcall.args[0] as IdentifierReference).targetVarDecl(program)!!, (fcall as Node).definingSubroutine) + asmgen.popCpuStack(DataType.UBYTE, (fcall.args[0] as PtIdentifier).targetVarDecl(program)!!, fcall.definingSub()) } "popw" -> { - require(fcall.args[0] is IdentifierReference) { - "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${(fcall as Node).position}" + require(fcall.args[0] is PtIdentifier) { + "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}" } - asmgen.popCpuStack(DataType.UWORD, (fcall.args[0] as IdentifierReference).targetVarDecl(program)!!, (fcall as Node).definingSubroutine) + asmgen.popCpuStack(DataType.UWORD, (fcall.args[0] as PtIdentifier).targetVarDecl(program)!!, fcall.definingSub()) } "rsave" -> funcRsave() "rsavex" -> funcRsaveX() @@ -77,7 +67,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, "cmp" -> funcCmp(fcall) "callfar" -> funcCallFar(fcall) "callrom" -> funcCallRom(fcall) - else -> throw AssemblyError("missing asmgen for builtin func ${func.name}") + else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}") } } @@ -132,29 +122,29 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, asmgen.out(" sta P8ZP_SCRATCH_B1 | pla | tax | lda P8ZP_SCRATCH_B1") } - private fun funcCallFar(fcall: IFunctionCall) { + private fun funcCallFar(fcall: PtBuiltinFunctionCall) { if(asmgen.options.compTarget.name != "cx16") throw AssemblyError("callfar only works on cx16 target at this time") - val bank = fcall.args[0].constValue(program)?.number?.toInt() - val address = fcall.args[1].constValue(program)?.number?.toInt() ?: 0 + val bank = fcall.args[0].asConstInteger() + val address = fcall.args[1].asConstInteger() ?: 0 val argAddrArg = fcall.args[2] if(bank==null) throw AssemblyError("callfar (jsrfar) bank has to be a constant") - if(fcall.args[1].constValue(program) == null) { + if(fcall.args[1] !is PtNumber) { assignAsmGen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AY, false) asmgen.out(" sta (+)+0 | sty (+)+1 ; store jsrfar address word") } - if(argAddrArg.constValue(program)?.number == 0.0) { + if(argAddrArg.asConstInteger() == 0) { asmgen.out(""" jsr cx16.jsrfar + .word ${address.toHex()} .byte ${bank.toHex()}""") } else { when(argAddrArg) { - is AddressOf -> { - if(argAddrArg.identifier.targetVarDecl(program)?.datatype != DataType.UBYTE) + is PtAddressOf -> { + if(argAddrArg.identifier.type != DataType.UBYTE) throw AssemblyError("callfar done with 'arg' pointer to variable that's not UBYTE") asmgen.out(""" lda ${asmgen.asmVariableName(argAddrArg.identifier)} @@ -163,7 +153,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, .byte ${bank.toHex()} sta ${asmgen.asmVariableName(argAddrArg.identifier)}""") } - is NumericLiteral -> { + is PtNumber -> { asmgen.out(""" lda ${argAddrArg.number.toHex()} jsr cx16.jsrfar @@ -176,12 +166,12 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcCallRom(fcall: IFunctionCall) { + private fun funcCallRom(fcall: PtBuiltinFunctionCall) { if(asmgen.options.compTarget.name != "cx16") throw AssemblyError("callrom only works on cx16 target at this time") - val bank = fcall.args[0].constValue(program)?.number?.toInt() - val address = fcall.args[1].constValue(program)?.number?.toInt() + val bank = fcall.args[0].asConstInteger() + val address = fcall.args[1].asConstInteger() if(bank==null || address==null) throw AssemblyError("callrom requires constant arguments") @@ -191,7 +181,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, throw AssemblyError("callrom bank must be <32") val argAddrArg = fcall.args[2] - if(argAddrArg.constValue(program)?.number == 0.0) { + if(argAddrArg.asConstInteger() == 0) { asmgen.out(""" lda $01 pha @@ -202,8 +192,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, sta $01""") } else { when(argAddrArg) { - is AddressOf -> { - if(argAddrArg.identifier.targetVarDecl(program)?.datatype != DataType.UBYTE) + is PtAddressOf -> { + if(argAddrArg.identifier.type != DataType.UBYTE) throw AssemblyError("callrom done with 'arg' pointer to variable that's not UBYTE") asmgen.out(""" lda $01 @@ -216,7 +206,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, pla sta $01""") } - is NumericLiteral -> { + is PtNumber -> { asmgen.out(""" lda $01 pha @@ -233,46 +223,44 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcCmp(fcall: IFunctionCall) { + private fun funcCmp(fcall: PtBuiltinFunctionCall) { val arg1 = fcall.args[0] val arg2 = fcall.args[1] - val dt1 = arg1.inferType(program).getOrElse { throw AssemblyError("unknown dt") } - val dt2 = arg2.inferType(program).getOrElse { throw AssemblyError("unknown dt") } - if(dt1 in ByteDatatypes) { - if(dt2 in ByteDatatypes) { + if(arg1.type in ByteDatatypes) { + if(arg2.type in ByteDatatypes) { when (arg2) { - is IdentifierReference -> { + is PtIdentifier -> { asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A) asmgen.out(" cmp ${asmgen.asmVariableName(arg2)}") } - is NumericLiteral -> { + is PtNumber -> { asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A) asmgen.out(" cmp #${arg2.number.toInt()}") } - is DirectMemoryRead -> { - if(arg2.addressExpression is NumericLiteral) { + is PtMemoryByte -> { + if(arg2.address is PtNumber) { asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A) - asmgen.out(" cmp ${arg2.addressExpression.constValue(program)!!.number.toHex()}") + asmgen.out(" cmp ${arg2.address.asConstInteger()!!.toHex()}") } else { - if(arg1.isSimple) { - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine) + if(arg1.isSimple()) { + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingSub()) asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A) asmgen.out(" cmp P8ZP_SCRATCH_B1") } else { asmgen.pushCpuStack(DataType.UBYTE, arg1) - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingSub()) asmgen.out(" pla | cmp P8ZP_SCRATCH_B1") } } } else -> { - if(arg1.isSimple) { - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine) + if(arg1.isSimple()) { + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingSub()) asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A) asmgen.out(" cmp P8ZP_SCRATCH_B1") } else { asmgen.pushCpuStack(DataType.UBYTE, arg1) - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, fcall.definingSub()) asmgen.out(" pla | cmp P8ZP_SCRATCH_B1") } } @@ -280,10 +268,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } else throw AssemblyError("args for cmp() should have same dt") } else { - // dt1 is a word - if(dt2 in WordDatatypes) { + // arg1 is a word + if(arg2.type in WordDatatypes) { when (arg2) { - is IdentifierReference -> { + is PtIdentifier -> { asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY) asmgen.out(""" cpy ${asmgen.asmVariableName(arg2)}+1 @@ -291,7 +279,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, cmp ${asmgen.asmVariableName(arg2)} +""") } - is NumericLiteral -> { + is PtNumber -> { asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY) asmgen.out(""" cpy #>${arg2.number.toInt()} @@ -300,8 +288,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, +""") } else -> { - if(arg1.isSimple) { - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, (fcall as Node).definingSubroutine) + if(arg1.isSimple()) { + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, fcall.definingSub()) asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY) asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 @@ -310,7 +298,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, +""") } else { asmgen.pushCpuStack(DataType.UWORD, arg1) - asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, (fcall as Node).definingSubroutine) + asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, fcall.definingSub()) asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.restoreRegisterStack(CpuRegister.A, false) asmgen.out(""" @@ -326,14 +314,15 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcMemory(fcall: IFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) { - if(discardResult || fcall !is BuiltinFunctionCall) + private fun funcMemory(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + if(discardResult || fcall !is PtBuiltinFunctionCall) throw AssemblyError("should not discard result of memory allocation at $fcall") - val name = (fcall.args[0] as StringLiteral).value + val name = (fcall.args[0] as PtString).value require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name ${fcall.position}"} - val slabname = IdentifierReference(listOf("prog8_slabs", "prog8_memoryslab_$name"), fcall.position) - slabname.linkParents(fcall) - val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = AddressOf(slabname, fcall.position)) + val slabname = PtIdentifier("prog8_slabs.prog8_memoryslab_$name", DataType.UWORD, fcall.position) + val addressOf = PtAddressOf(fcall.position) + addressOf.add(slabname) + val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = addressOf) val target = if(resultToStack) AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, null) @@ -343,7 +332,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, asmgen.translateNormalAssignment(assign) } - private fun funcSqrt16(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { + private fun funcSqrt16(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: PtSub?) { translateArguments(fcall.args, func, scope) if(resultToStack) asmgen.out(" jsr prog8_lib.func_sqrt16_stack") @@ -353,13 +342,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcReverse(fcall: IFunctionCall) { + private fun funcReverse(fcall: PtBuiltinFunctionCall) { val variable = fcall.args.single() - if (variable is IdentifierReference) { + if (variable is PtIdentifier) { val decl = variable.targetVarDecl(program)!! val varName = asmgen.asmVariableName(variable) - val numElements = decl.arraysize!!.constIndex() - when (decl.datatype) { + val numElements = decl.arraySize!! + when (decl.type) { DataType.ARRAY_UB, DataType.ARRAY_B -> { asmgen.out(""" lda #<$varName @@ -392,13 +381,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcSort(fcall: IFunctionCall) { + private fun funcSort(fcall: PtBuiltinFunctionCall) { val variable = fcall.args.single() - if (variable is IdentifierReference) { + if (variable is PtIdentifier) { val decl = variable.targetVarDecl(program)!! val varName = asmgen.asmVariableName(variable) - val numElements = decl.arraysize!!.constIndex() - when (decl.datatype) { + val numElements = decl.arraySize!! + when (decl.type) { DataType.ARRAY_UB, DataType.ARRAY_B -> { asmgen.out(""" lda #<$varName @@ -406,7 +395,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 lda #$numElements""") - asmgen.out(if (decl.datatype == DataType.ARRAY_UB) " jsr prog8_lib.func_sort_ub" else " jsr prog8_lib.func_sort_b") + asmgen.out(if (decl.type == DataType.ARRAY_UB) " jsr prog8_lib.func_sort_ub" else " jsr prog8_lib.func_sort_b") } DataType.ARRAY_UW, DataType.ARRAY_W -> { asmgen.out(""" @@ -415,7 +404,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 lda #$numElements""") - asmgen.out(if (decl.datatype == DataType.ARRAY_UW) " jsr prog8_lib.func_sort_uw" else " jsr prog8_lib.func_sort_w") + asmgen.out(if (decl.type == DataType.ARRAY_UW) " jsr prog8_lib.func_sort_uw" else " jsr prog8_lib.func_sort_w") } DataType.ARRAY_F -> throw AssemblyError("sorting of floating point array is not supported") else -> throw AssemblyError("weird type") @@ -424,26 +413,25 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, throw AssemblyError("weird type") } - private fun funcRor2(fcall: IFunctionCall) { + private fun funcRor2(fcall: PtBuiltinFunctionCall) { val what = fcall.args.single() - val dt = what.inferType(program) - when (dt.getOr(DataType.UNDEFINED)) { + when (what.type) { DataType.UBYTE -> { when (what) { - is ArrayIndexedExpression -> { - translateRolRorArrayArgs(what.arrayvar, what.indexer, "ror2", 'b') + is PtArrayIndexer -> { + translateRolRorArrayArgs(what.variable, what, "ror2", 'b') asmgen.out(" jsr prog8_lib.ror2_array_ub") } - is DirectMemoryRead -> { - if (what.addressExpression is NumericLiteral) { - val number = (what.addressExpression as NumericLiteral).number + is PtMemoryByte -> { + if (what.address is PtNumber) { + val number = (what.address as PtNumber).number asmgen.out(" lda ${number.toHex()} | lsr a | bcc + | ora #\$80 |+ | sta ${number.toHex()}") } else { - asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY) + asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY) asmgen.out(" jsr prog8_lib.ror2_mem_ub") } } - is IdentifierReference -> { + is PtIdentifier -> { val variable = asmgen.asmVariableName(what) asmgen.out(" lda $variable | lsr a | bcc + | ora #\$80 |+ | sta $variable") } @@ -452,11 +440,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } DataType.UWORD -> { when (what) { - is ArrayIndexedExpression -> { - translateRolRorArrayArgs(what.arrayvar, what.indexer, "ror2", 'w') + is PtArrayIndexer -> { + translateRolRorArrayArgs(what.variable, what, "ror2", 'w') asmgen.out(" jsr prog8_lib.ror2_array_uw") } - is IdentifierReference -> { + is PtIdentifier -> { val variable = asmgen.asmVariableName(what) asmgen.out(" lsr $variable+1 | ror $variable | bcc + | lda $variable+1 | ora #\$80 | sta $variable+1 |+ ") } @@ -467,26 +455,25 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcRor(fcall: IFunctionCall) { + private fun funcRor(fcall: PtBuiltinFunctionCall) { val what = fcall.args.single() - val dt = what.inferType(program) - when (dt.getOr(DataType.UNDEFINED)) { + when (what.type) { DataType.UBYTE -> { when (what) { - is ArrayIndexedExpression -> { - translateRolRorArrayArgs(what.arrayvar, what.indexer, "ror", 'b') + is PtArrayIndexer -> { + translateRolRorArrayArgs(what.variable, what, "ror", 'b') asmgen.out(" jsr prog8_lib.ror_array_ub") } - is DirectMemoryRead -> { - if (what.addressExpression is NumericLiteral) { - val number = (what.addressExpression as NumericLiteral).number + is PtMemoryByte -> { + if (what.address is PtNumber) { + val number = (what.address as PtNumber).number asmgen.out(" ror ${number.toHex()}") } else { - val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression) + val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address) if(ptrAndIndex!=null) { - asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) - asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) asmgen.restoreRegisterLocal(CpuRegister.X) asmgen.out(""" @@ -495,7 +482,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, + ror ${'$'}ffff,x ; modified""") asmgen.restoreRegisterLocal(CpuRegister.X) } else { - asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY) + asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY) asmgen.out(""" sta (+) + 1 sty (+) + 2 @@ -503,7 +490,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } } - is IdentifierReference -> { + is PtIdentifier -> { val variable = asmgen.asmVariableName(what) asmgen.out(" ror $variable") } @@ -512,11 +499,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } DataType.UWORD -> { when (what) { - is ArrayIndexedExpression -> { - translateRolRorArrayArgs(what.arrayvar, what.indexer, "ror", 'w') + is PtArrayIndexer -> { + translateRolRorArrayArgs(what.variable, what, "ror", 'w') asmgen.out(" jsr prog8_lib.ror_array_uw") } - is IdentifierReference -> { + is PtIdentifier -> { val variable = asmgen.asmVariableName(what) asmgen.out(" ror $variable+1 | ror $variable") } @@ -527,26 +514,25 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcRol2(fcall: IFunctionCall) { + private fun funcRol2(fcall: PtBuiltinFunctionCall) { val what = fcall.args.single() - val dt = what.inferType(program) - when (dt.getOr(DataType.UNDEFINED)) { + when (what.type) { DataType.UBYTE -> { when (what) { - is ArrayIndexedExpression -> { - translateRolRorArrayArgs(what.arrayvar, what.indexer, "rol2", 'b') + is PtArrayIndexer -> { + translateRolRorArrayArgs(what.variable, what, "rol2", 'b') asmgen.out(" jsr prog8_lib.rol2_array_ub") } - is DirectMemoryRead -> { - if (what.addressExpression is NumericLiteral) { - val number = (what.addressExpression as NumericLiteral).number + is PtMemoryByte -> { + if (what.address is PtNumber) { + val number = (what.address as PtNumber).number asmgen.out(" lda ${number.toHex()} | cmp #\$80 | rol a | sta ${number.toHex()}") } else { - asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY) + asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY) asmgen.out(" jsr prog8_lib.rol2_mem_ub") } } - is IdentifierReference -> { + is PtIdentifier -> { val variable = asmgen.asmVariableName(what) asmgen.out(" lda $variable | cmp #\$80 | rol a | sta $variable") } @@ -555,11 +541,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } DataType.UWORD -> { when (what) { - is ArrayIndexedExpression -> { - translateRolRorArrayArgs(what.arrayvar, what.indexer, "rol2", 'w') + is PtArrayIndexer -> { + translateRolRorArrayArgs(what.variable, what, "rol2", 'w') asmgen.out(" jsr prog8_lib.rol2_array_uw") } - is IdentifierReference -> { + is PtIdentifier -> { val variable = asmgen.asmVariableName(what) asmgen.out(" asl $variable | rol $variable+1 | bcc + | inc $variable |+ ") } @@ -570,26 +556,25 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcRol(fcall: IFunctionCall) { + private fun funcRol(fcall: PtBuiltinFunctionCall) { val what = fcall.args.single() - val dt = what.inferType(program) - when (dt.getOr(DataType.UNDEFINED)) { + when (what.type) { DataType.UBYTE -> { when (what) { - is ArrayIndexedExpression -> { - translateRolRorArrayArgs(what.arrayvar, what.indexer, "rol", 'b') + is PtArrayIndexer -> { + translateRolRorArrayArgs(what.variable, what, "rol", 'b') asmgen.out(" jsr prog8_lib.rol_array_ub") } - is DirectMemoryRead -> { - if (what.addressExpression is NumericLiteral) { - val number = (what.addressExpression as NumericLiteral).number + is PtMemoryByte -> { + if (what.address is PtNumber) { + val number = (what.address as PtNumber).number asmgen.out(" rol ${number.toHex()}") } else { - val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression) + val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address) if(ptrAndIndex!=null) { - asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) - asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) asmgen.restoreRegisterLocal(CpuRegister.X) asmgen.out(""" @@ -598,7 +583,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, + rol ${'$'}ffff,x ; modified""") asmgen.restoreRegisterLocal(CpuRegister.X) } else { - asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY) + asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY) asmgen.out(""" sta (+) + 1 sty (+) + 2 @@ -606,7 +591,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } } - is IdentifierReference -> { + is PtIdentifier -> { val variable = asmgen.asmVariableName(what) asmgen.out(" rol $variable") } @@ -615,11 +600,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } DataType.UWORD -> { when (what) { - is ArrayIndexedExpression -> { - translateRolRorArrayArgs(what.arrayvar, what.indexer, "rol", 'w') + is PtArrayIndexer -> { + translateRolRorArrayArgs(what.variable, what, "rol", 'w') asmgen.out(" jsr prog8_lib.rol_array_uw") } - is IdentifierReference -> { + is PtIdentifier -> { val variable = asmgen.asmVariableName(what) asmgen.out(" rol $variable | rol $variable+1") } @@ -630,22 +615,24 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun translateRolRorArrayArgs(arrayvar: IdentifierReference, indexer: ArrayIndex, operation: String, dt: Char) { - if(arrayvar.targetVarDecl(program)!!.datatype==DataType.UWORD) { + private fun translateRolRorArrayArgs(arrayvar: PtIdentifier, indexer: PtArrayIndexer, operation: String, dt: Char) { + if(arrayvar.type==DataType.UWORD) { if(dt!='b') throw AssemblyError("non-array var indexing requires bytes dt") asmgen.assignExpressionToVariable(arrayvar, "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD, null) } else { - asmgen.assignExpressionToVariable(AddressOf(arrayvar, arrayvar.position), "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD, null) + val addressOf = PtAddressOf(arrayvar.position) + addressOf.add(arrayvar) + asmgen.assignExpressionToVariable(addressOf, "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD, null) } - asmgen.assignExpressionToVariable(indexer.indexExpr, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE, null) + asmgen.assignExpressionToVariable(indexer.index, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE, null) } - private fun funcSgn(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { + private fun funcSgn(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: PtSub?) { translateArguments(fcall.args, func, scope) - val dt = fcall.args.single().inferType(program) + val dt = fcall.args.single().type if(resultToStack) { - when (dt.getOr(DataType.UNDEFINED)) { + when (dt) { DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_stack") DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_stack") DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_stack") @@ -654,7 +641,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, else -> throw AssemblyError("weird type $dt") } } else { - when (dt.getOr(DataType.UNDEFINED)) { + when (dt) { DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A") DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A") DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A") @@ -666,30 +653,30 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcAnyAll(fcall: IFunctionCall, function: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { + private fun funcAnyAll(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: PtSub?) { outputAddressAndLenghtOfArray(fcall.args[0]) - val dt = fcall.args.single().inferType(program) + val dt = fcall.args.single().type if(resultToStack) { - when (dt.getOr(DataType.UNDEFINED)) { - DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_stack") - DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_stack") - DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_stack") + when (dt) { + DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_b_stack") + DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_w_stack") + DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${fcall.name}_f_stack") else -> throw AssemblyError("weird type $dt") } } else { - when (dt.getOr(DataType.UNDEFINED)) { - DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_into_A | ldy #0") - DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_into_A | ldy #0") - DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_into_A | ldy #0") + when (dt) { + DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_b_into_A | ldy #0") + DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${fcall.name}_w_into_A | ldy #0") + DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${fcall.name}_f_into_A | ldy #0") else -> throw AssemblyError("weird type $dt") } assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, asmgen), CpuRegister.A) } } - private fun funcAbs(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { + private fun funcAbs(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: PtSub?) { translateArguments(fcall.args, func, scope) - val dt = fcall.args.single().inferType(program).getOr(DataType.UNDEFINED) + val dt = fcall.args.single().type if(resultToStack) { when (dt) { DataType.UBYTE -> asmgen.out(" ldy #0") @@ -710,19 +697,19 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcPokeW(fcall: IFunctionCall) { + private fun funcPokeW(fcall: PtBuiltinFunctionCall) { when(val addrExpr = fcall.args[0]) { - is NumericLiteral -> { + is PtNumber -> { asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AY) val addr = addrExpr.number.toHex() asmgen.out(" sta $addr | sty ${addr}+1") return } - is IdentifierReference -> { + is PtIdentifier -> { val varname = asmgen.asmVariableName(addrExpr) if(asmgen.isZpVar(addrExpr)) { // pointervar is already in the zero page, no need to copy - asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX) if (asmgen.isTargetCpu(CpuType.CPU65c02)) { asmgen.out(""" @@ -742,14 +729,14 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, return } } - is BinaryExpression -> { - if(addrExpr.operator=="+" && addrExpr.left is IdentifierReference && addrExpr.right is NumericLiteral) { - val varname = asmgen.asmVariableName(addrExpr.left as IdentifierReference) - if(asmgen.isZpVar(addrExpr.left as IdentifierReference)) { + is PtBinaryExpression -> { + if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier && addrExpr.right is PtNumber) { + val varname = asmgen.asmVariableName(addrExpr.left as PtIdentifier) + if(asmgen.isZpVar(addrExpr.left as PtIdentifier)) { // pointervar is already in the zero page, no need to copy - asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingSub()!!) asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX) - val index = (addrExpr.right as NumericLiteral).number.toHex() + val index = (addrExpr.right as PtNumber).number.toHex() asmgen.out(""" ldy #$index sta ($varname),y @@ -769,13 +756,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, asmgen.out(" jsr prog8_lib.func_pokew") } - private fun funcPeekW(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcPeekW(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { when(val addrExpr = fcall.args[0]) { - is NumericLiteral -> { + is PtNumber -> { val addr = addrExpr.number.toHex() asmgen.out(" lda $addr | ldy ${addr}+1") } - is IdentifierReference -> { + is PtIdentifier -> { val varname = asmgen.asmVariableName(addrExpr) if(asmgen.isZpVar(addrExpr)) { // pointervar is already in the zero page, no need to copy @@ -800,12 +787,12 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, asmgen.out(" jsr prog8_lib.func_peekw") } } - is BinaryExpression -> { - if(addrExpr.operator=="+" && addrExpr.left is IdentifierReference && addrExpr.right is NumericLiteral) { - val varname = asmgen.asmVariableName(addrExpr.left as IdentifierReference) - if(asmgen.isZpVar(addrExpr.left as IdentifierReference)) { + is PtBinaryExpression -> { + if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier && addrExpr.right is PtNumber) { + val varname = asmgen.asmVariableName(addrExpr.left as PtIdentifier) + if(asmgen.isZpVar(addrExpr.left as PtIdentifier)) { // pointervar is already in the zero page, no need to copy - val index = (addrExpr.right as NumericLiteral).number.toHex() + val index = (addrExpr.right as PtNumber).number.toHex() asmgen.out(""" ldy #$index lda ($varname),y @@ -845,7 +832,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcMkword(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcMkword(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { if(resultToStack) { asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb @@ -854,12 +841,12 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, val reg = resultRegister ?: RegisterOrPair.AY var needAsave = asmgen.needAsaveForExpr(fcall.args[0]) if(!needAsave) { - val mr0 = fcall.args[0] as? DirectMemoryRead - val mr1 = fcall.args[1] as? DirectMemoryRead + val mr0 = fcall.args[0] as? PtMemoryByte + val mr1 = fcall.args[1] as? PtMemoryByte if (mr0 != null) - needAsave = mr0.addressExpression !is NumericLiteral + needAsave = mr0.address !is PtNumber if (mr1 != null) - needAsave = needAsave or (mr1.addressExpression !is NumericLiteral) + needAsave = needAsave or (mr1.address !is PtNumber) } when(reg) { RegisterOrPair.AX -> { @@ -898,13 +885,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcMsb(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcMsb(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() - if (!arg.inferType(program).isWords) + if (arg.type !in WordDatatypes) throw AssemblyError("msb required word argument") - if (arg is NumericLiteral) + if (arg is PtNumber) throw AssemblyError("msb(const) should have been const-folded away") - if (arg is IdentifierReference) { + if (arg is PtIdentifier) { val sourceName = asmgen.asmVariableName(arg) if(resultToStack) { asmgen.out(" lda $sourceName+1 | sta P8ESTACK_LO,x | dex") @@ -952,14 +939,14 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcLsb(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { + private fun funcLsb(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() - if (!arg.inferType(program).isWords) + if (arg.type !in WordDatatypes) throw AssemblyError("lsb required word argument") - if (arg is NumericLiteral) + if (arg is PtNumber) throw AssemblyError("lsb(const) should have been const-folded away") - if (arg is IdentifierReference) { + if (arg is PtIdentifier) { val sourceName = asmgen.asmVariableName(arg) if(resultToStack) { asmgen.out(" lda $sourceName | sta P8ESTACK_LO,x | dex") @@ -1013,13 +1000,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun outputAddressAndLenghtOfArray(arg: Expression) { + private fun outputAddressAndLenghtOfArray(arg: PtExpression) { // address in P8ZP_SCRATCH_W1, number of elements in A - arg as IdentifierReference + arg as PtIdentifier val arrayVar = arg.targetVarDecl(program)!! - if(!arrayVar.isArray) + if(arrayVar.arraySize==null) throw AssemblyError("length of non-array requested") - val size = arrayVar.arraysize!!.constIndex()!! + val size = arrayVar.arraySize!! val identifierName = asmgen.asmVariableName(arg) asmgen.out(""" lda #<$identifierName @@ -1030,18 +1017,17 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, """) } - private fun translateArguments(args: MutableList, signature: FSignature, scope: Subroutine?) { - val callConv = signature.callConvention(args.map { - it.inferType(program).getOrElse { throw AssemblyError("unknown dt") } - }) + private fun translateArguments(args: MutableList, signature: FSignature, scope: PtSub?) { + val callConv = signature.callConvention(args.map { it.type}) - fun getSourceForFloat(value: Expression): AsmAssignSource { + fun getSourceForFloat(value: PtExpression): AsmAssignSource { return when (value) { - is IdentifierReference -> { - val addr = AddressOf(value, value.position) + is PtIdentifier -> { + val addr = PtAddressOf(value.position) + addr.add(value) AsmAssignSource.fromAstSource(addr, program, asmgen) } - is NumericLiteral -> { + is PtNumber -> { throw AssemblyError("float literals should have been converted into autovar") } else -> { @@ -1049,9 +1035,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, throw AssemblyError("cannot use float arguments outside of a subroutine scope") asmgen.subroutineExtra(scope).usedFloatEvalResultVar2 = true - val variable = IdentifierReference(listOf(subroutineFloatEvalResultVar2), value.position) - val addr = AddressOf(variable, value.position) - addr.linkParents(value) + val variable = PtIdentifier(subroutineFloatEvalResultVar2, DataType.FLOAT, value.position) + val addr = PtAddressOf(value.position) + addr.add(variable) asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.FLOAT, scope) AsmAssignSource.fromAstSource(addr, program, asmgen) } @@ -1069,7 +1055,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, DataType.FLOAT -> getSourceForFloat(value) in PassByReferenceDatatypes -> { // put the address of the argument in AY - val addr = AddressOf(value as IdentifierReference, value.position) + val addr = PtAddressOf(value.position) + addr.add(value) AsmAssignSource.fromAstSource(addr, program, asmgen) } else -> { @@ -1085,7 +1072,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, DataType.FLOAT -> getSourceForFloat(value) in PassByReferenceDatatypes -> { // put the address of the argument in AY - val addr = AddressOf(value as IdentifierReference, value.position) + val addr = PtAddressOf(value.position) + addr.add(value) AsmAssignSource.fromAstSource(addr, program, asmgen) } else -> { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt index fae2a6fb6..9878a5b45 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt @@ -1,16 +1,15 @@ package prog8.codegen.cpu6502 -import prog8.ast.Program -import prog8.ast.expressions.* +import prog8.code.ast.* import prog8.code.core.* import kotlin.math.absoluteValue -internal class ExpressionsAsmGen(private val program: Program, +internal class ExpressionsAsmGen(private val program: PtProgram, private val asmgen: AsmGen, private val allocator: VariableAllocator) { @Deprecated("avoid calling this as it generates slow evalstack based code") - internal fun translateExpression(expression:Expression) { + internal fun translateExpression(expression: PtExpression) { if (this.asmgen.options.slowCodegenWarnings) { asmgen.errors.warn("slow stack evaluation used for expression $expression", expression.position) } @@ -21,31 +20,31 @@ internal class ExpressionsAsmGen(private val program: Program, // the rest of the methods are all PRIVATE - private fun translateExpressionInternal(expression: Expression) { + private fun translateExpressionInternal(expression: PtExpression) { when(expression) { - is PrefixExpression -> translateExpression(expression) - is BinaryExpression -> translateExpression(expression) - is ArrayIndexedExpression -> translateExpression(expression) - is TypecastExpression -> translateExpression(expression) - is AddressOf -> translateExpression(expression) - is DirectMemoryRead -> asmgen.translateDirectMemReadExpressionToRegAorStack(expression, true) - is NumericLiteral -> translateExpression(expression) - is IdentifierReference -> translateExpression(expression) - is FunctionCallExpression -> translateFunctionCallResultOntoStack(expression) - is BuiltinFunctionCall -> asmgen.translateBuiltinFunctionCallExpression(expression, true, null) - is ContainmentCheck -> throw AssemblyError("containment check as complex expression value is not supported") - is ArrayLiteral, is StringLiteral -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable") - is RangeExpression -> throw AssemblyError("range expression should have been changed into array values") - is CharLiteral -> throw AssemblyError("charliteral should have been replaced by ubyte using certain encoding") + is PtPrefix -> translateExpression(expression) + is PtBinaryExpression -> translateExpression(expression) + is PtArrayIndexer -> translateExpression(expression) + is PtTypeCast -> translateExpression(expression) + is PtAddressOf -> translateExpression(expression) + is PtMemoryByte -> asmgen.translateDirectMemReadExpressionToRegAorStack(expression, true) + is PtNumber -> translateExpression(expression) + is PtIdentifier -> translateExpression(expression) + is PtFunctionCall -> translateFunctionCallResultOntoStack(expression) + is PtBuiltinFunctionCall -> asmgen.translateBuiltinFunctionCallExpression(expression, true, null) + is PtContainmentCheck -> throw AssemblyError("containment check as complex expression value is not supported") + is PtArray, is PtString -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable") + is PtRange -> throw AssemblyError("range expression should have been changed into array values") + is PtMachineRegister -> TODO("machine register expression node") else -> TODO("missing expression asmgen for $expression") } } - private fun translateFunctionCallResultOntoStack(call: FunctionCallExpression) { + private fun translateFunctionCallResultOntoStack(call: PtFunctionCall) { // only for use in nested expression evaluation - val sub = call.target.targetSubroutine(program)!! + val sub = call.targetSubroutine(program)!! asmgen.saveXbeforeCall(call) asmgen.translateFunctionCall(call, true) if(sub.regXasResult()) { @@ -54,7 +53,8 @@ internal class ExpressionsAsmGen(private val program: Program, } asmgen.restoreXafterCall(call) - val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters) + sub. + val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters) // TODO does regular sub also have asmReturnvaluesRegisters set? for ((_, reg) in returns) { // result value is in cpu or status registers, put it on the stack instead (as we're evaluating an expression tree) if (reg.registerOrPair != null) { @@ -133,9 +133,9 @@ internal class ExpressionsAsmGen(private val program: Program, } } - private fun translateExpression(typecast: TypecastExpression) { - translateExpressionInternal(typecast.expression) - when(typecast.expression.inferType(program).getOr(DataType.UNDEFINED)) { + private fun translateExpression(typecast: PtTypeCast) { + translateExpressionInternal(typecast.value) + when(typecast.value.type) { DataType.UBYTE, DataType.BOOL -> { when(typecast.type) { DataType.UBYTE, DataType.BYTE -> {} @@ -197,12 +197,12 @@ internal class ExpressionsAsmGen(private val program: Program, } } - private fun translateExpression(expr: AddressOf) { + private fun translateExpression(expr: PtAddressOf) { val name = asmgen.asmVariableName(expr.identifier) asmgen.out(" lda #<$name | sta P8ESTACK_LO,x | lda #>$name | sta P8ESTACK_HI,x | dex") } - private fun translateExpression(expr: NumericLiteral) { + private fun translateExpression(expr: PtNumber) { when(expr.type) { DataType.UBYTE, DataType.BYTE -> asmgen.out(" lda #${expr.number.toHex()} | sta P8ESTACK_LO,x | dex") DataType.UWORD, DataType.WORD -> asmgen.out(""" @@ -220,9 +220,9 @@ internal class ExpressionsAsmGen(private val program: Program, } } - private fun translateExpression(expr: IdentifierReference) { + private fun translateExpression(expr: PtIdentifier) { val varname = asmgen.asmVariableName(expr) - when(expr.inferType(program).getOr(DataType.UNDEFINED)) { + when(expr.type) { DataType.UBYTE, DataType.BYTE -> { asmgen.out(" lda $varname | sta P8ESTACK_LO,x | dex") } @@ -239,22 +239,17 @@ internal class ExpressionsAsmGen(private val program: Program, } } - private fun translateExpression(expr: BinaryExpression) { + private fun translateExpression(expr: PtBinaryExpression) { // Uses evalstack to evaluate the given expression. // TODO we're slowly reducing the number of places where this is called and instead replace that by more efficient assignment-form code (using temp var or register for instance). - val leftIDt = expr.left.inferType(program) - val rightIDt = expr.right.inferType(program) - if(!leftIDt.isKnown || !rightIDt.isKnown) - throw AssemblyError("can't infer type of both expression operands") - - val leftDt = leftIDt.getOrElse { throw AssemblyError("unknown dt") } - val rightDt = rightIDt.getOrElse { throw AssemblyError("unknown dt") } + val leftDt = expr.left.type + val rightDt = expr.right.type // see if we can apply some optimized routines when(expr.operator) { "+" -> { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val leftVal = expr.left.constValue(program)?.number?.toInt() - val rightVal = expr.right.constValue(program)?.number?.toInt() + val leftVal = expr.left.asConstInteger() + val rightVal = expr.right.asConstInteger() if (leftVal!=null && leftVal in -4..4) { translateExpressionInternal(expr.right) if(rightDt in ByteDatatypes) { @@ -318,7 +313,7 @@ internal class ExpressionsAsmGen(private val program: Program, } "-" -> { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val rightVal = expr.right.constValue(program)?.number?.toInt() + val rightVal = expr.right.asConstInteger() if (rightVal!=null && rightVal in -4..4) { translateExpressionInternal(expr.left) @@ -352,7 +347,7 @@ internal class ExpressionsAsmGen(private val program: Program, } } ">>" -> { - val amount = expr.right.constValue(program)?.number?.toInt() + val amount = expr.right.asConstInteger() if(amount!=null) { translateExpressionInternal(expr.left) when (leftDt) { @@ -423,7 +418,7 @@ internal class ExpressionsAsmGen(private val program: Program, } } "<<" -> { - val amount = expr.right.constValue(program)?.number?.toInt() + val amount = expr.right.asConstInteger() if(amount!=null) { translateExpressionInternal(expr.left) if (leftDt in ByteDatatypes) { @@ -450,13 +445,13 @@ internal class ExpressionsAsmGen(private val program: Program, } "*" -> { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val leftVar = expr.left as? IdentifierReference - val rightVar = expr.right as? IdentifierReference + val leftVar = expr.left as? PtIdentifier + val rightVar = expr.right as? PtIdentifier if(leftVar!=null && rightVar!=null && leftVar==rightVar) return translateSquared(leftVar, leftDt) } - val value = expr.right.constValue(program) + val value = expr.right as? PtNumber if(value!=null) { if(rightDt in IntegerDatatypes) { val amount = value.number.toInt() @@ -516,7 +511,7 @@ internal class ExpressionsAsmGen(private val program: Program, } "/" -> { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val rightVal = expr.right.constValue(program)?.number?.toInt() + val rightVal = expr.right.asConstInteger() if(rightVal!=null && rightVal==2) { translateExpressionInternal(expr.left) when (leftDt) { @@ -557,8 +552,8 @@ internal class ExpressionsAsmGen(private val program: Program, } in ComparisonOperators -> { if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) { - val rightVal = expr.right.constValue(program)?.number - if(rightVal==0.0) + val rightVal = expr.right.asConstInteger() + if(rightVal==0) return translateComparisonWithZero(expr.left, leftDt, expr.operator) } } @@ -584,8 +579,8 @@ internal class ExpressionsAsmGen(private val program: Program, } } - private fun translateComparisonWithZero(expr: Expression, dt: DataType, operator: String) { - if(expr.isSimple) { + private fun translateComparisonWithZero(expr: PtExpression, dt: DataType, operator: String) { + if(expr.isSimple()) { if(operator=="!=") { when (dt) { in ByteDatatypes -> { @@ -641,7 +636,7 @@ internal class ExpressionsAsmGen(private val program: Program, } "<" -> { if(dt==DataType.UBYTE || dt==DataType.UWORD) - return translateExpressionInternal(NumericLiteral.fromBoolean(false, expr.position)) + return translateExpressionInternal(PtNumber.fromBoolean(false, expr.position)) when(dt) { DataType.BYTE -> asmgen.out(" jsr prog8_lib.lesszero_b") DataType.WORD -> asmgen.out(" jsr prog8_lib.lesszero_w") @@ -671,7 +666,7 @@ internal class ExpressionsAsmGen(private val program: Program, } ">=" -> { if(dt==DataType.UBYTE || dt==DataType.UWORD) - return translateExpressionInternal(NumericLiteral.fromBoolean(true, expr.position)) + return translateExpressionInternal(PtNumber.fromBoolean(true, expr.position)) when(dt) { DataType.BYTE -> asmgen.out(" jsr prog8_lib.greaterequalzero_sb") DataType.WORD -> asmgen.out(" jsr prog8_lib.greaterequalzero_sw") @@ -683,7 +678,7 @@ internal class ExpressionsAsmGen(private val program: Program, } } - private fun translateSquared(variable: IdentifierReference, dt: DataType) { + private fun translateSquared(variable: PtIdentifier, dt: DataType) { val asmVar = asmgen.asmVariableName(variable) when(dt) { DataType.BYTE, DataType.UBYTE -> { @@ -699,14 +694,12 @@ internal class ExpressionsAsmGen(private val program: Program, asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") } - private fun translateExpression(expr: PrefixExpression) { - translateExpressionInternal(expr.expression) - val itype = expr.inferType(program) - val type = itype.getOrElse { throw AssemblyError("unknown dt") } + private fun translateExpression(expr: PtPrefix) { + translateExpressionInternal(expr.value) when(expr.operator) { "+" -> {} "-" -> { - when(type) { + when(expr.type) { in ByteDatatypes -> asmgen.out(" jsr prog8_lib.neg_b") in WordDatatypes -> asmgen.out(" jsr prog8_lib.neg_w") DataType.FLOAT -> asmgen.out(" jsr floats.neg_f") @@ -714,7 +707,7 @@ internal class ExpressionsAsmGen(private val program: Program, } } "~" -> { - when(type) { + when(expr.type) { in ByteDatatypes -> asmgen.out(""" lda P8ESTACK_LO+1,x @@ -729,22 +722,18 @@ internal class ExpressionsAsmGen(private val program: Program, } } - private fun translateExpression(arrayExpr: ArrayIndexedExpression) { - val elementIDt = arrayExpr.inferType(program) - if(!elementIDt.isKnown) - throw AssemblyError("unknown dt") - val elementDt = elementIDt.getOr(DataType.UNDEFINED) - val arrayVarName = asmgen.asmVariableName(arrayExpr.arrayvar) + private fun translateExpression(arrayExpr: PtArrayIndexer) { + val elementDt = arrayExpr.type + val arrayVarName = asmgen.asmVariableName(arrayExpr.variable) - val arrayVarDecl = arrayExpr.arrayvar.targetVarDecl(program)!! - if(arrayVarDecl.datatype==DataType.UWORD) { + if(arrayExpr.type==DataType.UWORD) { // indexing a pointer var instead of a real array or string if(elementDt !in ByteDatatypes) throw AssemblyError("non-array var indexing requires bytes dt") - if(arrayExpr.inferType(program) isnot DataType.UBYTE) + if(arrayExpr.index.type != DataType.UBYTE) throw AssemblyError("non-array var indexing requires bytes index") asmgen.loadScaledArrayIndexIntoRegister(arrayExpr, elementDt, CpuRegister.Y) - if(asmgen.isZpVar(arrayExpr.arrayvar)) { + if(asmgen.isZpVar(arrayExpr.variable)) { asmgen.out(" lda ($arrayVarName),y") } else { asmgen.out(" lda $arrayVarName | sta P8ZP_SCRATCH_W1 | lda $arrayVarName+1 | sta P8ZP_SCRATCH_W1+1") @@ -754,7 +743,7 @@ internal class ExpressionsAsmGen(private val program: Program, return } - val constIndexNum = arrayExpr.indexer.constIndex() + val constIndexNum = arrayExpr.index.asConstInteger() if(constIndexNum!=null) { val indexValue = constIndexNum * program.memsizer.memorySize(elementDt) when(elementDt) { @@ -881,7 +870,7 @@ internal class ExpressionsAsmGen(private val program: Program, } } - private fun translateCompareStrings(s1: Expression, operator: String, s2: Expression) { + private fun translateCompareStrings(s1: PtExpression, operator: String, s2: PtExpression) { asmgen.assignExpressionToVariable(s1, "prog8_lib.strcmp_expression._arg_s1", DataType.UWORD, null) asmgen.assignExpressionToVariable(s2, "prog8_lib.strcmp_expression._arg_s2", DataType.UWORD, null) asmgen.out(" jsr prog8_lib.strcmp_expression") // result of compare is in A diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt new file mode 100644 index 000000000..589907ddc --- /dev/null +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt @@ -0,0 +1,91 @@ +package prog8.codegen.cpu6502 + +import prog8.code.ast.* +import prog8.code.core.CpuRegister +import prog8.code.core.RegisterOrPair +import kotlin.math.abs + +// TODO include this in the node class directly? + +internal fun PtExpression.asConstInteger(): Int? = + (this as? PtNumber)?.number?.toInt() + + +internal fun PtRange.toConstantIntegerRange(): IntProgression? { + fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression { + return when { + fromVal <= toVal -> when { + stepVal <= 0 -> IntRange.EMPTY + stepVal == 1 -> fromVal..toVal + else -> fromVal..toVal step stepVal + } + else -> when { + stepVal >= 0 -> IntRange.EMPTY + stepVal == -1 -> fromVal downTo toVal + else -> fromVal downTo toVal step abs(stepVal) + } + } + } + + val fromLv = from as? PtNumber + val toLv = to as? PtNumber + val stepLv = step as? PtNumber + if(fromLv==null || toLv==null || stepLv==null) + return null + val fromVal = fromLv.number.toInt() + val toVal = toLv.number.toInt() + val stepVal = stepLv.number.toInt() + return makeRange(fromVal, toVal, stepVal) +} + + +fun PtExpression.isSimple(): Boolean { + when(this) { + is PtAddressOf -> TODO() + is PtArray -> TODO() + is PtArrayIndexer -> TODO() + is PtBinaryExpression -> TODO() + is PtBuiltinFunctionCall -> TODO() + is PtContainmentCheck -> TODO() + is PtFunctionCall -> TODO() + is PtIdentifier -> TODO() + is PtMachineRegister -> TODO() + is PtMemoryByte -> TODO() + is PtNumber -> TODO() + is PtPrefix -> TODO() + is PtRange -> TODO() + is PtString -> TODO() + is PtTypeCast -> TODO() + } +} + +internal fun PtIdentifier.targetStatement(program: PtProgram): PtNode? { + TODO("Not yet implemented") +} + +internal fun PtIdentifier.targetVarDecl(program: PtProgram): PtVariable? = + this.targetStatement(program) as? PtVariable + +internal fun IPtSubroutine.regXasResult(): Boolean = + (this is PtAsmSub) && this.retvalRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } + +internal fun IPtSubroutine.shouldSaveX(): Boolean = + this.regXasResult() || (this is PtAsmSub && (CpuRegister.X in this.clobbers || regXasParam())) + +internal fun PtAsmSub.regXasParam(): Boolean = + parameters.any { it.second.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } + +internal class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean) + +internal fun PtAsmSub.shouldKeepA(): KeepAresult { + // determine if A's value should be kept when preparing for calling the subroutine, and when returning from it + + // it seems that we never have to save A when calling? will be loaded correctly after setup. + // but on return it depends on wether the routine returns something in A. + val saveAonReturn = retvalRegisters.any { it.registerOrPair==RegisterOrPair.A || it.registerOrPair==RegisterOrPair.AY || it.registerOrPair==RegisterOrPair.AX } + return KeepAresult(false, saveAonReturn) +} + +internal fun PtFunctionCall.targetSubroutine(program: PtProgram): IPtSubroutine? { + TODO() +} diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index f3cdb6084..cba2f9e3c 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -1,46 +1,44 @@ package prog8.codegen.cpu6502 import com.github.michaelbull.result.fold -import prog8.ast.Program -import prog8.ast.expressions.IdentifierReference -import prog8.ast.expressions.RangeExpression -import prog8.ast.statements.ForLoop +import prog8.code.ast.PtForLoop +import prog8.code.ast.PtIdentifier +import prog8.code.ast.PtProgram +import prog8.code.ast.PtRange import prog8.code.core.* import kotlin.math.absoluteValue -internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen, private val zeropage: Zeropage) { +internal class ForLoopsAsmGen(private val program: PtProgram, private val asmgen: AsmGen, private val zeropage: Zeropage) { - internal fun translate(stmt: ForLoop) { - val iterableDt = stmt.iterable.inferType(program) - if(!iterableDt.isKnown) - throw AssemblyError("unknown dt") + internal fun translate(stmt: PtForLoop) { + val iterableDt = stmt.iterable.type when(stmt.iterable) { - is RangeExpression -> { - val range = (stmt.iterable as RangeExpression).toConstantIntegerRange() + is PtRange -> { + val range = (stmt.iterable as PtRange).toConstantIntegerRange() if(range==null) { - translateForOverNonconstRange(stmt, iterableDt.getOrElse { throw AssemblyError("unknown dt") }, stmt.iterable as RangeExpression) + translateForOverNonconstRange(stmt, iterableDt, stmt.iterable as PtRange) } else { - translateForOverConstRange(stmt, iterableDt.getOrElse { throw AssemblyError("unknown dt") }, range) + translateForOverConstRange(stmt, iterableDt, range) } } - is IdentifierReference -> { - translateForOverIterableVar(stmt, iterableDt.getOrElse { throw AssemblyError("unknown dt") }, stmt.iterable as IdentifierReference) + is PtIdentifier -> { + translateForOverIterableVar(stmt, iterableDt, stmt.iterable as PtIdentifier) } else -> throw AssemblyError("can't iterate over ${stmt.iterable.javaClass} - should have been replaced by a variable") } } - private fun translateForOverNonconstRange(stmt: ForLoop, iterableDt: DataType, range: RangeExpression) { - val loopLabel = program.makeLabel("for_loop") - val endLabel = program.makeLabel("for_end") - val modifiedLabel = program.makeLabel("for_modified") - val modifiedLabel2 = program.makeLabel("for_modifiedb") + private fun translateForOverNonconstRange(stmt: PtForLoop, iterableDt: DataType, range: PtRange) { + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") + val modifiedLabel = asmgen.makeLabel("for_modified") + val modifiedLabel2 = asmgen.makeLabel("for_modifiedb") asmgen.loopEndLabels.push(endLabel) - val stepsize=range.step.constValue(program)!!.number.toInt() + val stepsize=range.step.asConstInteger()!! if(stepsize < -1) { - val limit = range.to.constValue(program)?.number - if(limit==0.0) + val limit = range.to.asConstInteger() + if(limit==0) throw AssemblyError("for unsigned loop variable it's not possible to count down with step != -1 from a non-const value to exactly zero due to value wrapping") } @@ -52,11 +50,11 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen: val incdec = if(stepsize==1) "inc" else "dec" // loop over byte range via loopvar - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt), null) asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt), null) asmgen.out(loopLabel) - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) asmgen.out(""" lda $varname $modifiedLabel cmp #0 ; modified @@ -70,11 +68,11 @@ $modifiedLabel cmp #0 ; modified // bytes, step >= 2 or <= -2 // loop over byte range via loopvar - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt), null) asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt), null) asmgen.out(loopLabel) - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) if(stepsize>0) { asmgen.out(""" lda $varname @@ -102,14 +100,14 @@ $modifiedLabel cmp #0 ; modified // words, step 1 or -1 stepsize == 1 || stepsize == -1 -> { - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) assignLoopvar(stmt, range) asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY) asmgen.out(""" sty $modifiedLabel+1 sta $modifiedLabel2+1 $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) asmgen.out(""" lda $varname+1 $modifiedLabel cmp #0 ; modified @@ -136,14 +134,14 @@ $modifiedLabel2 cmp #0 ; modified stepsize > 0 -> { // (u)words, step >= 2 - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) assignLoopvar(stmt, range) asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY) asmgen.out(""" sty $modifiedLabel+1 sta $modifiedLabel2+1 $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) if (iterableDt == DataType.ARRAY_UW) { asmgen.out(""" @@ -184,14 +182,14 @@ $endLabel""") else -> { // (u)words, step <= -2 - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) assignLoopvar(stmt, range) asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY) asmgen.out(""" sty $modifiedLabel+1 sta $modifiedLabel2+1 $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) if(iterableDt==DataType.ARRAY_UW) { asmgen.out(""" @@ -237,9 +235,9 @@ $endLabel""") asmgen.loopEndLabels.pop() } - private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) { - val loopLabel = program.makeLabel("for_loop") - val endLabel = program.makeLabel("for_end") + private fun translateForOverIterableVar(stmt: PtForLoop, iterableDt: DataType, ident: PtIdentifier) { + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val iterableName = asmgen.asmVariableName(ident) val decl = ident.targetVarDecl(program)!! @@ -252,8 +250,8 @@ $endLabel""") sty $loopLabel+2 $loopLabel lda ${65535.toHex()} ; modified beq $endLabel - sta ${asmgen.asmVariableName(stmt.loopVar)}""") - asmgen.translate(stmt.body) + sta ${asmgen.asmVariableName(stmt.variable)}""") + asmgen.translate(stmt.statements) asmgen.out(""" inc $loopLabel+1 bne $loopLabel @@ -262,15 +260,15 @@ $loopLabel lda ${65535.toHex()} ; modified $endLabel""") } DataType.ARRAY_UB, DataType.ARRAY_B -> { - val length = decl.arraysize!!.constIndex()!! - val indexVar = program.makeLabel("for_index") + val length = decl.arraySize!! + val indexVar = asmgen.makeLabel("for_index") asmgen.out(""" ldy #0 $loopLabel sty $indexVar lda $iterableName,y - sta ${asmgen.asmVariableName(stmt.loopVar)}""") - asmgen.translate(stmt.body) - if(length<=255) { + sta ${asmgen.asmVariableName(stmt.variable)}""") + asmgen.translate(stmt.statements) + if(length<=255u) { asmgen.out(""" ldy $indexVar iny @@ -285,7 +283,7 @@ $loopLabel sty $indexVar bne $loopLabel beq $endLabel""") } - if(length>=16) { + if(length>=16u) { // allocate index var on ZP if possible val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, stmt.position, asmgen.errors) result.fold( @@ -298,9 +296,9 @@ $loopLabel sty $indexVar asmgen.out(endLabel) } DataType.ARRAY_W, DataType.ARRAY_UW -> { - val length = decl.arraysize!!.constIndex()!! * 2 - val indexVar = program.makeLabel("for_index") - val loopvarName = asmgen.asmVariableName(stmt.loopVar) + val length = decl.arraySize!! * 2u + val indexVar = asmgen.makeLabel("for_index") + val loopvarName = asmgen.asmVariableName(stmt.variable) asmgen.out(""" ldy #0 $loopLabel sty $indexVar @@ -308,8 +306,8 @@ $loopLabel sty $indexVar sta $loopvarName lda $iterableName+1,y sta $loopvarName+1""") - asmgen.translate(stmt.body) - if(length<=127) { + asmgen.translate(stmt.statements) + if(length<=127u) { asmgen.out(""" ldy $indexVar iny @@ -326,7 +324,7 @@ $loopLabel sty $indexVar bne $loopLabel beq $endLabel""") } - if(length>=16) { + if(length>=16u) { // allocate index var on ZP if possible val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, stmt.position, asmgen.errors) result.fold( @@ -346,7 +344,7 @@ $loopLabel sty $indexVar asmgen.loopEndLabels.pop() } - private fun translateForOverConstRange(stmt: ForLoop, iterableDt: DataType, range: IntProgression) { + private fun translateForOverConstRange(stmt: PtForLoop, iterableDt: DataType, range: IntProgression) { if (range.isEmpty() || range.step==0) throw AssemblyError("empty range or step 0") if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) { @@ -359,18 +357,18 @@ $loopLabel sty $indexVar } // not one of the easy cases, generate more complex code... - val loopLabel = program.makeLabel("for_loop") - val endLabel = program.makeLabel("for_end") + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) when(iterableDt) { DataType.ARRAY_B, DataType.ARRAY_UB -> { // loop over byte range via loopvar, step >= 2 or <= -2 - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) asmgen.out(""" lda #${range.first} sta $varname $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) when (range.step) { 0, 1, -1 -> { throw AssemblyError("step 0, 1 and -1 should have been handled specifically $stmt") @@ -430,7 +428,7 @@ $loopLabel""") } DataType.ARRAY_W, DataType.ARRAY_UW -> { // loop over word range via loopvar, step >= 2 or <= -2 - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) when (range.step) { 0, 1, -1 -> { throw AssemblyError("step 0, 1 and -1 should have been handled specifically $stmt") @@ -444,7 +442,7 @@ $loopLabel""") sta $varname sty $varname+1 $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) asmgen.out(""" lda $varname cmp #<${range.last} @@ -470,16 +468,16 @@ $loopLabel""") asmgen.loopEndLabels.pop() } - private fun translateForSimpleByteRangeAsc(stmt: ForLoop, range: IntProgression) { - val loopLabel = program.makeLabel("for_loop") - val endLabel = program.makeLabel("for_end") + private fun translateForSimpleByteRangeAsc(stmt: PtForLoop, range: IntProgression) { + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) asmgen.out(""" lda #${range.first} sta $varname $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) if (range.last == 255) { asmgen.out(""" inc $varname @@ -496,16 +494,16 @@ $endLabel""") asmgen.loopEndLabels.pop() } - private fun translateForSimpleByteRangeDesc(stmt: ForLoop, range: IntProgression) { - val loopLabel = program.makeLabel("for_loop") - val endLabel = program.makeLabel("for_end") + private fun translateForSimpleByteRangeDesc(stmt: PtForLoop, range: IntProgression) { + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) asmgen.out(""" lda #${range.first} sta $varname $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) when (range.last) { 0 -> { asmgen.out(""" @@ -533,18 +531,18 @@ $endLabel""") asmgen.loopEndLabels.pop() } - private fun translateForSimpleWordRangeAsc(stmt: ForLoop, range: IntProgression) { - val loopLabel = program.makeLabel("for_loop") - val endLabel = program.makeLabel("for_end") + private fun translateForSimpleWordRangeAsc(stmt: PtForLoop, range: IntProgression) { + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) asmgen.out(""" lda #<${range.first} ldy #>${range.first} sta $varname sty $varname+1 $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) asmgen.out(""" lda $varname cmp #<${range.last} @@ -560,18 +558,18 @@ $loopLabel""") asmgen.loopEndLabels.pop() } - private fun translateForSimpleWordRangeDesc(stmt: ForLoop, range: IntProgression) { - val loopLabel = program.makeLabel("for_loop") - val endLabel = program.makeLabel("for_end") + private fun translateForSimpleWordRangeDesc(stmt: PtForLoop, range: IntProgression) { + val loopLabel = asmgen.makeLabel("for_loop") + val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) - val varname = asmgen.asmVariableName(stmt.loopVar) + val varname = asmgen.asmVariableName(stmt.variable) asmgen.out(""" lda #<${range.first} ldy #>${range.first} sta $varname sty $varname+1 $loopLabel""") - asmgen.translate(stmt.body) + asmgen.translate(stmt.statements) asmgen.out(""" lda $varname cmp #<${range.last} @@ -588,10 +586,10 @@ $loopLabel""") asmgen.loopEndLabels.pop() } - private fun assignLoopvar(stmt: ForLoop, range: RangeExpression) = + private fun assignLoopvar(stmt: PtForLoop, range: PtRange) = asmgen.assignExpressionToVariable( range.from, - asmgen.asmVariableName(stmt.loopVar), - stmt.loopVarDt(program).getOrElse { throw AssemblyError("unknown dt") }, - stmt.definingSubroutine) + asmgen.asmVariableName(stmt.variable), + stmt.variable.type, + stmt.definingSub()) } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index 101b13d76..ea3773653 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -1,16 +1,6 @@ package prog8.codegen.cpu6502 -import prog8.ast.IFunctionCall -import prog8.ast.Node -import prog8.ast.Program -import prog8.ast.expressions.AddressOf -import prog8.ast.expressions.Expression -import prog8.ast.expressions.IdentifierReference -import prog8.ast.expressions.NumericLiteral -import prog8.ast.statements.FunctionCallStatement -import prog8.ast.statements.InlineAssembly -import prog8.ast.statements.Subroutine -import prog8.ast.statements.SubroutineParameter +import prog8.code.ast.* import prog8.code.core.* import prog8.codegen.cpu6502.assignment.AsmAssignSource import prog8.codegen.cpu6502.assignment.AsmAssignTarget @@ -18,51 +8,57 @@ import prog8.codegen.cpu6502.assignment.AsmAssignment import prog8.codegen.cpu6502.assignment.TargetStorageKind -internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen) { +internal class FunctionCallAsmGen(private val program: PtProgram, private val asmgen: AsmGen) { - internal fun translateFunctionCallStatement(stmt: FunctionCallStatement) { + internal fun translateFunctionCallStatement(stmt: PtFunctionCall) { saveXbeforeCall(stmt) translateFunctionCall(stmt, false) restoreXafterCall(stmt) // just ignore any result values from the function call. } - internal fun saveXbeforeCall(stmt: IFunctionCall) { - val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}") + internal fun saveXbeforeCall(stmt: PtFunctionCall) { + val sub = stmt.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.name}") if(sub.shouldSaveX()) { - val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls - if(regSaveOnStack) - asmgen.saveRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnEntry) - else - asmgen.saveRegisterLocal(CpuRegister.X, (stmt as Node).definingSubroutine!!) + if(sub is PtAsmSub) { + val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls + if (regSaveOnStack) + asmgen.saveRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnEntry) + else + asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingSub()!!) + } else + asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingSub()!!) } } - internal fun restoreXafterCall(stmt: IFunctionCall) { - val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}") + internal fun restoreXafterCall(stmt: PtFunctionCall) { + val sub = stmt.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.name}") if(sub.shouldSaveX()) { - val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls - if(regSaveOnStack) - asmgen.restoreRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnReturn) - else + if(sub is PtAsmSub) { + val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls + if (regSaveOnStack) + asmgen.restoreRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnReturn) + else + asmgen.restoreRegisterLocal(CpuRegister.X) + } else asmgen.restoreRegisterLocal(CpuRegister.X) } } - internal fun optimizeIntArgsViaRegisters(sub: Subroutine) = + internal fun optimizeIntArgsViaRegisters(sub: PtSub) = (sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes) || (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes) - internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) { // TODO remove isExpression unused parameter + internal fun translateFunctionCall(call: PtFunctionCall, isExpression: Boolean) { // TODO remove isExpression unused parameter // Output only the code to set up the parameters and perform the actual call // NOTE: does NOT output the code to deal with the result values! // NOTE: does NOT output code to save/restore the X register for this call! Every caller should deal with this in their own way!! // (you can use subroutine.shouldSaveX() and saveX()/restoreX() routines as a help for this) - val sub = call.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${call.target}") - val subAsmName = asmgen.asmSymbolName(call.target) + val sub: IPtSubroutine = call.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${call.name}") + val subAsmName = asmgen.asmSymbolName(call.name) - if(sub.isAsmSubroutine) { + if(sub is PtAsmSub) { argumentsViaRegisters(sub, call) if (sub.inline && asmgen.options.optimize) { // inline the subroutine. @@ -70,13 +66,13 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg // NOTE: *if* there is a return statement, it will be the only one, and the very last statement of the subroutine // (this condition has been enforced by an ast check earlier) asmgen.out(" \t; inlined routine follows: ${sub.name}") - sub.statements.forEach { asmgen.translate(it as InlineAssembly) } + sub.children.forEach { asmgen.translate(it as PtInlineAssembly) } asmgen.out(" \t; inlined routine end: ${sub.name}") } else { asmgen.out(" jsr $subAsmName") } } - else { + else if(sub is PtSub) { if(sub.inline) throw AssemblyError("can only reliably inline asmsub routines at this time") @@ -100,84 +96,80 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg } asmgen.out(" jsr $subAsmName") } + else throw AssemblyError("invalid sub type") // remember: dealing with the X register and/or dealing with return values is the responsibility of the caller } - private fun argumentsViaRegisters(sub: Subroutine, call: IFunctionCall) { + private fun argumentsViaRegisters(sub: PtAsmSub, call: PtFunctionCall) { if(sub.parameters.size==1) { - argumentViaRegister(sub, IndexedValue(0, sub.parameters.single()), call.args[0]) + argumentViaRegister(sub, IndexedValue(0, sub.parameters.single().first), call.args[0]) } else { - if(asmsub6502ArgsHaveRegisterClobberRisk(call.args, sub.asmParameterRegisters)) { + if(asmsub6502ArgsHaveRegisterClobberRisk(call.args, sub.parameters)) { registerArgsViaCpuStackEvaluation(call, sub) } else { asmsub6502ArgsEvalOrder(sub).forEach { val param = sub.parameters[it] val arg = call.args[it] - argumentViaRegister(sub, IndexedValue(it, param), arg) + argumentViaRegister(sub, IndexedValue(it, param.first), arg) } } } } - private fun registerArgsViaCpuStackEvaluation(call: IFunctionCall, callee: Subroutine) { + private fun registerArgsViaCpuStackEvaluation(call: PtFunctionCall, callee: PtAsmSub) { // this is called when one or more of the arguments are 'complex' and // cannot be assigned to a register easily or risk clobbering other registers. - require(callee.isAsmSubroutine) { "register args only for asm subroutine ${callee.position}" } if(callee.parameters.isEmpty()) return // use the cpu hardware stack as intermediate storage for the arguments. val argOrder = asmsub6502ArgsEvalOrder(callee) argOrder.reversed().forEach { - asmgen.pushCpuStack(callee.parameters[it].type, call.args[it]) + asmgen.pushCpuStack(callee.parameters[it].first.type, call.args[it]) } argOrder.forEach { - val param = callee.parameters[it] + val param = callee.parameters[it].first val targetVar = callee.searchParameter(param.name)!! - asmgen.popCpuStack(param.type, targetVar, (call as Node).definingSubroutine) + asmgen.popCpuStack(param.type, targetVar, call.definingSub()) } } - private fun argumentViaVariable(sub: Subroutine, parameter: SubroutineParameter, value: Expression) { + private fun argumentViaVariable(sub: PtSub, parameter: PtSubroutineParameter, value: PtExpression) { // pass parameter via a regular variable (not via registers) - val valueIDt = value.inferType(program) - val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") } - if(!isArgumentTypeCompatible(valueDt, parameter.type)) + if(!isArgumentTypeCompatible(value.type, parameter.type)) throw AssemblyError("argument type incompatible") val varName = asmgen.asmVariableName(sub.scopedName + parameter.name) asmgen.assignExpressionToVariable(value, varName, parameter.type, sub) } - private fun argumentViaRegister(sub: Subroutine, parameter: IndexedValue, value: Expression, registerOverride: RegisterOrPair? = null) { + private fun argumentViaRegister(sub: IPtSubroutine, parameter: IndexedValue, value: PtExpression, registerOverride: RegisterOrPair? = null) { // pass argument via a register parameter - val valueIDt = value.inferType(program) - val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") } - if(!isArgumentTypeCompatible(valueDt, parameter.value.type)) + if(!isArgumentTypeCompatible(value.type, parameter.value.type)) throw AssemblyError("argument type incompatible") - val paramRegister = if(registerOverride==null) sub.asmParameterRegisters[parameter.index] else RegisterOrStatusflag(registerOverride, null) + val paramRegister = if(registerOverride==null) sub.parameters[parameter.index].second else RegisterOrStatusflag(registerOverride, null) val statusflag = paramRegister.statusflag val register = paramRegister.registerOrPair val requiredDt = parameter.value.type - if(requiredDt!=valueDt) { - if(valueDt largerThan requiredDt) + if(requiredDt!=value.type) { + if(value.type largerThan requiredDt) throw AssemblyError("can only convert byte values to word param types") } if (statusflag!=null) { - if(requiredDt!=valueDt) + if(requiredDt!=value.type) throw AssemblyError("for statusflag, byte value is required") if (statusflag == Statusflag.Pc) { // this param needs to be set last, right before the jsr // for now, this is already enforced on the subroutine definition by the Ast Checker when(value) { - is NumericLiteral -> { + is PtNumber -> { val carrySet = value.number.toInt() != 0 asmgen.out(if(carrySet) " sec" else " clc") } - is IdentifierReference -> { + is PtIdentifier -> { val sourceName = asmgen.asmVariableName(value) asmgen.out(""" pha @@ -202,10 +194,10 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg else { // via register or register pair register!! - if(requiredDt largerThan valueDt) { + if(requiredDt largerThan value.type) { // we need to sign extend the source, do this via temporary word variable asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", DataType.UBYTE, sub) - asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", valueDt) + asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", value.type) asmgen.assignVariableToRegister("P8ZP_SCRATCH_W1", register) } else { val target: AsmAssignTarget = @@ -215,9 +207,10 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg val signed = parameter.value.type == DataType.BYTE || parameter.value.type == DataType.WORD AsmAssignTarget.fromRegisters(register, signed, sub, asmgen) } - val src = if(valueDt in PassByReferenceDatatypes) { - if(value is IdentifierReference) { - val addr = AddressOf(value, Position.DUMMY) + val src = if(value.type in PassByReferenceDatatypes) { + if(value is PtIdentifier) { + val addr = PtAddressOf(Position.DUMMY) + addr.add(value) AsmAssignSource.fromAstSource(addr, program, asmgen).adjustSignedUnsigned(target) } else { AsmAssignSource.fromAstSource(value, program, asmgen).adjustSignedUnsigned(target) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt index d5d052725..db56a016f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt @@ -1,23 +1,23 @@ package prog8.codegen.cpu6502 -import prog8.ast.Program -import prog8.ast.expressions.IdentifierReference -import prog8.ast.expressions.NumericLiteral -import prog8.ast.statements.PostIncrDecr +import prog8.code.ast.PtIdentifier +import prog8.code.ast.PtNumber +import prog8.code.ast.PtPostIncrDecr +import prog8.code.ast.PtProgram import prog8.code.core.* -internal class PostIncrDecrAsmGen(private val program: Program, private val asmgen: AsmGen) { - internal fun translate(stmt: PostIncrDecr) { +internal class PostIncrDecrAsmGen(private val program: PtProgram, private val asmgen: AsmGen) { + internal fun translate(stmt: PtPostIncrDecr) { val incr = stmt.operator=="++" val targetIdent = stmt.target.identifier - val targetMemory = stmt.target.memoryAddress - val targetArrayIdx = stmt.target.arrayindexed - val scope = stmt.definingSubroutine + val targetMemory = stmt.target.memory + val targetArrayIdx = stmt.target.array + val scope = stmt.definingSub() when { targetIdent!=null -> { val what = asmgen.asmVariableName(targetIdent) - when (stmt.target.inferType(program).getOr(DataType.UNDEFINED)) { + when (stmt.target.type) { in ByteDatatypes -> asmgen.out(if (incr) " inc $what" else " dec $what") in WordDatatypes -> { if(incr) @@ -38,12 +38,12 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg } } targetMemory!=null -> { - when (val addressExpr = targetMemory.addressExpression) { - is NumericLiteral -> { + when (val addressExpr = targetMemory.address) { + is PtNumber -> { val what = addressExpr.number.toHex() asmgen.out(if(incr) " inc $what" else " dec $what") } - is IdentifierReference -> { + is PtIdentifier -> { val what = asmgen.asmVariableName(addressExpr) asmgen.out(" lda $what | sta (+) +1 | lda $what+1 | sta (+) +2") if(incr) @@ -62,9 +62,9 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg } } targetArrayIdx!=null -> { - val asmArrayvarname = asmgen.asmVariableName(targetArrayIdx.arrayvar) - val elementDt = targetArrayIdx.inferType(program).getOr(DataType.UNDEFINED) - val constIndex = targetArrayIdx.indexer.constIndex() + val asmArrayvarname = asmgen.asmVariableName(targetArrayIdx.variable) + val elementDt = targetArrayIdx.type + val constIndex = targetArrayIdx.index.asConstInteger() if(constIndex!=null) { val indexValue = constIndex * program.memsizer.memorySize(elementDt) when(elementDt) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 4e69dc90b..e3b694292 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -1,12 +1,10 @@ package prog8.codegen.cpu6502 -import prog8.ast.Program -import prog8.ast.statements.* import prog8.code.* +import prog8.code.ast.* import prog8.code.core.* import prog8.codegen.cpu6502.assignment.AsmAssignTarget import prog8.codegen.cpu6502.assignment.TargetStorageKind -import prog8.compiler.CallGraph import java.time.LocalDate import java.time.LocalDateTime import kotlin.math.absoluteValue @@ -20,7 +18,7 @@ import kotlin.math.absoluteValue * - all variables (note: VarDecl ast nodes are *NOT* used anymore for this! now uses IVariablesAndConsts data tables!) */ internal class ProgramAndVarsGen( - val program: Program, + val program: PtProgram, val options: CompilationOptions, val errors: IErrorReporter, private val symboltable: SymbolTable, @@ -30,20 +28,19 @@ internal class ProgramAndVarsGen( private val zeropage: Zeropage ) { private val compTarget = options.compTarget - private val callGraph = CallGraph(program, true) - private val blockVariableInitializers = program.allBlocks.associateWith { it.statements.filterIsInstance() } + // TODO ???? private val callGraph = CallGraph(program, true) + private val blockVariableInitializers = program.allBlocks().associateWith { it.children.filterIsInstance() } internal fun generate() { val allInitializers = blockVariableInitializers.asSequence().flatMap { it.value } - require(allInitializers.all { it.origin==AssignmentOrigin.VARINIT }) {"all block-level assignments must be a variable initializer"} header() - val allBlocks = program.allBlocks + val allBlocks = program.allBlocks() if(allBlocks.first().name != "main") throw AssemblyError("first block should be 'main'") if(errors.noErrors()) { - program.allBlocks.forEach { block2asm(it) } + program.allBlocks().forEach { block2asm(it) } // the global list of all floating point constants for the whole program asmgen.out("; global float constants") @@ -100,7 +97,7 @@ internal class ProgramAndVarsGen( when(options.launcher) { CbmPrgLauncherType.BASIC -> { if (options.loadAddress != options.compTarget.machine.PROGRAM_LOAD_ADDRESS) { - errors.err("BASIC output must have load address ${options.compTarget.machine.PROGRAM_LOAD_ADDRESS.toHex()}", program.toplevelModule.position) + errors.err("BASIC output must have load address ${options.compTarget.machine.PROGRAM_LOAD_ADDRESS.toHex()}", program.position) } asmgen.out("; ---- basic program with sys call ----") asmgen.out("* = ${options.loadAddress.toHex()}") @@ -183,28 +180,28 @@ internal class ProgramAndVarsGen( asmgen.out("prog8_program_end\t; end of program label for progend()") } - private fun block2asm(block: Block) { + private fun block2asm(block: PtBlock) { asmgen.out("") asmgen.out("; ---- block: '${block.name}' ----") if(block.address!=null) asmgen.out("* = ${block.address!!.toHex()}") else { - if("align_word" in block.options()) + if(block.alignment==PtBlock.BlockAlignment.WORD) asmgen.out("\t.align 2") - else if("align_page" in block.options()) + else if(block.alignment==PtBlock.BlockAlignment.PAGE) asmgen.out("\t.align $100") } - asmgen.out("${block.name}\t" + (if("force_output" in block.options()) ".block\n" else ".proc\n")) + asmgen.out("${block.name}\t" + (if(block.forceOutput) ".block\n" else ".proc\n")) asmgen.outputSourceLine(block) createBlockVariables(block) - asmsubs2asm(block.statements) + asmsubs2asm(block.children) asmgen.out("") val initializers = blockVariableInitializers.getValue(block) - val notInitializers = block.statements.filterNot { it in initializers } + val notInitializers = block.children.filterNot { it in initializers } notInitializers.forEach { asmgen.translate(it) } if(!options.dontReinitGlobals) { @@ -216,13 +213,13 @@ internal class ProgramAndVarsGen( } } - asmgen.out(if("force_output" in block.options()) "\n\t.bend\n" else "\n\t.pend\n") + asmgen.out(if(block.forceOutput) "\n\t.bend\n" else "\n\t.pend\n") } private fun getVars(scope: StNode): Map = scope.children.filter { it.value.type in arrayOf(StNodeType.STATICVAR, StNodeType.CONSTANT, StNodeType.MEMVAR) } - private fun createBlockVariables(block: Block) { + private fun createBlockVariables(block: PtBlock) { val scope = symboltable.lookupUnscopedOrElse(block.name) { throw AssemblyError("lookup") } require(scope.type==StNodeType.BLOCK) val varsInBlock = getVars(scope) @@ -247,12 +244,41 @@ internal class ProgramAndVarsGen( nonZpVariables2asm(variables) } - internal fun translateSubroutine(sub: Subroutine) { + internal fun translateAsmSubroutine(sub: PtAsmSub) { + if(sub.inline) { + if(options.optimize) { + return + } + } + + asmgen.out("") + + val asmStartScope: String + val asmEndScope: String + if(sub.definingBlock()!!.forceOutput) { + asmStartScope = ".block" + asmEndScope = ".bend" + } else { + asmStartScope = ".proc" + asmEndScope = ".pend" + } + + if(sub.address!=null) + return // already done at the memvars section + + // asmsub with most likely just an inline asm in it + asmgen.out("${sub.name}\t$asmStartScope") + sub.children.forEach { asmgen.translate(it) } + asmgen.out(" $asmEndScope\n") + } + + + internal fun translateSubroutine(sub: PtSub) { var onlyVariables = false if(sub.inline) { if(options.optimize) { - if(sub.isAsmSubroutine || callGraph.unused(sub)) + if(callGraph.unused(sub)) return // from an inlined subroutine only the local variables are generated, @@ -266,7 +292,7 @@ internal class ProgramAndVarsGen( val asmStartScope: String val asmEndScope: String - if(sub.definingBlock.options().contains("force_output")) { + if(sub.definingBlock()!!.forceOutput) { asmStartScope = ".block" asmEndScope = ".bend" } else { @@ -274,95 +300,84 @@ internal class ProgramAndVarsGen( asmEndScope = ".pend" } - if(sub.isAsmSubroutine) { - if(sub.asmAddress!=null) - return // already done at the memvars section + asmgen.out("${sub.name}\t$asmStartScope") - // asmsub with most likely just an inline asm in it - asmgen.out("${sub.name}\t$asmStartScope") - sub.statements.forEach { asmgen.translate(it) } - asmgen.out(" $asmEndScope\n") - } else { - // regular subroutine - asmgen.out("${sub.name}\t$asmStartScope") + val scope = symboltable.lookupOrElse(sub.scopedName) { throw AssemblyError("lookup") } + require(scope.type==StNodeType.SUBROUTINE) + val varsInSubroutine = getVars(scope) - val scope = symboltable.lookupOrElse(sub.scopedName.joinToString(".")) { throw AssemblyError("lookup") } - require(scope.type==StNodeType.SUBROUTINE) - val varsInSubroutine = getVars(scope) + // Zeropage Variables + val varnames = varsInSubroutine.filter { it.value.type==StNodeType.STATICVAR }.map { it.value.scopedName }.toSet() + zeropagevars2asm(varnames) - // Zeropage Variables - val varnames = varsInSubroutine.filter { it.value.type==StNodeType.STATICVAR }.map { it.value.scopedName }.toSet() - zeropagevars2asm(varnames) + // MemDefs and Consts + val mvs = varsInSubroutine + .filter { it.value.type==StNodeType.MEMVAR } + .map { it.value as StMemVar } + val consts = varsInSubroutine + .filter { it.value.type==StNodeType.CONSTANT } + .map { it.value as StConstant } + memdefsAndConsts2asm(mvs, consts) - // MemDefs and Consts - val mvs = varsInSubroutine - .filter { it.value.type==StNodeType.MEMVAR } - .map { it.value as StMemVar } - val consts = varsInSubroutine - .filter { it.value.type==StNodeType.CONSTANT } - .map { it.value as StConstant } - memdefsAndConsts2asm(mvs, consts) + asmsubs2asm(sub.children) - asmsubs2asm(sub.statements) + // the main.start subroutine is the program's entrypoint and should perform some initialization logic + if(sub.name=="start" && sub.definingBlock()!!.name=="main") + entrypointInitialization() - // the main.start subroutine is the program's entrypoint and should perform some initialization logic - if(sub.name=="start" && sub.definingBlock.name=="main") - entrypointInitialization() - - if(functioncallAsmGen.optimizeIntArgsViaRegisters(sub)) { - asmgen.out("; simple int arg(s) passed via register(s)") - if(sub.parameters.size==1) { - val dt = sub.parameters[0].type - val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, sub, variableAsmName = sub.parameters[0].name) - if(dt in ByteDatatypes) - asmgen.assignRegister(RegisterOrPair.A, target) - else - asmgen.assignRegister(RegisterOrPair.AY, target) - } else { - require(sub.parameters.size==2) - // 2 simple byte args, first in A, second in Y - val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, sub.parameters[0].type, sub, variableAsmName = sub.parameters[0].name) - val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, sub.parameters[1].type, sub, variableAsmName = sub.parameters[1].name) - asmgen.assignRegister(RegisterOrPair.A, target1) - asmgen.assignRegister(RegisterOrPair.Y, target2) - } + if(functioncallAsmGen.optimizeIntArgsViaRegisters(sub)) { + asmgen.out("; simple int arg(s) passed via register(s)") + if(sub.parameters.size==1) { + val dt = sub.parameters[0].type + val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, sub, variableAsmName = sub.parameters[0].name) + if(dt in ByteDatatypes) + asmgen.assignRegister(RegisterOrPair.A, target) + else + asmgen.assignRegister(RegisterOrPair.AY, target) + } else { + require(sub.parameters.size==2) + // 2 simple byte args, first in A, second in Y + val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, sub.parameters[0].type, sub, variableAsmName = sub.parameters[0].name) + val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, sub.parameters[1].type, sub, variableAsmName = sub.parameters[1].name) + asmgen.assignRegister(RegisterOrPair.A, target1) + asmgen.assignRegister(RegisterOrPair.Y, target2) } - - if(!onlyVariables) { - asmgen.out("; statements") - sub.statements.forEach { asmgen.translate(it) } - } - - asmgen.out("; variables") - val asmGenInfo = asmgen.subroutineExtra(sub) - for((dt, name, addr) in asmGenInfo.extraVars) { - if(addr!=null) - asmgen.out("$name = $addr") - else when(dt) { - DataType.UBYTE -> asmgen.out("$name .byte 0") - DataType.UWORD -> asmgen.out("$name .word 0") - else -> throw AssemblyError("weird dt") - } - } - if(asmGenInfo.usedRegsaveA) // will probably never occur - asmgen.out("prog8_regsaveA .byte 0") - if(asmGenInfo.usedRegsaveX) - asmgen.out("prog8_regsaveX .byte 0") - if(asmGenInfo.usedRegsaveY) - asmgen.out("prog8_regsaveY .byte 0") - if(asmGenInfo.usedFloatEvalResultVar1) - asmgen.out("$subroutineFloatEvalResultVar1 .byte 0,0,0,0,0") - if(asmGenInfo.usedFloatEvalResultVar2) - asmgen.out("$subroutineFloatEvalResultVar2 .byte 0,0,0,0,0") - - // normal statically allocated variables - val variables = varsInSubroutine - .filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName.split('.')) } - .map { it.value as StStaticVariable } - nonZpVariables2asm(variables) - - asmgen.out(" $asmEndScope\n") } + + if(!onlyVariables) { + asmgen.out("; statements") + sub.children.forEach { asmgen.translate(it) } + } + + asmgen.out("; variables") + val asmGenInfo = asmgen.subroutineExtra(sub) + for((dt, name, addr) in asmGenInfo.extraVars) { + if(addr!=null) + asmgen.out("$name = $addr") + else when(dt) { + DataType.UBYTE -> asmgen.out("$name .byte 0") + DataType.UWORD -> asmgen.out("$name .word 0") + else -> throw AssemblyError("weird dt") + } + } + if(asmGenInfo.usedRegsaveA) // will probably never occur + asmgen.out("prog8_regsaveA .byte 0") + if(asmGenInfo.usedRegsaveX) + asmgen.out("prog8_regsaveX .byte 0") + if(asmGenInfo.usedRegsaveY) + asmgen.out("prog8_regsaveY .byte 0") + if(asmGenInfo.usedFloatEvalResultVar1) + asmgen.out("$subroutineFloatEvalResultVar1 .byte 0,0,0,0,0") + if(asmGenInfo.usedFloatEvalResultVar2) + asmgen.out("$subroutineFloatEvalResultVar2 .byte 0,0,0,0,0") + + // normal statically allocated variables + val variables = varsInSubroutine + .filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName.split('.')) } + .map { it.value as StStaticVariable } + nonZpVariables2asm(variables) + + asmgen.out(" $asmEndScope\n") } private fun entrypointInitialization() { @@ -593,12 +608,12 @@ internal class ProgramAndVarsGen( } } - private fun asmsubs2asm(statements: List) { + private fun asmsubs2asm(statements: List) { statements - .filter { it is Subroutine && it.isAsmSubroutine && it.asmAddress!=null } + .filter { it is PtAsmSub && it.address!=null } .forEach { asmsub -> - asmsub as Subroutine - asmgen.out(" ${asmsub.name} = ${asmsub.asmAddress!!.toHex()}") + asmsub as PtAsmSub + asmgen.out(" ${asmsub.name} = ${asmsub.address!!.toHex()}") } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index ae1e60702..0680f7611 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -22,7 +22,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable, allocateZeropageVariables() } - internal fun isZpVar(scopedName: List) = scopedName in zeropageVars + internal fun isZpVar(scopedName: List) = scopedName in zeropageVars // TODO as dotted string instead of list? internal fun getFloatAsmConst(number: Double): String { val asmName = globalFloatConsts[number] diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index 8f01d7611..3fc9829da 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -1,13 +1,11 @@ package prog8.codegen.cpu6502.assignment -import prog8.ast.Program -import prog8.ast.expressions.* -import prog8.ast.statements.AssignTarget -import prog8.ast.statements.Assignment -import prog8.ast.statements.DirectMemoryWrite -import prog8.ast.statements.Subroutine +import prog8.code.ast.* import prog8.code.core.* import prog8.codegen.cpu6502.AsmGen +import prog8.codegen.cpu6502.asConstInteger +import prog8.codegen.cpu6502.targetSubroutine +import prog8.codegen.cpu6502.targetVarDecl internal enum class TargetStorageKind { @@ -31,20 +29,20 @@ internal enum class SourceStorageKind { internal class AsmAssignTarget(val kind: TargetStorageKind, private val asmgen: AsmGen, val datatype: DataType, - val scope: Subroutine?, + val scope: IPtSubroutine?, private val variableAsmName: String? = null, - val array: ArrayIndexedExpression? = null, - val memory: DirectMemoryWrite? = null, + val array: PtArrayIndexer? = null, + val memory: PtMemoryByte? = null, val register: RegisterOrPair? = null, - val origAstTarget: AssignTarget? = null + val origAstTarget: PtAssignTarget? = null ) { - val constArrayIndexValue by lazy { array?.indexer?.constIndex()?.toUInt() } + val constArrayIndexValue by lazy { array?.index?.asConstInteger()?.toUInt() } val asmVarname: String by lazy { if (array == null) variableAsmName!! else - asmgen.asmVariableName(array.arrayvar) + asmgen.asmVariableName(array.variable) } lateinit var origAssign: AsmAssignment @@ -55,10 +53,8 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, } companion object { - fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen): AsmAssignTarget { + fun fromAstAssignment(assign: PtAssignment, program: PtProgram, asmgen: AsmGen): AsmAssignTarget { with(assign.target) { - val idt = inferType(program) - val dt = idt.getOrElse { throw AssemblyError("unknown dt") } when { identifier != null -> { val parameter = identifier!!.targetVarDecl(program)?.subroutineParameter @@ -69,19 +65,19 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, if(reg.statusflag!=null) throw AssemblyError("can't assign value to processor statusflag directly") else - return AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, assign.definingSubroutine, register=reg.registerOrPair, origAstTarget = this) + return AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, type, assign.definingSub(), register=reg.registerOrPair, origAstTarget = this) } } - return AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this) + return AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, type, assign.definingSub(), variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this) } - arrayindexed != null -> return AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this) - memoryAddress != null -> return AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, dt, assign.definingSubroutine, memory = memoryAddress, origAstTarget = this) + array != null -> return AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, type, assign.definingSub(), array = array, origAstTarget = this) + memory != null -> return AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, type, assign.definingSub(), memory = memory, origAstTarget = this) else -> throw AssemblyError("weird target") } } } - fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: Subroutine?, asmgen: AsmGen): AsmAssignTarget = + fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: IPtSubroutine?, asmgen: AsmGen): AsmAssignTarget = when(registers) { RegisterOrPair.A, RegisterOrPair.X, @@ -112,69 +108,65 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, } internal class AsmAssignSource(val kind: SourceStorageKind, - private val program: Program, + private val program: PtProgram, private val asmgen: AsmGen, val datatype: DataType, private val variableAsmName: String? = null, - val array: ArrayIndexedExpression? = null, - val memory: DirectMemoryRead? = null, + val array: PtArrayIndexer? = null, + val memory: PtMemoryByte? = null, val register: RegisterOrPair? = null, - val number: NumericLiteral? = null, - val expression: Expression? = null + val number: PtNumber? = null, + val expression: PtExpression? = null ) { val asmVarname: String get() = if(array==null) variableAsmName!! else - asmgen.asmVariableName(array.arrayvar) + asmgen.asmVariableName(array.variable) companion object { - fun fromAstSource(value: Expression, program: Program, asmgen: AsmGen): AsmAssignSource { - val cv = value.constValue(program) + fun fromAstSource(value: PtExpression, program: PtProgram, asmgen: AsmGen): AsmAssignSource { + val cv = value as? PtNumber if(cv!=null) return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv) return when(value) { - is NumericLiteral -> throw AssemblyError("should have been constant value") - is StringLiteral -> throw AssemblyError("string literal value should not occur anymore for asm generation") - is ArrayLiteral -> throw AssemblyError("array literal value should not occur anymore for asm generation") - is IdentifierReference -> { + is PtNumber -> throw AssemblyError("should have been constant value") + is PtString -> throw AssemblyError("string literal value should not occur anymore for asm generation") + is PtArray -> throw AssemblyError("array literal value should not occur anymore for asm generation") + is PtIdentifier -> { val parameter = value.targetVarDecl(program)?.subroutineParameter if(parameter!=null && parameter.definingSubroutine!!.isAsmSubroutine) throw AssemblyError("can't assign from a asmsub register parameter $value ${value.position}") - val dt = value.inferType(program).getOr(DataType.UNDEFINED) val varName=asmgen.asmVariableName(value) // special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system - if(dt == DataType.UWORD && varName.lowercase().startsWith("cx16.r")) { + if(value.type == DataType.UWORD && varName.lowercase().startsWith("cx16.r")) { val regStr = varName.lowercase().substring(5) val reg = RegisterOrPair.valueOf(regStr.uppercase()) - AsmAssignSource(SourceStorageKind.REGISTER, program, asmgen, dt, register = reg) + AsmAssignSource(SourceStorageKind.REGISTER, program, asmgen, value.type, register = reg) } else { - AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, dt, variableAsmName = varName) + AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, value.type, variableAsmName = varName) } } - is DirectMemoryRead -> { + is PtMemoryByte -> { AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value) } - is ArrayIndexedExpression -> { - val dt = value.inferType(program).getOrElse { throw AssemblyError("unknown dt") } - AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, dt, array = value) + is PtArrayIndexer -> { + AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, value.type, array = value) } - is BuiltinFunctionCall -> { - val returnType = value.inferType(program) - AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType.getOrElse { throw AssemblyError("unknown dt") }, expression = value) + is PtBuiltinFunctionCall -> { + AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, value.type, expression = value) } - is FunctionCallExpression -> { - val sub = value.target.targetSubroutine(program)!! + is PtFunctionCall -> { + val sub = value.targetSubroutine(program)!! val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first ?: throw AssemblyError("can't translate zero return values in assignment") AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value) } else -> { - val returnType = value.inferType(program) - AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType.getOrElse { throw AssemblyError("unknown dt") }, expression = value) + AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, value.type, expression = value) } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 5deb3deef..3e248e14d 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -1,24 +1,20 @@ package prog8.codegen.cpu6502.assignment -import prog8.ast.Program -import prog8.ast.expressions.* -import prog8.ast.statements.* +import prog8.code.ast.* import prog8.code.core.* -import prog8.codegen.cpu6502.AsmGen -import prog8.codegen.cpu6502.VariableAllocator -import prog8.compiler.builtinFunctionReturnType +import prog8.codegen.cpu6502.* -internal class AssignmentAsmGen(private val program: Program, +internal class AssignmentAsmGen(private val program: PtProgram, private val asmgen: AsmGen, private val allocator: VariableAllocator) { private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator) - fun translate(assignment: Assignment) { + fun translate(assignment: PtAssignment) { val target = AsmAssignTarget.fromAstAssignment(assignment, program, asmgen) val source = AsmAssignSource.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target) - val assign = AsmAssignment(source, target, assignment.isAugmentable, program.memsizer, assignment.position) + val assign = AsmAssignment(source, target, assignment.isInplaceAssign, program.memsizer, assignment.position) target.origAssign = assign if(assign.isAugmentable) @@ -64,17 +60,16 @@ internal class AssignmentAsmGen(private val program: Program, SourceStorageKind.ARRAY -> { val value = assign.source.array!! val elementDt = assign.source.datatype - val arrayVarName = asmgen.asmVariableName(value.arrayvar) + val arrayVarName = asmgen.asmVariableName(value.variable) - val arrayVarDecl = value.arrayvar.targetVarDecl(program)!! - if(arrayVarDecl.datatype==DataType.UWORD) { + if(value.variable.type==DataType.UWORD) { // indexing a pointer var instead of a real array or string if(elementDt !in ByteDatatypes) throw AssemblyError("non-array var indexing requires bytes dt") - if(value.inferType(program) isnot DataType.UBYTE) + if(value.type != DataType.UBYTE) throw AssemblyError("non-array var indexing requires bytes index") asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y) - if(asmgen.isZpVar(value.arrayvar)) { + if(asmgen.isZpVar(value.variable)) { asmgen.out(" lda ($arrayVarName),y") } else { asmgen.out(" lda $arrayVarName | sta P8ZP_SCRATCH_W1 | lda $arrayVarName+1 | sta P8ZP_SCRATCH_W1+1") @@ -84,7 +79,7 @@ internal class AssignmentAsmGen(private val program: Program, return } - val constIndex = value.indexer.constIndex() + val constIndex = value.index.asConstInteger() if (constIndex!=null) { // constant array index value val indexValue = constIndex * program.memsizer.memorySize(elementDt) @@ -133,29 +128,29 @@ internal class AssignmentAsmGen(private val program: Program, } } SourceStorageKind.MEMORY -> { - fun assignViaExprEval(expression: Expression) { + fun assignViaExprEval(expression: PtExpression) { assignExpressionToVariable(expression, "P8ZP_SCRATCH_W2", DataType.UWORD, assign.target.scope) asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2") assignRegisterByte(assign.target, CpuRegister.A) } val value = assign.source.memory!! - when (value.addressExpression) { - is NumericLiteral -> { - val address = (value.addressExpression as NumericLiteral).number.toUInt() + when (value.address) { + is PtNumber -> { + val address = (value.address as PtNumber).number.toUInt() assignMemoryByte(assign.target, address, null) } - is IdentifierReference -> { - assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference) + is PtIdentifier -> { + assignMemoryByte(assign.target, null, value.address as PtIdentifier) } - is BinaryExpression -> { - if(asmgen.tryOptimizedPointerAccessWithA(value.addressExpression as BinaryExpression, false)) { + is PtBinaryExpression -> { + if(asmgen.tryOptimizedPointerAccessWithA(value.address as PtBinaryExpression, false)) { assignRegisterByte(assign.target, CpuRegister.A) } else { - assignViaExprEval(value.addressExpression) + assignViaExprEval(value.address) } } - else -> assignViaExprEval(value.addressExpression) + else -> assignViaExprEval(value.address) } } SourceStorageKind.EXPRESSION -> { @@ -173,17 +168,17 @@ internal class AssignmentAsmGen(private val program: Program, private fun assignExpression(assign: AsmAssignment) { when(val value = assign.source.expression!!) { - is AddressOf -> { + is PtAddressOf -> { val sourceName = asmgen.asmSymbolName(value.identifier) assignAddressOf(assign.target, sourceName) } - is NumericLiteral -> throw AssemblyError("source kind should have been literalnumber") - is IdentifierReference -> throw AssemblyError("source kind should have been variable") - is ArrayIndexedExpression -> throw AssemblyError("source kind should have been array") - is DirectMemoryRead -> throw AssemblyError("source kind should have been memory") - is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, value) - is FunctionCallExpression -> { - val sub = value.target.targetSubroutine(program)!! + is PtNumber -> throw AssemblyError("source kind should have been literalnumber") + is PtIdentifier -> throw AssemblyError("source kind should have been variable") + is PtArrayIndexer -> throw AssemblyError("source kind should have been array") + is PtMemoryByte -> throw AssemblyError("source kind should have been memory") + is PtTypeCast -> assignTypeCastedValue(assign.target, value.type, value.value, value) + is PtFunctionCall -> { + val sub = value.targetSubroutine(program)!! asmgen.saveXbeforeCall(value) asmgen.translateFunctionCall(value, true) val returnValue = sub.returntypes.zip(sub.asmReturnvaluesRegisters).singleOrNull { it.second.registerOrPair!=null } ?: @@ -245,14 +240,11 @@ internal class AssignmentAsmGen(private val program: Program, } } } - is BuiltinFunctionCall -> { + is PtBuiltinFunctionCall -> { asmgen.translateBuiltinFunctionCallExpression(value, false, assign.target.register) if(assign.target.register==null) { // still need to assign the result to the target variable/etc. - val returntype = builtinFunctionReturnType(value.name) - if(!returntype.isKnown) - throw AssemblyError("unknown dt") - when(returntype.getOr(DataType.UNDEFINED)) { + when(builtinFunctionReturnType(value.name)) { in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A) // function's byte result is in A in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY DataType.STR -> { @@ -279,13 +271,13 @@ internal class AssignmentAsmGen(private val program: Program, } } } - is PrefixExpression -> { + is PtPrefix -> { if(assign.target.array==null) { // First assign the value to the target then apply the operator in place on the target. // This saves a temporary variable translateNormalAssignment( AsmAssignment( - AsmAssignSource.fromAstSource(value.expression, program, asmgen), + AsmAssignSource.fromAstSource(value.value, program, asmgen), assign.target, false, program.memsizer, assign.position ) @@ -301,11 +293,11 @@ internal class AssignmentAsmGen(private val program: Program, assignPrefixedExpressionToArrayElt(assign) } } - is ContainmentCheck -> { + is PtContainmentCheck -> { containmentCheckIntoA(value) assignRegisterByte(assign.target, CpuRegister.A) } - is BinaryExpression -> { + is PtBinaryExpression -> { 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, @@ -318,7 +310,7 @@ internal class AssignmentAsmGen(private val program: Program, } internal fun assignPrefixedExpressionToArrayElt(assign: AsmAssignment) { - require(assign.source.expression is PrefixExpression) + require(assign.source.expression is PtPrefix) if(assign.source.datatype==DataType.FLOAT) { // floatarray[x] = -value ... just use FAC1 to calculate the expression into and then store that back into the array. assignExpressionToRegister(assign.source.expression, RegisterOrPair.FAC1, true) @@ -350,9 +342,9 @@ internal class AssignmentAsmGen(private val program: Program, } } - private fun attemptAssignOptimizedBinexpr(expr: BinaryExpression, assign: AsmAssignment): Boolean { + private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { if(expr.operator in ComparisonOperators) { - if(expr.right.constValue(program)?.number == 0.0) { + if(expr.right.asConstInteger() == 0) { if(expr.operator == "==" || expr.operator=="!=") { when(assign.target.datatype) { in ByteDatatypes -> if(attemptAssignToByteCompareZero(expr, assign)) return true @@ -365,30 +357,36 @@ internal class AssignmentAsmGen(private val program: Program, val origTarget = assign.target.origAstTarget if(origTarget!=null) { assignConstantByte(assign.target, 0) - val assignTrue = AnonymousScope(mutableListOf( - Assignment(origTarget, NumericLiteral.fromBoolean(true, assign.position), AssignmentOrigin.ASMGEN, assign.position) - ), assign.position) - val assignFalse = AnonymousScope(mutableListOf(), assign.position) - val ifelse = IfElse(expr.copy(), assignTrue, assignFalse, assign.position) - ifelse.linkParents(expr) + val assignTrue = PtNodeGroup() + val assignment = PtAssignment(assign.position) + assignment.add(origTarget) + assignment.add(PtNumber.fromBoolean(true, assign.position)) + assignTrue.add(assignment) + val assignFalse = PtNodeGroup() + val ifelse = PtIfElse(assign.position) + val exprClone = arrayOf(expr).clone()[0] + require(exprClone !== expr) // TODO remove check if it works + ifelse.add(expr) + ifelse.add(assignTrue) + ifelse.add(assignFalse) asmgen.translate(ifelse) return true } } - if(!expr.inferType(program).isInteger) + if(expr.type !in IntegerDatatypes) return false fun simpleLogicalBytesExpr() { // both left and right expression operands are simple. - if (expr.right is NumericLiteral || expr.right is IdentifierReference) + if (expr.right is PtNumber || expr.right is PtIdentifier) assignLogicalWithSimpleRightOperandByte(assign.target, expr.left, expr.operator, expr.right) - else if (expr.left is NumericLiteral || expr.left is IdentifierReference) + else if (expr.left is PtNumber || expr.left is PtIdentifier) assignLogicalWithSimpleRightOperandByte(assign.target, expr.right, expr.operator, expr.left) else { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.saveRegisterStack(CpuRegister.A, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSub()) asmgen.restoreRegisterStack(CpuRegister.A, false) when (expr.operator) { "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1") @@ -402,15 +400,15 @@ internal class AssignmentAsmGen(private val program: Program, fun simpleLogicalWordsExpr() { // both left and right expression operands are simple. - if (expr.right is NumericLiteral || expr.right is IdentifierReference) + if (expr.right is PtNumber || expr.right is PtIdentifier) assignLogicalWithSimpleRightOperandWord(assign.target, expr.left, expr.operator, expr.right) - else if (expr.left is NumericLiteral || expr.left is IdentifierReference) + else if (expr.left is PtNumber || expr.left is PtIdentifier) assignLogicalWithSimpleRightOperandWord(assign.target, expr.right, expr.operator, expr.left) else { assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSubroutine) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSub()) when (expr.operator) { "&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1") "|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1") @@ -422,14 +420,14 @@ internal class AssignmentAsmGen(private val program: Program, } if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) { - if (expr.left.inferType(program).isBytes && expr.right.inferType(program).isBytes) { - if (expr.right.isSimple) { + if (expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) { + if (expr.right.isSimple()) { simpleLogicalBytesExpr() return true } } - if (expr.left.inferType(program).isWords && expr.right.inferType(program).isWords) { - if (expr.right.isSimple) { + if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + if (expr.right.isSimple()) { simpleLogicalWordsExpr() return true } @@ -439,11 +437,11 @@ internal class AssignmentAsmGen(private val program: Program, if(expr.operator == "==" || expr.operator == "!=") { // expression datatype is BOOL (ubyte) but operands can be anything - if(expr.left.inferType(program).isBytes && expr.right.inferType(program).isBytes && - expr.left.isSimple && expr.right.isSimple) { + if(expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes && + expr.left.isSimple() && expr.right.isSimple()) { assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.saveRegisterStack(CpuRegister.A, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSub()) asmgen.restoreRegisterStack(CpuRegister.A, false) if(expr.operator=="==") { asmgen.out(""" @@ -464,12 +462,12 @@ internal class AssignmentAsmGen(private val program: Program, } assignRegisterByte(assign.target, CpuRegister.A) return true - } else if(expr.left.inferType(program).isWords && expr.right.inferType(program).isWords && - expr.left.isSimple && expr.right.isSimple) { + } else if(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes && + expr.left.isSimple() && expr.right.isSimple()) { assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSubroutine) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSub()) asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.restoreRegisterStack(CpuRegister.A, false) if(expr.operator=="==") { @@ -499,12 +497,12 @@ internal class AssignmentAsmGen(private val program: Program, return false } else if(expr.operator=="+" || expr.operator=="-") { - val dt = expr.inferType(program).getOrElse { throw AssemblyError("invalid dt") } + val dt = expr.type val left = expr.left val right = expr.right if(dt in ByteDatatypes) { when (right) { - is IdentifierReference -> { + is PtIdentifier -> { assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) val symname = asmgen.asmVariableName(right) if(expr.operator=="+") @@ -514,7 +512,7 @@ internal class AssignmentAsmGen(private val program: Program, assignRegisterByte(assign.target, CpuRegister.A) return true } - is NumericLiteral -> { + is PtNumber -> { assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE) if(expr.operator=="+") asmgen.out(" clc | adc #${right.number.toHex()}") @@ -527,7 +525,7 @@ internal class AssignmentAsmGen(private val program: Program, } } else if(dt in WordDatatypes) { when (right) { - is AddressOf -> { + is PtAddressOf -> { assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) val symbol = asmgen.asmVariableName(right.identifier) if(expr.operator=="+") @@ -551,7 +549,7 @@ internal class AssignmentAsmGen(private val program: Program, assignRegisterpairWord(assign.target, RegisterOrPair.AY) return true } - is IdentifierReference -> { + is PtIdentifier -> { val symname = asmgen.asmVariableName(right) assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) if(expr.operator=="+") @@ -575,7 +573,7 @@ internal class AssignmentAsmGen(private val program: Program, assignRegisterpairWord(assign.target, RegisterOrPair.AY) return true } - is NumericLiteral -> { + is PtNumber -> { assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) if(expr.operator=="+") { asmgen.out(""" @@ -599,10 +597,10 @@ internal class AssignmentAsmGen(private val program: Program, assignRegisterpairWord(assign.target, RegisterOrPair.AY) return true } - is TypecastExpression -> { - val castedValue = right.expression - if(right.type in WordDatatypes && castedValue.inferType(program).isBytes) { - if(castedValue is IdentifierReference) { + is PtTypeCast -> { + val castedValue = right.value + if(right.type in WordDatatypes && castedValue.type in ByteDatatypes) { + if(castedValue is PtIdentifier) { val castedSymname = asmgen.asmVariableName(castedValue) assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) if(expr.operator=="+") @@ -629,11 +627,11 @@ internal class AssignmentAsmGen(private val program: Program, } } else if(expr.operator=="<<" || expr.operator==">>") { - val shifts = expr.right.constValue(program)?.number?.toInt() + val shifts = expr.right.asConstInteger() if(shifts!=null) { - val dt = expr.left.inferType(program) - if(dt.isBytes && shifts in 0..7) { - val signed = dt istype DataType.BYTE + val dt = expr.left.type + if(dt in ByteDatatypes && shifts in 0..7) { + val signed = dt == DataType.BYTE assignExpressionToRegister(expr.left, RegisterOrPair.A, signed) if(expr.operator=="<<") { repeat(shifts) { @@ -650,8 +648,8 @@ internal class AssignmentAsmGen(private val program: Program, } assignRegisterByte(assign.target, CpuRegister.A) return true - } else if(dt.isWords && shifts in 0..7) { - val signed = dt istype DataType.WORD + } else if(dt in WordDatatypes && shifts in 0..7) { + val signed = dt == DataType.WORD assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) if(expr.operator=="<<") { if(shifts>0) { @@ -683,11 +681,11 @@ internal class AssignmentAsmGen(private val program: Program, return false } - private fun assignLogicalWithSimpleRightOperandByte(target: AsmAssignTarget, left: Expression, operator: String, right: Expression) { + private fun assignLogicalWithSimpleRightOperandByte(target: AsmAssignTarget, left: PtExpression, operator: String, right: PtExpression) { assignExpressionToRegister(left, RegisterOrPair.A, false) val operand = when(right) { - is NumericLiteral -> "#${right.number.toHex()}" - is IdentifierReference -> asmgen.asmSymbolName(right) + is PtNumber -> "#${right.number.toHex()}" + is PtIdentifier -> asmgen.asmSymbolName(right) else -> throw AssemblyError("wrong right operand type") } when (operator) { @@ -699,10 +697,10 @@ internal class AssignmentAsmGen(private val program: Program, assignRegisterByte(target, CpuRegister.A) } - private fun assignLogicalWithSimpleRightOperandWord(target: AsmAssignTarget, left: Expression, operator: String, right: Expression) { + private fun assignLogicalWithSimpleRightOperandWord(target: AsmAssignTarget, left: PtExpression, operator: String, right: PtExpression) { assignExpressionToRegister(left, RegisterOrPair.AY, false) when(right) { - is NumericLiteral -> { + is PtNumber -> { val number = right.number.toHex() when (operator) { "&", "and" -> asmgen.out(" and #<$number | pha | tya | and #>$number | tay | pla") @@ -711,7 +709,7 @@ internal class AssignmentAsmGen(private val program: Program, else -> throw AssemblyError("invalid operator") } } - is IdentifierReference -> { + is PtIdentifier -> { val name = asmgen.asmSymbolName(right) when (operator) { "&", "and" -> asmgen.out(" and $name | pha | tya | and $name+1 | tay | pla") @@ -725,10 +723,10 @@ internal class AssignmentAsmGen(private val program: Program, assignRegisterpairWord(target, RegisterOrPair.AY) } - private fun attemptAssignToByteCompareZero(expr: BinaryExpression, assign: AsmAssignment): Boolean { + private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { when (expr.operator) { "==" -> { - when(val dt = expr.left.inferType(program).getOrElse { throw AssemblyError("invalid dt") }) { + when(val dt = expr.left.type) { in ByteDatatypes -> { assignExpressionToRegister(expr.left, RegisterOrPair.A, dt==DataType.BYTE) asmgen.out(""" @@ -765,7 +763,7 @@ internal class AssignmentAsmGen(private val program: Program, } } "!=" -> { - when(val dt = expr.left.inferType(program).getOrElse { throw AssemblyError("invalid dt") }) { + when(val dt = expr.left.type) { in ByteDatatypes -> { assignExpressionToRegister(expr.left, RegisterOrPair.A, dt==DataType.BYTE) asmgen.out(" beq + | lda #1") @@ -807,65 +805,20 @@ internal class AssignmentAsmGen(private val program: Program, assignStackValue(assign.target) } - private fun containmentCheckIntoA(containment: ContainmentCheck) { - val elementDt = containment.element.inferType(program) - val variable = (containment.iterable as? IdentifierReference)?.targetVarDecl(program) + private fun containmentCheckIntoA(containment: PtContainmentCheck) { + val elementDt = containment.element.type + val variable = (containment.iterable as? PtIdentifier)?.targetVarDecl(program) ?: throw AssemblyError("invalid containment iterable type") - if(variable.origin!=VarDeclOrigin.USERCODE) { - when(variable.datatype) { - DataType.STR -> { - require(elementDt.isBytes) { "must be byte string ${variable.position}" } - val stringVal = variable.value as StringLiteral - val varname = asmgen.asmVariableName(containment.iterable as IdentifierReference) - assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) - asmgen.restoreRegisterLocal(CpuRegister.A) - asmgen.out(" ldy #${stringVal.value.length}") - asmgen.out(" jsr prog8_lib.containment_bytearray") - return - } - DataType.ARRAY_F -> { - // require(elementDt istype DataType.FLOAT) - throw AssemblyError("containment check of floats not supported") - } - in ArrayDatatypes -> { - require(elementDt.isInteger) { "must be integer array ${variable.position}" } - val arrayVal = variable.value as ArrayLiteral - val dt = elementDt.getOr(DataType.UNDEFINED) - val varname = asmgen.asmVariableName(containment.iterable as IdentifierReference) - when(dt) { - in ByteDatatypes -> { - assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) - asmgen.restoreRegisterLocal(CpuRegister.A) - asmgen.out(" ldy #${arrayVal.value.size}") - asmgen.out(" jsr prog8_lib.containment_bytearray") - } - in WordDatatypes -> { - assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt.getOr(DataType.UNDEFINED), containment.definingSubroutine) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname) - asmgen.out(" ldy #${arrayVal.value.size}") - asmgen.out(" jsr prog8_lib.containment_wordarray") - } - else -> throw AssemblyError("invalid dt") - } - return - } - else -> throw AssemblyError("invalid dt") - } - } - val varname = asmgen.asmVariableName(containment.iterable as IdentifierReference) - when(variable.datatype) { + val varname = asmgen.asmVariableName(containment.iterable) + when(variable.type) { DataType.STR -> { // use subroutine - assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) + assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) + asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSub()!!) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSub(), "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) - val stringVal = variable.value as StringLiteral + val stringVal = variable.value as PtString asmgen.out(" ldy #${stringVal.value.length}") asmgen.out(" jsr prog8_lib.containment_bytearray") return @@ -874,19 +827,19 @@ internal class AssignmentAsmGen(private val program: Program, throw AssemblyError("containment check of floats not supported") } DataType.ARRAY_B, DataType.ARRAY_UB -> { - val numElements = variable.arraysize!!.constIndex()!! - assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname) + val numElements = variable.arraySize!! + assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) + asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSub()!!) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSub(), "P8ZP_SCRATCH_W1"), varname) asmgen.restoreRegisterLocal(CpuRegister.A) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_bytearray") return } DataType.ARRAY_W, DataType.ARRAY_UW -> { - val numElements = variable.arraysize!!.constIndex()!! - assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt.getOr(DataType.UNDEFINED), containment.definingSubroutine) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname) + val numElements = variable.arraySize!! + assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt, containment.definingSub()) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSub(), "P8ZP_SCRATCH_W2"), varname) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_wordarray") return @@ -913,14 +866,13 @@ internal class AssignmentAsmGen(private val program: Program, assignRegisterByte(target, CpuRegister.A) } - private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: Expression, origTypeCastExpression: TypecastExpression) { - val valueIDt = value.inferType(program) - val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") } + private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: PtExpression, origTypeCastExpression: PtTypeCast) { + val valueDt = value.type if(valueDt==targetDt) throw AssemblyError("type cast to identical dt should have been removed") when(value) { - is IdentifierReference -> { + is PtIdentifier -> { if(targetDt in WordDatatypes) { if(valueDt==DataType.UBYTE) { assignVariableUByteIntoWord(target, value) @@ -932,47 +884,47 @@ internal class AssignmentAsmGen(private val program: Program, } } } - is DirectMemoryRead -> { + is PtMemoryByte -> { if(targetDt in WordDatatypes) { - fun assignViaExprEval(addressExpression: Expression) { + fun assignViaExprEval(addressExpression: PtExpression) { asmgen.assignExpressionToVariable(addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD, null) asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2") asmgen.out(" ldy #0") assignRegisterpairWord(target, RegisterOrPair.AY) } - when (value.addressExpression) { - is NumericLiteral -> { - val address = (value.addressExpression as NumericLiteral).number.toUInt() + when (value.address) { + is PtNumber -> { + val address = (value.address as PtNumber).number.toUInt() assignMemoryByteIntoWord(target, address, null) } - is IdentifierReference -> { - assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference) + is PtIdentifier -> { + assignMemoryByteIntoWord(target, null, value.address as PtIdentifier) } - is BinaryExpression -> { - if(asmgen.tryOptimizedPointerAccessWithA(value.addressExpression as BinaryExpression, false)) { + is PtBinaryExpression -> { + if(asmgen.tryOptimizedPointerAccessWithA(value.address as PtBinaryExpression, false)) { asmgen.out(" ldy #0") assignRegisterpairWord(target, RegisterOrPair.AY) } else { - assignViaExprEval(value.addressExpression) + assignViaExprEval(value.address) } } else -> { - assignViaExprEval(value.addressExpression) + assignViaExprEval(value.address) } } return } } - is NumericLiteral -> throw AssemblyError("a cast of a literal value should have been const-folded away") + is PtNumber -> throw AssemblyError("a cast of a literal value should have been const-folded away") else -> {} } // special case optimizations if(target.kind == TargetStorageKind.VARIABLE) { - if(value is IdentifierReference && valueDt != DataType.UNDEFINED) + if(value is PtIdentifier && valueDt != DataType.UNDEFINED) return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt) when (valueDt) { @@ -998,7 +950,7 @@ internal class AssignmentAsmGen(private val program: Program, } if(valueDt in WordDatatypes && origTypeCastExpression.type == DataType.UBYTE) { - val parentTc = origTypeCastExpression.parent as? TypecastExpression + val parentTc = origTypeCastExpression.parent as? PtTypeCast if(parentTc!=null && parentTc.type==DataType.UWORD) { // typecast a word value to ubyte and directly back to uword // generate code for lsb(value) here instead of the ubyte typecast @@ -1111,25 +1063,25 @@ internal class AssignmentAsmGen(private val program: Program, when(valueDt) { DataType.UBYTE -> { assignExpressionToRegister(value, RegisterOrPair.Y, false) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSub()!!) asmgen.out(" jsr floats.FREADUY") asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.BYTE -> { assignExpressionToRegister(value, RegisterOrPair.A, true) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSub()!!) asmgen.out(" jsr floats.FREADSA") asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.UWORD -> { assignExpressionToRegister(value, RegisterOrPair.AY, false) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSub()!!) asmgen.out(" jsr floats.GIVUAYFAY") asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.WORD -> { assignExpressionToRegister(value, RegisterOrPair.AY, true) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!) + asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSub()!!) asmgen.out(" jsr floats.GIVAYFAY") asmgen.restoreRegisterLocal(CpuRegister.X) } @@ -1147,9 +1099,9 @@ internal class AssignmentAsmGen(private val program: Program, asmgen.assignExpressionTo(origTypeCastExpression, target) } - private fun assignCastViaLsbFunc(value: Expression, target: AsmAssignTarget) { - val lsb = BuiltinFunctionCall(IdentifierReference(listOf("lsb"), value.position), mutableListOf(value), value.position) - lsb.linkParents(value.parent) + private fun assignCastViaLsbFunc(value: PtExpression, target: AsmAssignTarget) { + val lsb = PtBuiltinFunctionCall("lsb", false, true, DataType.UBYTE, value.position) + lsb.add(value) val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb) val assign = AsmAssignment(src, target, false, program.memsizer, value.position) translateNormalAssignment(assign) @@ -1175,7 +1127,7 @@ internal class AssignmentAsmGen(private val program: Program, if(sourceDt == targetDt) throw AssemblyError("typecast to identical type") - // also see: ExpressionAsmGen, fun translateExpression(typecast: TypecastExpression) + // also see: PtExpressionAsmGen, fun translateExpression(typecast: PtTypeCast) when(sourceDt) { DataType.UBYTE -> { when(targetDt) { @@ -1290,7 +1242,7 @@ internal class AssignmentAsmGen(private val program: Program, if(sourceDt == targetDt) throw AssemblyError("typecast to identical type") - // also see: ExpressionAsmGen, fun translateExpression(typecast: TypecastExpression) + // also see: PtExpressionAsmGen, fun translateExpression(typecast: PtTypeCast) when(sourceDt) { DataType.UBYTE -> { when(targetDt) { @@ -1793,11 +1745,11 @@ internal class AssignmentAsmGen(private val program: Program, ldy #>${target.asmVarname} sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1""") - val constIndex = target.array!!.indexer.constIndex() + val constIndex = target.array!!.index.asConstInteger() if(constIndex!=null) { asmgen.out(" lda #$constIndex") } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) + val asmvarname = asmgen.asmVariableName(target.array.index as PtIdentifier) asmgen.out(" lda $asmvarname") } asmgen.out(" jsr floats.set_array_float_from_fac1") @@ -1829,11 +1781,11 @@ internal class AssignmentAsmGen(private val program: Program, ldy #>${target.asmVarname} sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1""") - val constIndex = target.array!!.indexer.constIndex() + val constIndex = target.array!!.index.asConstInteger() if(constIndex!=null) { asmgen.out(" lda #$constIndex") } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) + val asmvarname = asmgen.asmVariableName(target.array.index as PtIdentifier) asmgen.out(" lda $asmvarname") } asmgen.out(" jsr floats.set_array_float") @@ -1872,11 +1824,11 @@ internal class AssignmentAsmGen(private val program: Program, ldy #>${target.asmVarname} sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1""") - val constIndex = target.array!!.indexer.constIndex() + val constIndex = target.array!!.index.asConstInteger() if(constIndex!=null) { asmgen.out(" lda #$constIndex") } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) + val asmvarname = asmgen.asmVariableName(target.array.index as PtIdentifier) asmgen.out(" lda $asmvarname") } asmgen.out(" jsr floats.set_array_float") @@ -1906,14 +1858,14 @@ internal class AssignmentAsmGen(private val program: Program, storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { - if(target.origAstTarget?.arrayindexed?.arrayvar?.targetVarDecl(program)?.datatype==DataType.UWORD) { + if(target.origAstTarget?.array?.variable?.type==DataType.UWORD) { // assigning an indexed pointer var if (target.constArrayIndexValue==0u) { asmgen.out(" lda $sourceName") - asmgen.storeAIntoPointerVar(target.origAstTarget.arrayindexed!!.arrayvar) + asmgen.storeAIntoPointerVar(target.origAstTarget.array!!.variable) } else { asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UBYTE, CpuRegister.Y) - if (asmgen.isZpVar(target.origAstTarget.arrayindexed!!.arrayvar)) { + if (asmgen.isZpVar(target.origAstTarget.array!!.variable)) { asmgen.out(" lda $sourceName | sta (${target.asmVarname}),y") } else { asmgen.out(" lda ${target.asmVarname} | sta P8ZP_SCRATCH_W2 | lda ${target.asmVarname}+1 | sta P8ZP_SCRATCH_W2+1") @@ -1961,7 +1913,7 @@ internal class AssignmentAsmGen(private val program: Program, } } - private fun assignVariableByteIntoWord(wordtarget: AsmAssignTarget, bytevar: IdentifierReference) { + private fun assignVariableByteIntoWord(wordtarget: AsmAssignTarget, bytevar: PtIdentifier) { val sourceName = asmgen.asmVariableName(bytevar) when (wordtarget.kind) { TargetStorageKind.VARIABLE -> { @@ -2042,7 +1994,7 @@ internal class AssignmentAsmGen(private val program: Program, } } - private fun assignVariableUByteIntoWord(wordtarget: AsmAssignTarget, bytevar: IdentifierReference) { + private fun assignVariableUByteIntoWord(wordtarget: AsmAssignTarget, bytevar: PtIdentifier) { val sourceName = asmgen.asmVariableName(bytevar) when(wordtarget.kind) { TargetStorageKind.VARIABLE -> { @@ -2129,7 +2081,7 @@ internal class AssignmentAsmGen(private val program: Program, CpuRegister.X -> asmgen.out(" txa") CpuRegister.Y -> asmgen.out(" tya") } - val indexVar = target.array!!.indexer.indexExpr as IdentifierReference + val indexVar = target.array!!.index as PtIdentifier asmgen.out(" ldy ${asmgen.asmVariableName(indexVar)} | sta ${target.asmVarname},y") } } @@ -2448,14 +2400,14 @@ internal class AssignmentAsmGen(private val program: Program, storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { - if(target.origAstTarget?.arrayindexed?.arrayvar?.targetVarDecl(program)?.datatype==DataType.UWORD) { + if(target.origAstTarget?.array?.variable?.type==DataType.UWORD) { // assigning an indexed pointer var if (target.constArrayIndexValue==0u) { asmgen.out(" lda #0") - asmgen.storeAIntoPointerVar(target.origAstTarget.arrayindexed!!.arrayvar) + asmgen.storeAIntoPointerVar(target.origAstTarget.array!!.variable) } else { asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UBYTE, CpuRegister.Y) - if (asmgen.isZpVar(target.origAstTarget.arrayindexed!!.arrayvar)) { + if (asmgen.isZpVar(target.origAstTarget.array!!.variable)) { asmgen.out(" lda #0 | sta (${target.asmVarname}),y") } else { asmgen.out(" lda ${target.asmVarname} | sta P8ZP_SCRATCH_W2 | lda ${target.asmVarname}+1 | sta P8ZP_SCRATCH_W2+1") @@ -2504,14 +2456,14 @@ internal class AssignmentAsmGen(private val program: Program, storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { - if(target.origAstTarget?.arrayindexed?.arrayvar?.targetVarDecl(program)?.datatype==DataType.UWORD) { + if(target.origAstTarget?.array?.variable?.type==DataType.UWORD) { // assigning an indexed pointer var if (target.constArrayIndexValue==0u) { asmgen.out(" lda #${byte.toHex()}") - asmgen.storeAIntoPointerVar(target.origAstTarget.arrayindexed!!.arrayvar) + asmgen.storeAIntoPointerVar(target.origAstTarget.array!!.variable) } else { asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UBYTE, CpuRegister.Y) - if (asmgen.isZpVar(target.origAstTarget.arrayindexed!!.arrayvar)) { + if (asmgen.isZpVar(target.origAstTarget.array!!.variable)) { asmgen.out(" lda #${byte.toHex()} | sta (${target.asmVarname}),y") } else { asmgen.out(" lda ${target.asmVarname} | sta P8ZP_SCRATCH_W2 | lda ${target.asmVarname}+1 | sta P8ZP_SCRATCH_W2+1") @@ -2585,7 +2537,7 @@ internal class AssignmentAsmGen(private val program: Program, """) } TargetStorageKind.ARRAY -> { - val constIndex = target.array!!.indexer.constIndex() + val constIndex = target.array!!.index.asConstInteger() if (constIndex!=null) { val indexValue = constIndex * program.memsizer.memorySize(DataType.FLOAT) if(asmgen.isTargetCpu(CpuType.CPU65c02)) @@ -2606,7 +2558,7 @@ internal class AssignmentAsmGen(private val program: Program, sta ${target.asmVarname}+$indexValue+4 """) } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) + val asmvarname = asmgen.asmVariableName(target.array.index as PtIdentifier) asmgen.out(""" lda #<${target.asmVarname} sta P8ZP_SCRATCH_W1 @@ -2647,7 +2599,7 @@ internal class AssignmentAsmGen(private val program: Program, } TargetStorageKind.ARRAY -> { val arrayVarName = target.asmVarname - val constIndex = target.array!!.indexer.constIndex() + val constIndex = target.array!!.index.asConstInteger() if (constIndex!=null) { val indexValue = constIndex * program.memsizer.memorySize(DataType.FLOAT) asmgen.out(""" @@ -2659,7 +2611,7 @@ internal class AssignmentAsmGen(private val program: Program, ldy #>($arrayVarName+$indexValue) jsr floats.copy_float""") } else { - val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference) + val asmvarname = asmgen.asmVariableName(target.array.index as PtIdentifier) asmgen.out(""" lda #<${constFloat} sta P8ZP_SCRATCH_W1 @@ -2691,7 +2643,7 @@ internal class AssignmentAsmGen(private val program: Program, } } - private fun assignMemoryByte(target: AsmAssignTarget, address: UInt?, identifier: IdentifierReference?) { + private fun assignMemoryByte(target: AsmAssignTarget, address: UInt?, identifier: PtIdentifier?) { if (address != null) { when(target.kind) { TargetStorageKind.VARIABLE -> { @@ -2775,7 +2727,7 @@ internal class AssignmentAsmGen(private val program: Program, } } - private fun assignMemoryByteIntoWord(wordtarget: AsmAssignTarget, address: UInt?, identifier: IdentifierReference?) { + private fun assignMemoryByteIntoWord(wordtarget: AsmAssignTarget, address: UInt?, identifier: PtIdentifier?) { if (address != null) { when(wordtarget.kind) { TargetStorageKind.VARIABLE -> { @@ -2838,13 +2790,13 @@ internal class AssignmentAsmGen(private val program: Program, } } - private fun storeRegisterAInMemoryAddress(memoryAddress: DirectMemoryWrite) { - val addressExpr = memoryAddress.addressExpression - val addressLv = addressExpr as? NumericLiteral + private fun storeRegisterAInMemoryAddress(memoryAddress: PtMemoryByte) { + val addressExpr = memoryAddress.address + val addressLv = addressExpr as? PtNumber fun storeViaExprEval() { when(addressExpr) { - is NumericLiteral, is IdentifierReference -> { + is PtNumber, is PtIdentifier -> { assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD, null) asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2") } @@ -2862,10 +2814,10 @@ internal class AssignmentAsmGen(private val program: Program, addressLv != null -> { asmgen.out(" sta ${addressLv.number.toHex()}") } - addressExpr is IdentifierReference -> { + addressExpr is PtIdentifier -> { asmgen.storeAIntoPointerVar(addressExpr) } - addressExpr is BinaryExpression -> { + addressExpr is PtBinaryExpression -> { if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, true)) storeViaExprEval() } @@ -2873,15 +2825,15 @@ internal class AssignmentAsmGen(private val program: Program, } } - internal fun assignExpressionToRegister(expr: Expression, register: RegisterOrPair, signed: Boolean) { + internal fun assignExpressionToRegister(expr: PtExpression, register: RegisterOrPair, signed: Boolean) { val src = AsmAssignSource.fromAstSource(expr, program, asmgen) val tgt = AsmAssignTarget.fromRegisters(register, signed, null, asmgen) val assign = AsmAssignment(src, tgt, false, program.memsizer, expr.position) translateNormalAssignment(assign) } - internal fun assignExpressionToVariable(expr: Expression, asmVarName: String, dt: DataType, scope: Subroutine?) { - if(expr.inferType(program) istype DataType.FLOAT && dt!=DataType.FLOAT) { + internal fun assignExpressionToVariable(expr: PtExpression, asmVarName: String, dt: DataType, scope: IPtSubroutine?) { + if(expr.type==DataType.FLOAT && dt!=DataType.FLOAT) { throw AssemblyError("can't directly assign a FLOAT expression to an integer variable $expr") } else { val src = AsmAssignSource.fromAstSource(expr, program, asmgen) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index e185bf326..9c0ade365 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -1,15 +1,12 @@ package prog8.codegen.cpu6502.assignment -import prog8.ast.Program -import prog8.ast.base.FatalAstException -import prog8.ast.expressions.* -import prog8.ast.statements.Subroutine +import prog8.code.ast.* import prog8.code.core.* import prog8.codegen.cpu6502.AsmGen import prog8.codegen.cpu6502.VariableAllocator -internal class AugmentableAssignmentAsmGen(private val program: Program, +internal class AugmentableAssignmentAsmGen(private val program: PtProgram, private val assignmentAsmGen: AssignmentAsmGen, private val asmgen: AsmGen, private val allocator: VariableAllocator @@ -21,7 +18,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } when (val value = assign.source.expression!!) { - is PrefixExpression -> { + is PtPrefix -> { // A = -A , A = +A, A = ~A, A = not A when (value.operator) { "+" -> {} @@ -30,13 +27,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, else -> throw AssemblyError("invalid prefix operator") } } - is TypecastExpression -> inplaceCast(assign.target, value, assign.position) - is BinaryExpression -> inplaceBinary(assign.target, value) + is PtTypeCast -> inplaceCast(assign.target, value, assign.position) + is PtBinaryExpression -> inplaceBinary(assign.target, value) else -> throw AssemblyError("invalid aug assign value type") } } - private fun inplaceBinary(target: AsmAssignTarget, binExpr: BinaryExpression) { + private fun inplaceBinary(target: AsmAssignTarget, binExpr: PtBinaryExpression) { val astTarget = target.origAstTarget!! if (binExpr.left isSameAs astTarget) { // A = A Something @@ -49,7 +46,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, return inplaceModification(target, binExpr.operator, binExpr.left) } - val leftBinExpr = binExpr.left as? BinaryExpression + val leftBinExpr = binExpr.left as? PtBinaryExpression if (leftBinExpr?.operator == binExpr.operator) { // TODO better optimize the chained asm to avoid intermediate stores/loads? when { @@ -73,7 +70,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } } - val rightBinExpr = binExpr.right as? BinaryExpression + val rightBinExpr = binExpr.right as? PtBinaryExpression if (rightBinExpr?.operator == binExpr.operator) { when { binExpr.left isSameAs astTarget -> { @@ -98,8 +95,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - val leftBinExpr = binExpr.left as? BinaryExpression - val rightBinExpr = binExpr.right as? BinaryExpression + val leftBinExpr = binExpr.left as? PtBinaryExpression + val rightBinExpr = binExpr.right as? PtBinaryExpression if(leftBinExpr!=null && rightBinExpr==null) { if(leftBinExpr.left isSameAs astTarget) { // X = (X Right) Something @@ -141,26 +138,26 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - throw FatalAstException("assignment should follow augmentable rules $binExpr") + throw AssemblyError("assignment should follow augmentable rules $binExpr") } - private fun inplaceModification(target: AsmAssignTarget, operator: String, origValue: Expression) { + private fun inplaceModification(target: AsmAssignTarget, operator: String, origValue: PtExpression) { // the asm-gen code can deal with situations where you want to assign a byte into a word. // it will create the most optimized code to do this (so it type-extends for us). // But we can't deal with writing a word into a byte - explicit typeconversion is required - val value = if(program.memsizer.memorySize(origValue.inferType(program).getOrElse { throw AssemblyError("unknown dt") }) > program.memsizer.memorySize(target.datatype)) { - val typecast = TypecastExpression(origValue, target.datatype, true, origValue.position) - typecast.linkParents(origValue.parent) + val value = if(program.memsizer.memorySize(origValue.type) > program.memsizer.memorySize(target.datatype)) { + val typecast = PtTypeCast(target.datatype, origValue.position) + typecast.add(origValue) typecast } else { origValue } - val valueLv = (value as? NumericLiteral)?.number - val ident = value as? IdentifierReference - val memread = value as? DirectMemoryRead + val valueLv = (value as? PtNumber)?.number + val ident = value as? PtIdentifier + val memread = value as? PtMemoryByte when (target.kind) { TargetStorageKind.VARIABLE -> { @@ -170,7 +167,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, valueLv != null -> inplaceModification_byte_litval_to_variable(target.asmVarname, target.datatype, operator, valueLv.toInt()) ident != null -> inplaceModification_byte_variable_to_variable(target.asmVarname, target.datatype, operator, ident) memread != null -> inplaceModification_byte_memread_to_variable(target.asmVarname, target.datatype, operator, memread) - value is TypecastExpression -> { + value is PtTypeCast -> { if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return inplaceModification_byte_value_to_variable(target.asmVarname, target.datatype, operator, value) } @@ -182,7 +179,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, valueLv != null -> inplaceModification_word_litval_to_variable(target.asmVarname, target.datatype, operator, valueLv.toInt()) ident != null -> inplaceModification_word_variable_to_variable(target.asmVarname, target.datatype, operator, ident) memread != null -> inplaceModification_word_memread_to_variable(target.asmVarname, target.datatype, operator, memread) - value is TypecastExpression -> { + value is PtTypeCast -> { if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return inplaceModification_word_value_to_variable(target.asmVarname, target.datatype, operator, value) @@ -194,7 +191,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, when { valueLv != null -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, valueLv.toDouble(), target.scope!!) ident != null -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, ident, target.scope!!) - value is TypecastExpression -> { + value is PtTypeCast -> { if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope!!) } @@ -206,27 +203,27 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } TargetStorageKind.MEMORY -> { val memory = target.memory!! - when (memory.addressExpression) { - is NumericLiteral -> { - val addr = (memory.addressExpression as NumericLiteral).number.toInt() + when (memory.address) { + is PtNumber -> { + val addr = (memory.address as PtNumber).number.toInt() // re-use code to assign a variable, instead this time, use a direct memory address when { valueLv != null -> inplaceModification_byte_litval_to_variable(addr.toHex(), DataType.UBYTE, operator, valueLv.toInt()) ident != null -> inplaceModification_byte_variable_to_variable(addr.toHex(), DataType.UBYTE, operator, ident) memread != null -> inplaceModification_byte_memread_to_variable(addr.toHex(), DataType.UBYTE, operator, value) - value is TypecastExpression -> { + value is PtTypeCast -> { if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value) } else -> inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value) } } - is IdentifierReference -> { - val pointer = memory.addressExpression as IdentifierReference + is PtIdentifier -> { + val pointer = memory.address as PtIdentifier when { valueLv != null -> inplaceModification_byte_litval_to_pointer(pointer, operator, valueLv.toInt()) ident != null -> inplaceModification_byte_variable_to_pointer(pointer, operator, ident) - value is TypecastExpression -> { + value is PtTypeCast -> { if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return inplaceModification_byte_value_to_pointer(pointer, operator, value) } @@ -235,13 +232,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } else -> { // TODO use some other evaluation here; don't use the estack to transfer the address to read/write from - asmgen.assignExpressionTo(memory.addressExpression, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingSubroutine)) + asmgen.assignExpressionTo(memory.address, AsmAssignTarget(TargetStorageKind.STACK, asmgen, DataType.UWORD, memory.definingSub())) asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1") when { valueLv != null -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, valueLv.toInt()) ident != null -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, ident) memread != null -> inplaceModification_byte_memread_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, memread) - value is TypecastExpression -> { + value is PtTypeCast -> { if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return inplaceModification_byte_value_to_variable("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value) } @@ -252,91 +249,89 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } TargetStorageKind.ARRAY -> { - with(target.array!!.indexer) { - val indexNum = indexExpr as? NumericLiteral - val indexVar = indexExpr as? IdentifierReference - when { - indexNum!=null -> { - val targetVarName = "${target.asmVarname} + ${indexNum.number.toInt()*program.memsizer.memorySize(target.datatype)}" - when (target.datatype) { - in ByteDatatypes -> { - when { - valueLv != null -> inplaceModification_byte_litval_to_variable(targetVarName, target.datatype, operator, valueLv.toInt()) - ident != null -> inplaceModification_byte_variable_to_variable(targetVarName, target.datatype, operator, ident) - memread != null -> inplaceModification_byte_memread_to_variable(targetVarName, target.datatype, operator, memread) - value is TypecastExpression -> { - if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return - inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value) - } - else -> inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value) + val indexNum = target.array!!.index as? PtNumber + val indexVar = target.array.index as? PtIdentifier + when { + indexNum!=null -> { + val targetVarName = "${target.asmVarname} + ${indexNum.number.toInt()*program.memsizer.memorySize(target.datatype)}" + when (target.datatype) { + in ByteDatatypes -> { + when { + valueLv != null -> inplaceModification_byte_litval_to_variable(targetVarName, target.datatype, operator, valueLv.toInt()) + ident != null -> inplaceModification_byte_variable_to_variable(targetVarName, target.datatype, operator, ident) + memread != null -> inplaceModification_byte_memread_to_variable(targetVarName, target.datatype, operator, memread) + value is PtTypeCast -> { + if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return + inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value) } + else -> inplaceModification_byte_value_to_variable(targetVarName, target.datatype, operator, value) } - in WordDatatypes -> { - when { - valueLv != null -> inplaceModification_word_litval_to_variable(targetVarName, target.datatype, operator, valueLv.toInt()) - ident != null -> inplaceModification_word_variable_to_variable(targetVarName, target.datatype, operator, ident) - memread != null -> inplaceModification_word_memread_to_variable(targetVarName, target.datatype, operator, memread) - value is TypecastExpression -> { - if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return - inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value) - } - else -> inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value) - } - } - DataType.FLOAT -> { - when { - valueLv != null -> inplaceModification_float_litval_to_variable(targetVarName, operator, valueLv.toDouble(), target.scope!!) - ident != null -> inplaceModification_float_variable_to_variable(targetVarName, operator, ident, target.scope!!) - value is TypecastExpression -> { - if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return - inplaceModification_float_value_to_variable(targetVarName, operator, value, target.scope!!) - } - else -> inplaceModification_float_value_to_variable(targetVarName, operator, value, target.scope!!) - } - } - else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") } - } - indexVar!=null -> { - when (target.datatype) { - in ByteDatatypes -> { - val tgt = - AsmAssignTarget.fromRegisters( - RegisterOrPair.A, - target.datatype == DataType.BYTE, null, - asmgen - ) - val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) - assignmentAsmGen.translateNormalAssignment(assign) - assignmentAsmGen.assignRegisterByte(target, CpuRegister.A) + in WordDatatypes -> { + when { + valueLv != null -> inplaceModification_word_litval_to_variable(targetVarName, target.datatype, operator, valueLv.toInt()) + ident != null -> inplaceModification_word_variable_to_variable(targetVarName, target.datatype, operator, ident) + memread != null -> inplaceModification_word_memread_to_variable(targetVarName, target.datatype, operator, memread) + value is PtTypeCast -> { + if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return + inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value) + } + else -> inplaceModification_word_value_to_variable(targetVarName, target.datatype, operator, value) } - in WordDatatypes -> { - val tgt = - AsmAssignTarget.fromRegisters( - RegisterOrPair.AY, - target.datatype == DataType.WORD, null, - asmgen - ) - val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) - assignmentAsmGen.translateNormalAssignment(assign) - assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY) - } - DataType.FLOAT -> { - val tgt = - AsmAssignTarget.fromRegisters( - RegisterOrPair.FAC1, - true, null, - asmgen - ) - val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) - assignmentAsmGen.translateNormalAssignment(assign) - assignmentAsmGen.assignFAC1float(target) - } - else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") } + DataType.FLOAT -> { + when { + valueLv != null -> inplaceModification_float_litval_to_variable(targetVarName, operator, valueLv.toDouble(), target.scope!!) + ident != null -> inplaceModification_float_variable_to_variable(targetVarName, operator, ident, target.scope!!) + value is PtTypeCast -> { + if (tryInplaceModifyWithRemovedRedundantCast(value, target, operator)) return + inplaceModification_float_value_to_variable(targetVarName, operator, value, target.scope!!) + } + else -> inplaceModification_float_value_to_variable(targetVarName, operator, value, target.scope!!) + } + } + else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") } - else -> throw AssemblyError("indexer expression should have been replaced by auto indexer var") } + indexVar!=null -> { + when (target.datatype) { + in ByteDatatypes -> { + val tgt = + AsmAssignTarget.fromRegisters( + RegisterOrPair.A, + target.datatype == DataType.BYTE, null, + asmgen + ) + val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) + assignmentAsmGen.translateNormalAssignment(assign) + assignmentAsmGen.assignRegisterByte(target, CpuRegister.A) + } + in WordDatatypes -> { + val tgt = + AsmAssignTarget.fromRegisters( + RegisterOrPair.AY, + target.datatype == DataType.WORD, null, + asmgen + ) + val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) + assignmentAsmGen.translateNormalAssignment(assign) + assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY) + } + DataType.FLOAT -> { + val tgt = + AsmAssignTarget.fromRegisters( + RegisterOrPair.FAC1, + true, null, + asmgen + ) + val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position) + assignmentAsmGen.translateNormalAssignment(assign) + assignmentAsmGen.assignFAC1float(target) + } + else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") + } + } + else -> throw AssemblyError("indexer expression should have been replaced by auto indexer var") } } TargetStorageKind.REGISTER -> throw AssemblyError("no asm gen for reg in-place modification") @@ -344,21 +339,20 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - private fun tryInplaceModifyWithRemovedRedundantCast(value: TypecastExpression, target: AsmAssignTarget, operator: String): Boolean { + private fun tryInplaceModifyWithRemovedRedundantCast(value: PtTypeCast, target: AsmAssignTarget, operator: String): Boolean { if (target.datatype == value.type) { - val childIDt = value.expression.inferType(program) - val childDt = childIDt.getOrElse { throw AssemblyError("unknown dt") } + val childDt = value.value.type if (value.type!=DataType.FLOAT && (value.type.equalsSize(childDt) || value.type.largerThan(childDt))) { // this typecast is redundant here; the rest of the code knows how to deal with the uncasted value. // (works for integer types, not for float.) - inplaceModification(target, operator, value.expression) + inplaceModification(target, operator, value.value) return true } } return false } - private fun inplaceModification_byte_value_to_pointer(pointervar: IdentifierReference, operator: String, value: Expression) { + private fun inplaceModification_byte_value_to_pointer(pointervar: PtIdentifier, operator: String, value: PtExpression) { asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.UBYTE, null) val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) when (operator) { @@ -394,7 +388,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.storeAIntoZpPointerVar(sourceName) } - private fun inplaceModification_byte_variable_to_pointer(pointervar: IdentifierReference, operator: String, value: IdentifierReference) { + private fun inplaceModification_byte_variable_to_pointer(pointervar: PtIdentifier, operator: String, value: PtIdentifier) { val otherName = asmgen.asmVariableName(value) val sourceName = asmgen.loadByteFromPointerIntoA(pointervar) @@ -431,7 +425,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.storeAIntoZpPointerVar(sourceName) } - private fun inplaceModification_byte_litval_to_pointer(pointervar: IdentifierReference, operator: String, value: Int) { + private fun inplaceModification_byte_litval_to_pointer(pointervar: PtIdentifier, operator: String, value: Int) { when (operator) { // note: ** (power) operator requires floats. "+" -> { @@ -499,7 +493,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - private fun inplaceModification_byte_value_to_variable(name: String, dt: DataType, operator: String, value: Expression) { + private fun inplaceModification_byte_value_to_variable(name: String, dt: DataType, operator: String, value: PtExpression) { // this should be the last resort for code generation for this, // because the value is evaluated onto the eval stack (=slow). when (operator) { @@ -594,7 +588,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - private fun inplaceModification_byte_variable_to_variable(name: String, dt: DataType, operator: String, ident: IdentifierReference) { + private fun inplaceModification_byte_variable_to_variable(name: String, dt: DataType, operator: String, ident: PtIdentifier) { val otherName = asmgen.asmVariableName(ident) when (operator) { // note: ** (power) operator requires floats. @@ -762,7 +756,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - private fun inplaceModification_byte_memread_to_variable(name: String, dt: DataType, operator: String, memread: DirectMemoryRead) { + private fun inplaceModification_byte_memread_to_variable(name: String, dt: DataType, operator: String, memread: PtMemoryByte) { when (operator) { "+" -> { asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) @@ -799,7 +793,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - private fun inplaceModification_word_memread_to_variable(name: String, dt: DataType, operator: String, memread: DirectMemoryRead) { + private fun inplaceModification_word_memread_to_variable(name: String, dt: DataType, operator: String, memread: PtMemoryByte) { when (operator) { "+" -> { asmgen.translateDirectMemReadExpressionToRegAorStack(memread, false) @@ -1111,9 +1105,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - private fun inplaceModification_word_variable_to_variable(name: String, dt: DataType, operator: String, ident: IdentifierReference) { + private fun inplaceModification_word_variable_to_variable(name: String, dt: DataType, operator: String, ident: PtIdentifier) { val otherName = asmgen.asmVariableName(ident) - when (val valueDt = ident.targetVarDecl(program)!!.datatype) { + when (val valueDt = ident.type) { in ByteDatatypes -> { // the other variable is a BYTE type so optimize for that when (operator) { @@ -1356,12 +1350,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - private fun inplaceModification_word_value_to_variable(name: String, dt: DataType, operator: String, value: Expression) { + private fun inplaceModification_word_value_to_variable(name: String, dt: DataType, operator: String, value: PtExpression) { // this should be the last resort for code generation for this, // because the value is evaluated onto the eval stack (=slow). - val valueiDt = value.inferType(program) - val valueDt = valueiDt.getOrElse { throw AssemblyError("unknown dt") } fun multiplyVarByWordInAY() { asmgen.out(""" @@ -1410,7 +1402,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, """) } - when (valueDt) { + when (val valueDt = value.type) { in ByteDatatypes -> { // the other variable is a BYTE type so optimize for that when (operator) { @@ -1581,7 +1573,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } - private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression, scope: Subroutine) { + private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression, scope: PtSub) { asmgen.assignExpressionToRegister(value, RegisterOrPair.FAC1) asmgen.saveRegisterLocal(CpuRegister.X, scope) when (operator) { @@ -1623,8 +1615,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference, scope: Subroutine) { - val valueDt = ident.targetVarDecl(program)!!.datatype + private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: PtIdentifier, scope: PtSub) { + val valueDt = ident.type if(valueDt != DataType.FLOAT) throw AssemblyError("float variable expected") @@ -1682,7 +1674,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: Subroutine) { + private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: PtSub) { val constValueName = allocator.getFloatAsmConst(value) asmgen.saveRegisterLocal(CpuRegister.X, scope) when (operator) { @@ -1744,9 +1736,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceCast(target: AsmAssignTarget, cast: TypecastExpression, position: Position) { + private fun inplaceCast(target: AsmAssignTarget, cast: PtTypeCast, position: Position) { val outerCastDt = cast.type - val innerCastDt = (cast.expression as? TypecastExpression)?.type + val innerCastDt = (cast.value as? PtTypeCast)?.type if (innerCastDt == null) { // simple typecast where the value is the target when (target.datatype) { @@ -1789,8 +1781,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, // typecast with nested typecast, that has the target as a value // calculate singular cast that is required val castDt = if (outerCastDt largerThan innerCastDt) innerCastDt else outerCastDt - val value = (cast.expression as TypecastExpression).expression - val resultingCast = TypecastExpression(value, castDt, false, position) + val resultingCast = PtTypeCast(castDt, position) + resultingCast.add((cast.value as PtTypeCast).value) inplaceCast(target, resultingCast, position) } } @@ -1808,21 +1800,21 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } TargetStorageKind.MEMORY -> { val memory = target.memory!! - when (memory.addressExpression) { - is NumericLiteral -> { - val addr = (memory.addressExpression as NumericLiteral).number.toHex() + when (memory.address) { + is PtNumber -> { + val addr = (memory.address as PtNumber).number.toHex() asmgen.out(""" lda $addr eor #255 sta $addr""") } - is IdentifierReference -> { - val sourceName = asmgen.loadByteFromPointerIntoA(memory.addressExpression as IdentifierReference) + is PtIdentifier -> { + val sourceName = asmgen.loadByteFromPointerIntoA(memory.address as PtIdentifier) asmgen.out(" eor #255") asmgen.out(" sta ($sourceName),y") } else -> { - asmgen.assignExpressionToVariable(memory.addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD, target.scope) + asmgen.assignExpressionToVariable(memory.address, "P8ZP_SCRATCH_W2", DataType.UWORD, target.scope) asmgen.out(""" ldy #0 lda (P8ZP_SCRATCH_W2),y diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 2e7769e16..84cc673d4 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -445,18 +445,13 @@ internal fun asmGeneratorFor(program: Program, symbolTable: SymbolTable, options: CompilationOptions): IAssemblyGenerator { - if(options.experimentalCodegen) { - val intermediateAst = IntermediateAstMaker(program, symbolTable, options).transform() + val intermediateAst = IntermediateAstMaker(program, symbolTable, options).transform() + if(options.experimentalCodegen) return prog8.codegen.experimental.CodeGen(intermediateAst, symbolTable, options, errors) - } else { - if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) - // TODO rewrite 6502 codegen on new Intermediary Ast or on new Intermediate Representation - return prog8.codegen.cpu6502.AsmGen(program, symbolTable, options, errors) - if (options.compTarget.name == VMTarget.NAME) { - val intermediateAst = IntermediateAstMaker(program, symbolTable, options).transform() - return VmCodeGen(intermediateAst, symbolTable, options, errors) - } - } - - throw NotImplementedError("no asm generator for cpu ${options.compTarget.machine.cpu}") + else if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) + return prog8.codegen.cpu6502.AsmGen(intermediateAst, symbolTable, options, errors) + else if (options.compTarget.name == VMTarget.NAME) + return VmCodeGen(intermediateAst, symbolTable, options, errors) + else + throw NotImplementedError("no asm generator for cpu ${options.compTarget.machine.cpu}") } diff --git a/compilerAst/src/prog8/ast/Program.kt b/compilerAst/src/prog8/ast/Program.kt index 0460d914b..b4a380496 100644 --- a/compilerAst/src/prog8/ast/Program.kt +++ b/compilerAst/src/prog8/ast/Program.kt @@ -147,7 +147,7 @@ class Program(val name: String, fun makeLabel(postfix: String): String { generatedLabelSequenceNumber++ - return "${generatedLabelPrefix}${generatedLabelSequenceNumber}_$postfix" + return "prog8_label_${generatedLabelSequenceNumber}_$postfix" } fun makeLabel(postfix: String, position: Position): Label { @@ -160,6 +160,3 @@ class Program(val name: String, return Jump(null, ident, null, label.position) } } - - -const val generatedLabelPrefix = "prog8_label_" diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index f591555e4..a0402e0ff 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -741,23 +741,6 @@ class Subroutine(override val name: String, override fun toString() = "Subroutine(name=$name, parameters=$parameters, returntypes=$returntypes, ${statements.size} statements, address=$asmAddress)" - fun regXasResult() = asmReturnvaluesRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } - fun regXasParam() = asmParameterRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } - fun shouldSaveX() = CpuRegister.X in asmClobbers || regXasResult() || regXasParam() - - class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean) - - fun shouldKeepA(): KeepAresult { - // determine if A's value should be kept when preparing for calling the subroutine, and when returning from it - if(!isAsmSubroutine) - return KeepAresult(saveOnEntry = false, saveOnReturn = false) - - // it seems that we never have to save A when calling? will be loaded correctly after setup. - // but on return it depends on wether the routine returns something in A. - val saveAonReturn = asmReturnvaluesRegisters.any { it.registerOrPair==RegisterOrPair.A || it.registerOrPair==RegisterOrPair.AY || it.registerOrPair==RegisterOrPair.AX } - return KeepAresult(false, saveAonReturn) - } - // code to provide the ability to reference asmsub parameters via qualified name: private val asmParamsDecls = mutableMapOf() diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 643be61b3..01c5cffad 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -17,11 +17,9 @@ For 9.0 major changes - OR.... make all this more generic and use some %segment option to create real segments for 64tass? - (need separate step in codegen and IR to write the "golden" variables) -- rewrite 6502 codegen on Pt* ast and symboltable, instead of CompilerAst nodes. (work in codegen-on-new-ast branch) +- rewrite 6502 codegen on Pt* ast and symboltable, instead of CompilerAst nodes. - optimize "dotted string" comments again. -- update to kotlin 1.8.0 once it is available in IDEA - Need help with ^^^^^^^^^^^^^^ @@ -44,7 +42,7 @@ Compiler: - ir: peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out! and don't renumber registers above SyscallRegisterBase!) - ir: add more optimizations in IRPeepholeOptimizer - ir: for expressions with array indexes that occur multiple times, can we avoid loading them into new virtualregs everytime and just reuse a single virtualreg as indexer? -- vm: somehow be able to load a label address as value? (VmProgramLoader) +- vm: somehow be able to load a label address as value? (VmProgramLoader) this may require storing the program in actual memory bytes though... - 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition. It is documented behavior to now loop 'around' $00 but it's too easy to forget about! Lot of work because of so many special cases in ForLoopsAsmgen..... (vm codegen already behaves like this) @@ -58,14 +56,7 @@ Compiler: Once new codegen is written that is based on the IR, this point is moot anyway as that will have its own dead code removal. - Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that) - add special (u)word array type (or modifier?) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing -- Add a mechanism to allocate variables into golden ram (or segments really) (see GoldenRam class) - - block "golden" treated specially: every var in here will be allocated in the Golden ram area - - that block can only contain variables. - - the variables can NOT have initialization values, they will all be set to zero on startup (simple memset) - - just initialize them yourself in start() if you need a non-zero value - - OR.... do all this automatically if 'golden' is enabled as a compiler option? So compiler allocates in ZP first, then Golden Ram, then regular ram - - OR.... make all this more generic and use some %segment option to create real segments for 64tass? - - (need separate step in codegen and IR to write the "golden" variables) + Libraries: @@ -96,6 +87,7 @@ Optimizations: - when a loopvariable of a forloop isn't referenced in the body, and the iterations are known, replace the loop by a repeatloop but we have no efficient way right now to see if the body references a variable. - optimize function argument expressions better (use temporary variables to replace non-simple expressions?) +- 6502 codegen optimize array1[index] += / -= array2[index] to not use slow stackeval (attemptAssignOptimizedBinexpr) STRUCTS again?