mirror of
https://github.com/irmen/prog8.git
synced 2025-01-14 01:29:55 +00:00
new common ICodeGeneratorBackend interface for all code generator classes
This commit is contained in:
parent
b6e5dbd06c
commit
b95608f68a
codeCore/src/prog8/code/core
codeGenCpu6502/src/prog8/codegen/cpu6502
AsmGen.ktBuiltinFunctionsAsmGen.ktExpressionsAsmGen.ktForLoopsAsmGen.ktFunctionCallAsmGen.ktPostIncrDecrAsmGen.ktProgramAndVarsGen.kt
assignment
codeGenExperimental/src/prog8/codegen/experimental
codeGenIntermediate/src/prog8/codegen/vm
compiler
@ -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"
|
19
codeCore/src/prog8/code/core/ICodeGeneratorBackend.kt
Normal file
19
codeCore/src/prog8/code/core/ICodeGeneratorBackend.kt
Normal 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"
|
@ -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
|
||||
|
@ -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? {
|
||||
|
@ -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")
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
) {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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}")
|
||||
}
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user