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 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,
internal val symbolTable: SymbolTable,
internal val options: CompilationOptions,
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 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 builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
override fun compileToAssembly(): IAssemblyProgram? {
fun compileToAssembly(): IAssemblyProgram? {
assemblyLines.clear()
loopEndLabels.clear()
@ -1076,7 +1087,7 @@ $repeatLabel lda $counterVar
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
if(node is PtSubroutineParameter)
return node

View File

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

View File

@ -5,7 +5,7 @@ import prog8.code.core.*
import kotlin.math.absoluteValue
internal class ExpressionsAsmGen(private val program: PtProgram,
private val asmgen: AsmGen,
private val asmgen: AsmGen6502Internal,
private val allocator: VariableAllocator) {
@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
internal class ForLoopsAsmGen(private val program: PtProgram,
private val asmgen: AsmGen,
private val asmgen: AsmGen6502Internal,
private val zeropage: Zeropage) {
internal fun translate(stmt: PtForLoop) {

View File

@ -8,7 +8,7 @@ import prog8.codegen.cpu6502.assignment.AsmAssignment
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) {
saveXbeforeCall(stmt)

View File

@ -7,7 +7,7 @@ import prog8.code.ast.PtProgram
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) {
val incr = stmt.operator=="++"
val targetIdent = stmt.target.identifier

View File

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

View File

@ -2,7 +2,7 @@ package prog8.codegen.cpu6502.assignment
import prog8.code.ast.*
import prog8.code.core.*
import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.codegen.cpu6502.asConstInteger
import prog8.codegen.cpu6502.returnsWhatWhere
@ -26,7 +26,7 @@ internal enum class SourceStorageKind {
}
internal class AsmAssignTarget(val kind: TargetStorageKind,
private val asmgen: AsmGen,
private val asmgen: AsmGen6502Internal,
val datatype: DataType,
val scope: IPtSubroutine?,
private val variableAsmName: String? = null,
@ -52,7 +52,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
}
companion object {
fun fromAstAssignment(assign: PtAssignment, asmgen: AsmGen): AsmAssignTarget {
fun fromAstAssignment(assign: PtAssignment, asmgen: AsmGen6502Internal): AsmAssignTarget {
with(assign.target) {
when {
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) {
RegisterOrPair.A,
RegisterOrPair.X,
@ -108,7 +108,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
internal class AsmAssignSource(val kind: SourceStorageKind,
private val program: PtProgram,
private val asmgen: AsmGen,
private val asmgen: AsmGen6502Internal,
val datatype: DataType,
private val variableAsmName: String? = null,
val array: PtArrayIndexer? = null,
@ -125,7 +125,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
asmgen.asmVariableName(array.variable)
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
if(cv!=null)
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,
private val asmgen: AsmGen,
private val asmgen: AsmGen6502Internal,
private val allocator: VariableAllocator) {
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.core.*
import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.codegen.cpu6502.VariableAllocator
internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
private val assignmentAsmGen: AssignmentAsmGen,
private val asmgen: AsmGen,
private val asmgen: AsmGen6502Internal,
private val allocator: VariableAllocator
) {
fun translate(assign: AsmAssignment) {

View File

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

View File

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

View File

@ -400,7 +400,19 @@ private fun createAssemblyAndAssemble(program: PtProgram,
errors: IErrorReporter,
compilerOptions: CompilationOptions
): 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()
return if(assembly!=null && errors.noErrors()) {
@ -409,20 +421,3 @@ private fun createAssemblyAndAssemble(program: PtProgram,
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.target.C64Target
import prog8.code.target.VMTarget
import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.compiler.astprocessing.IntermediateAstMaker
import prog8tests.helpers.*
@ -72,17 +72,17 @@ class TestAsmGenSymbols: StringSpec({
return program
}
fun createTestAsmGen(program: Program): AsmGen {
fun createTestAsmGen6502(program: Program): AsmGen6502Internal {
val errors = ErrorReporterForTests()
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u)
val ptProgram = IntermediateAstMaker(program, options).transform()
val st = SymbolTableMaker(ptProgram, options).make()
return AsmGen(ptProgram, st, options, errors)
return AsmGen6502Internal(ptProgram, st, options, errors)
}
"symbol and variable names from strings" {
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 "prog8_name"
@ -95,7 +95,7 @@ class TestAsmGenSymbols: StringSpec({
"symbol and variable names from variable identifiers" {
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
val asmgen = createTestAsmGen6502(program)
val sub = asmgen.program.entrypoint()!!
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" {
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
val asmgen = createTestAsmGen6502(program)
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
@ -144,7 +144,7 @@ main {
prog8_lib.P8ZP_SCRATCH_W2 = 1
*/
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_W2") shouldBe "P8ZP_SCRATCH_W2"
asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_REG")) shouldBe "P8ZP_SCRATCH_REG"