new common ICodeGeneratorBackend interface for all code generator classes

This commit is contained in:
Irmen de Jong
2023-02-12 23:49:48 +01:00
parent b6e5dbd06c
commit b95608f68a
16 changed files with 85 additions and 73 deletions

View File

@@ -1,12 +0,0 @@
package prog8.code.core
interface IAssemblyGenerator {
fun compileToAssembly(): IAssemblyProgram?
}
interface IAssemblyProgram {
val name: String
fun assemble(options: CompilationOptions): Boolean
}
fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"

View File

@@ -0,0 +1,19 @@
package prog8.code.core
import prog8.code.SymbolTable
import prog8.code.ast.PtProgram
interface ICodeGeneratorBackend {
fun generate(program: PtProgram,
symbolTable: SymbolTable,
options: CompilationOptions,
errors: IErrorReporter): IAssemblyProgram?
}
interface IAssemblyProgram {
val name: String
fun assemble(options: CompilationOptions): Boolean
}
fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"

View File

@@ -14,13 +14,24 @@ import kotlin.io.path.writeLines
internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1" internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2" internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
class AsmGen6502: ICodeGeneratorBackend {
override fun generate(
program: PtProgram,
symbolTable: SymbolTable,
options: CompilationOptions,
errors: IErrorReporter
): IAssemblyProgram? {
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
return asmgen.compileToAssembly()
}
}
class AsmGen( class AsmGen6502Internal (
val program: PtProgram, val program: PtProgram,
internal val symbolTable: SymbolTable, internal val symbolTable: SymbolTable,
internal val options: CompilationOptions, internal val options: CompilationOptions,
internal val errors: IErrorReporter internal val errors: IErrorReporter
): IAssemblyGenerator { ) {
internal val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100) internal val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100)
internal val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640) internal val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640)
@@ -37,7 +48,7 @@ class AsmGen(
private val assignmentAsmGen = AssignmentAsmGen(program, this, allocator) private val assignmentAsmGen = AssignmentAsmGen(program, this, allocator)
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen) private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
override fun compileToAssembly(): IAssemblyProgram? { fun compileToAssembly(): IAssemblyProgram? {
assemblyLines.clear() assemblyLines.clear()
loopEndLabels.clear() loopEndLabels.clear()
@@ -1076,7 +1087,7 @@ $repeatLabel lda $counterVar
return false return false
} }
internal fun findSubroutineParameter(name: String, asmgen: AsmGen): PtSubroutineParameter? { internal fun findSubroutineParameter(name: String, asmgen: AsmGen6502Internal): PtSubroutineParameter? {
val node = asmgen.symbolTable.lookup(name)!!.astNode val node = asmgen.symbolTable.lookup(name)!!.astNode
if(node is PtSubroutineParameter) if(node is PtSubroutineParameter)
return node return node

View File

@@ -6,7 +6,7 @@ import prog8.codegen.cpu6502.assignment.*
internal class BuiltinFunctionsAsmGen(private val program: PtProgram, internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
private val asmgen: AsmGen, private val asmgen: AsmGen6502Internal,
private val assignAsmGen: AssignmentAsmGen) { private val assignAsmGen: AssignmentAsmGen) {
internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? { internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?): DataType? {

View File

@@ -5,7 +5,7 @@ import prog8.code.core.*
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
internal class ExpressionsAsmGen(private val program: PtProgram, internal class ExpressionsAsmGen(private val program: PtProgram,
private val asmgen: AsmGen, private val asmgen: AsmGen6502Internal,
private val allocator: VariableAllocator) { private val allocator: VariableAllocator) {
@Deprecated("avoid calling this as it generates slow evalstack based code") @Deprecated("avoid calling this as it generates slow evalstack based code")

View File

@@ -6,7 +6,7 @@ import prog8.code.core.*
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
internal class ForLoopsAsmGen(private val program: PtProgram, internal class ForLoopsAsmGen(private val program: PtProgram,
private val asmgen: AsmGen, private val asmgen: AsmGen6502Internal,
private val zeropage: Zeropage) { private val zeropage: Zeropage) {
internal fun translate(stmt: PtForLoop) { internal fun translate(stmt: PtForLoop) {

View File

@@ -8,7 +8,7 @@ import prog8.codegen.cpu6502.assignment.AsmAssignment
import prog8.codegen.cpu6502.assignment.TargetStorageKind import prog8.codegen.cpu6502.assignment.TargetStorageKind
internal class FunctionCallAsmGen(private val program: PtProgram, private val asmgen: AsmGen) { internal class FunctionCallAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal) {
internal fun translateFunctionCallStatement(stmt: PtFunctionCall) { internal fun translateFunctionCallStatement(stmt: PtFunctionCall) {
saveXbeforeCall(stmt) saveXbeforeCall(stmt)

View File

@@ -7,7 +7,7 @@ import prog8.code.ast.PtProgram
import prog8.code.core.* import prog8.code.core.*
internal class PostIncrDecrAsmGen(private val program: PtProgram, private val asmgen: AsmGen) { internal class PostIncrDecrAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal) {
internal fun translate(stmt: PtPostIncrDecr) { internal fun translate(stmt: PtPostIncrDecr) {
val incr = stmt.operator=="++" val incr = stmt.operator=="++"
val targetIdent = stmt.target.identifier val targetIdent = stmt.target.identifier

View File

@@ -23,7 +23,7 @@ internal class ProgramAndVarsGen(
val errors: IErrorReporter, val errors: IErrorReporter,
private val symboltable: SymbolTable, private val symboltable: SymbolTable,
private val functioncallAsmGen: FunctionCallAsmGen, private val functioncallAsmGen: FunctionCallAsmGen,
private val asmgen: AsmGen, private val asmgen: AsmGen6502Internal,
private val allocator: VariableAllocator, private val allocator: VariableAllocator,
private val zeropage: Zeropage private val zeropage: Zeropage
) { ) {

View File

@@ -2,7 +2,7 @@ package prog8.codegen.cpu6502.assignment
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.* import prog8.code.core.*
import prog8.codegen.cpu6502.AsmGen import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.codegen.cpu6502.asConstInteger import prog8.codegen.cpu6502.asConstInteger
import prog8.codegen.cpu6502.returnsWhatWhere import prog8.codegen.cpu6502.returnsWhatWhere
@@ -26,7 +26,7 @@ internal enum class SourceStorageKind {
} }
internal class AsmAssignTarget(val kind: TargetStorageKind, internal class AsmAssignTarget(val kind: TargetStorageKind,
private val asmgen: AsmGen, private val asmgen: AsmGen6502Internal,
val datatype: DataType, val datatype: DataType,
val scope: IPtSubroutine?, val scope: IPtSubroutine?,
private val variableAsmName: String? = null, private val variableAsmName: String? = null,
@@ -52,7 +52,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
} }
companion object { companion object {
fun fromAstAssignment(assign: PtAssignment, asmgen: AsmGen): AsmAssignTarget { fun fromAstAssignment(assign: PtAssignment, asmgen: AsmGen6502Internal): AsmAssignTarget {
with(assign.target) { with(assign.target) {
when { when {
identifier != null -> { identifier != null -> {
@@ -76,7 +76,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
} }
} }
fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: IPtSubroutine?, asmgen: AsmGen): AsmAssignTarget = fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: IPtSubroutine?, asmgen: AsmGen6502Internal): AsmAssignTarget =
when(registers) { when(registers) {
RegisterOrPair.A, RegisterOrPair.A,
RegisterOrPair.X, RegisterOrPair.X,
@@ -108,7 +108,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
internal class AsmAssignSource(val kind: SourceStorageKind, internal class AsmAssignSource(val kind: SourceStorageKind,
private val program: PtProgram, private val program: PtProgram,
private val asmgen: AsmGen, private val asmgen: AsmGen6502Internal,
val datatype: DataType, val datatype: DataType,
private val variableAsmName: String? = null, private val variableAsmName: String? = null,
val array: PtArrayIndexer? = null, val array: PtArrayIndexer? = null,
@@ -125,7 +125,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
asmgen.asmVariableName(array.variable) asmgen.asmVariableName(array.variable)
companion object { companion object {
fun fromAstSource(value: PtExpression, program: PtProgram, asmgen: AsmGen): AsmAssignSource { fun fromAstSource(value: PtExpression, program: PtProgram, asmgen: AsmGen6502Internal): AsmAssignSource {
val cv = value as? PtNumber val cv = value as? PtNumber
if(cv!=null) if(cv!=null)
return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv) return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv)

View File

@@ -6,7 +6,7 @@ import prog8.codegen.cpu6502.*
internal class AssignmentAsmGen(private val program: PtProgram, internal class AssignmentAsmGen(private val program: PtProgram,
private val asmgen: AsmGen, private val asmgen: AsmGen6502Internal,
private val allocator: VariableAllocator) { private val allocator: VariableAllocator) {
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator) private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator)

View File

@@ -2,13 +2,13 @@ package prog8.codegen.cpu6502.assignment
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.* import prog8.code.core.*
import prog8.codegen.cpu6502.AsmGen import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.codegen.cpu6502.VariableAllocator import prog8.codegen.cpu6502.VariableAllocator
internal class AugmentableAssignmentAsmGen(private val program: PtProgram, internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
private val assignmentAsmGen: AssignmentAsmGen, private val assignmentAsmGen: AssignmentAsmGen,
private val asmgen: AsmGen, private val asmgen: AsmGen6502Internal,
private val allocator: VariableAllocator private val allocator: VariableAllocator
) { ) {
fun translate(assign: AsmAssignment) { fun translate(assign: AsmAssignment) {

View File

@@ -3,19 +3,19 @@ package prog8.codegen.experimental
import prog8.code.SymbolTable import prog8.code.SymbolTable
import prog8.code.ast.PtProgram import prog8.code.ast.PtProgram
import prog8.code.core.CompilationOptions import prog8.code.core.CompilationOptions
import prog8.code.core.IAssemblyGenerator
import prog8.code.core.IAssemblyProgram import prog8.code.core.IAssemblyProgram
import prog8.code.core.ICodeGeneratorBackend
import prog8.code.core.IErrorReporter import prog8.code.core.IErrorReporter
import prog8.codegen.intermediate.IRCodeGen import prog8.codegen.intermediate.IRCodeGen
import prog8.intermediate.IRFileWriter import prog8.intermediate.IRFileWriter
class CodeGen(private val program: PtProgram, class ExperiCodeGen: ICodeGeneratorBackend {
private val symbolTable: SymbolTable, override fun generate(
private val options: CompilationOptions, program: PtProgram,
private val errors: IErrorReporter symbolTable: SymbolTable,
): IAssemblyGenerator { options: CompilationOptions,
override fun compileToAssembly(): IAssemblyProgram? { errors: IErrorReporter
): IAssemblyProgram? {
// you could write a code generator directly on the PtProgram AST, // you could write a code generator directly on the PtProgram AST,
// but you can also use the Intermediate Representation to build a codegen on: // but you can also use the Intermediate Representation to build a codegen on:
val irCodeGen = IRCodeGen(program, symbolTable, options, errors) val irCodeGen = IRCodeGen(program, symbolTable, options, errors)

View File

@@ -3,23 +3,22 @@ package prog8.codegen.vm
import prog8.code.SymbolTable import prog8.code.SymbolTable
import prog8.code.ast.PtProgram import prog8.code.ast.PtProgram
import prog8.code.core.CompilationOptions import prog8.code.core.CompilationOptions
import prog8.code.core.IAssemblyGenerator
import prog8.code.core.IAssemblyProgram import prog8.code.core.IAssemblyProgram
import prog8.code.core.ICodeGeneratorBackend
import prog8.code.core.IErrorReporter import prog8.code.core.IErrorReporter
import prog8.codegen.intermediate.IRCodeGen import prog8.codegen.intermediate.IRCodeGen
import prog8.intermediate.IRFileWriter import prog8.intermediate.IRFileWriter
import prog8.intermediate.IRProgram import prog8.intermediate.IRProgram
class VmCodeGen(private val program: PtProgram, class VmCodeGen: ICodeGeneratorBackend {
private val symbolTable: SymbolTable, override fun generate(
private val options: CompilationOptions, program: PtProgram,
private val errors: IErrorReporter symbolTable: SymbolTable,
): IAssemblyGenerator { options: CompilationOptions,
override fun compileToAssembly(): IAssemblyProgram? { errors: IErrorReporter
): IAssemblyProgram? {
val irCodeGen = IRCodeGen(program, symbolTable, options, errors) val irCodeGen = IRCodeGen(program, symbolTable, options, errors)
val irProgram = irCodeGen.generate() val irProgram = irCodeGen.generate()
return VmAssemblyProgram(irProgram.name, irProgram) return VmAssemblyProgram(irProgram.name, irProgram)
} }
} }

View File

@@ -400,7 +400,19 @@ private fun createAssemblyAndAssemble(program: PtProgram,
errors: IErrorReporter, errors: IErrorReporter,
compilerOptions: CompilationOptions compilerOptions: CompilationOptions
): Boolean { ): Boolean {
val assembly = asmGeneratorFor(program, compilerOptions, errors).compileToAssembly()
val asmgen = if(compilerOptions.experimentalCodegen)
prog8.codegen.experimental.ExperiCodeGen()
else if (compilerOptions.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
prog8.codegen.cpu6502.AsmGen6502()
else if (compilerOptions.compTarget.name == VMTarget.NAME)
VmCodeGen()
else
throw NotImplementedError("no asm generator for cpu ${compilerOptions.compTarget.machine.cpu}")
val stMaker = SymbolTableMaker(program, compilerOptions)
val symbolTable = stMaker.make()
val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors)
errors.report() errors.report()
return if(assembly!=null && errors.noErrors()) { return if(assembly!=null && errors.noErrors()) {
@@ -409,20 +421,3 @@ private fun createAssemblyAndAssemble(program: PtProgram,
false false
} }
} }
internal fun asmGeneratorFor(program: PtProgram,
options: CompilationOptions,
errors: IErrorReporter): IAssemblyGenerator
{
val stMaker = SymbolTableMaker(program, options)
val symbolTable = stMaker.make()
return if(options.experimentalCodegen)
prog8.codegen.experimental.CodeGen(program, symbolTable, options, errors)
else if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
prog8.codegen.cpu6502.AsmGen(program, symbolTable, options, errors)
else if (options.compTarget.name == VMTarget.NAME)
VmCodeGen(program, symbolTable, options, errors)
else
throw NotImplementedError("no asm generator for cpu ${options.compTarget.machine.cpu}")
}

View File

@@ -17,7 +17,7 @@ import prog8.code.ast.PtProgram
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.VMTarget import prog8.code.target.VMTarget
import prog8.codegen.cpu6502.AsmGen import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.compiler.astprocessing.IntermediateAstMaker import prog8.compiler.astprocessing.IntermediateAstMaker
import prog8tests.helpers.* import prog8tests.helpers.*
@@ -72,17 +72,17 @@ class TestAsmGenSymbols: StringSpec({
return program return program
} }
fun createTestAsmGen(program: Program): AsmGen { fun createTestAsmGen6502(program: Program): AsmGen6502Internal {
val errors = ErrorReporterForTests() val errors = ErrorReporterForTests()
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u) val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u)
val ptProgram = IntermediateAstMaker(program, options).transform() val ptProgram = IntermediateAstMaker(program, options).transform()
val st = SymbolTableMaker(ptProgram, options).make() val st = SymbolTableMaker(ptProgram, options).make()
return AsmGen(ptProgram, st, options, errors) return AsmGen6502Internal(ptProgram, st, options, errors)
} }
"symbol and variable names from strings" { "symbol and variable names from strings" {
val program = createTestProgram() val program = createTestProgram()
val asmgen = createTestAsmGen(program) val asmgen = createTestAsmGen6502(program)
asmgen.asmSymbolName("name") shouldBe "name" asmgen.asmSymbolName("name") shouldBe "name"
asmgen.asmSymbolName("name") shouldBe "name" asmgen.asmSymbolName("name") shouldBe "name"
asmgen.asmSymbolName("<name>") shouldBe "prog8_name" asmgen.asmSymbolName("<name>") shouldBe "prog8_name"
@@ -95,7 +95,7 @@ class TestAsmGenSymbols: StringSpec({
"symbol and variable names from variable identifiers" { "symbol and variable names from variable identifiers" {
val program = createTestProgram() val program = createTestProgram()
val asmgen = createTestAsmGen(program) val asmgen = createTestAsmGen6502(program)
val sub = asmgen.program.entrypoint()!! val sub = asmgen.program.entrypoint()!!
val localvarIdent = sub.children.asSequence().filterIsInstance<PtAssignment>().first { it.value is PtIdentifier }.value as PtIdentifier val localvarIdent = sub.children.asSequence().filterIsInstance<PtAssignment>().first { it.value is PtIdentifier }.value as PtIdentifier
@@ -115,7 +115,7 @@ class TestAsmGenSymbols: StringSpec({
"symbol and variable names from label identifiers" { "symbol and variable names from label identifiers" {
val program = createTestProgram() val program = createTestProgram()
val asmgen = createTestAsmGen(program) val asmgen = createTestAsmGen6502(program)
val sub = asmgen.program.entrypoint()!! val sub = asmgen.program.entrypoint()!!
val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier
@@ -144,7 +144,7 @@ main {
prog8_lib.P8ZP_SCRATCH_W2 = 1 prog8_lib.P8ZP_SCRATCH_W2 = 1
*/ */
val program = createTestProgram() val program = createTestProgram()
val asmgen = createTestAsmGen(program) val asmgen = createTestAsmGen6502(program)
asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_REG") shouldBe "P8ZP_SCRATCH_REG" asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_REG") shouldBe "P8ZP_SCRATCH_REG"
asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_W2") shouldBe "P8ZP_SCRATCH_W2" asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_W2") shouldBe "P8ZP_SCRATCH_W2"
asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_REG")) shouldBe "P8ZP_SCRATCH_REG" asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_REG")) shouldBe "P8ZP_SCRATCH_REG"