some naming changes and cleanups

This commit is contained in:
Irmen de Jong 2022-02-06 22:56:17 +01:00
parent 10de7dc1f9
commit 101fb0b8aa
20 changed files with 140 additions and 143 deletions

View File

@ -23,9 +23,10 @@ const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
class AsmGen6502(internal val program: Program,
internal val errors: IErrorReporter,
internal val options: CompilationOptions): IAssemblyGenerator {
class AsmGen(internal val program: Program,
internal val errors: IErrorReporter,
internal val variables: IVariablesAndConsts,
internal val options: CompilationOptions): IAssemblyGenerator {
// for expressions and augmented assignments:
val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100)
@ -54,6 +55,8 @@ class AsmGen6502(internal val program: Program,
println("Generating assembly code... ")
// TODO variables.dump(program.memsizer)
val allInitializers = blockVariableInitializers.asSequence().flatMap { it.value }
require(allInitializers.all { it.origin==AssignmentOrigin.VARINIT }) {"all block-level assignments must be a variable initializer"}
@ -285,7 +288,7 @@ class AsmGen6502(internal val program: Program,
// first translate regular statements, and then put the subroutines at the end.
val (subroutine, stmts) = statements.partition { it is Subroutine }
stmts.forEach { translate(it) }
subroutine.forEach { translateSubroutine(it as Subroutine) }
subroutine.forEach { translate(it) }
if(!options.dontReinitGlobals) {
// generate subroutine to initialize block-level (global) variables

View File

@ -17,7 +17,7 @@ import prog8.compilerinterface.CpuType
import prog8.compilerinterface.FSignature
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen6502, private val assignAsmGen: AssignmentAsmGen) {
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) {
internal fun translateFunctioncallExpression(fcall: FunctionCallExpression, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
translateFunctioncall(fcall, func, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister)

View File

@ -11,7 +11,7 @@ import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.CpuType
import kotlin.math.absoluteValue
internal class ExpressionsAsmGen(private val program: Program, private val asmgen: AsmGen6502, private val functioncallAsmGen: FunctionCallAsmGen) {
internal class ExpressionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val functioncallAsmGen: FunctionCallAsmGen) {
@Deprecated("avoid calling this as it generates slow evalstack based code")
internal fun translateExpression(expression:Expression) {

View File

@ -12,7 +12,7 @@ import prog8.ast.toHex
import prog8.compilerinterface.AssemblyError
import kotlin.math.absoluteValue
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen6502) {
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translate(stmt: ForLoop) {
val iterableDt = stmt.iterable.inferType(program)

View File

@ -17,7 +17,7 @@ import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.CpuType
internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen6502) {
internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translateFunctionCallStatement(stmt: IFunctionCall) {
saveXbeforeCall(stmt)

View File

@ -9,7 +9,7 @@ import prog8.ast.toHex
import prog8.compilerinterface.AssemblyError
internal class PostIncrDecrAsmGen(private val program: Program, private val asmgen: AsmGen6502) {
internal class PostIncrDecrAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translate(stmt: PostIncrDecr) {
val incr = stmt.operator=="++"
val targetIdent = stmt.target.identifier

View File

@ -4,7 +4,7 @@ import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.codegen.cpu6502.AsmGen6502
import prog8.codegen.cpu6502.AsmGen
import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.IMemSizer
@ -29,7 +29,7 @@ internal enum class SourceStorageKind {
internal class AsmAssignTarget(val kind: TargetStorageKind,
private val program: Program,
private val asmgen: AsmGen6502,
private val asmgen: AsmGen,
val datatype: DataType,
val scope: Subroutine?,
private val variableAsmName: String? = null,
@ -56,7 +56,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
}
companion object {
fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen6502): AsmAssignTarget {
fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen): AsmAssignTarget {
with(assign.target) {
val idt = inferType(program)
val dt = idt.getOrElse { throw AssemblyError("unknown dt") }
@ -82,7 +82,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
}
}
fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: Subroutine?, program: Program, asmgen: AsmGen6502): AsmAssignTarget =
fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: Subroutine?, program: Program, asmgen: AsmGen): AsmAssignTarget =
when(registers) {
RegisterOrPair.A,
RegisterOrPair.X,
@ -114,7 +114,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
internal class AsmAssignSource(val kind: SourceStorageKind,
private val program: Program,
private val asmgen: AsmGen6502,
private val asmgen: AsmGen,
val datatype: DataType,
private val variableAsmName: String? = null,
val array: ArrayIndexedExpression? = null,
@ -134,9 +134,9 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
asmgen.asmVariableName(array.arrayvar)
companion object {
fun fromAstSource(indexer: ArrayIndex, program: Program, asmgen: AsmGen6502): AsmAssignSource = fromAstSource(indexer.indexExpr, program, asmgen)
fun fromAstSource(indexer: ArrayIndex, program: Program, asmgen: AsmGen): AsmAssignSource = fromAstSource(indexer.indexExpr, program, asmgen)
fun fromAstSource(value: Expression, program: Program, asmgen: AsmGen6502): AsmAssignSource {
fun fromAstSource(value: Expression, program: Program, asmgen: AsmGen): AsmAssignSource {
val cv = value.constValue(program)
if(cv!=null)
return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv)

View File

@ -5,14 +5,14 @@ import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.toHex
import prog8.codegen.cpu6502.AsmGen6502
import prog8.codegen.cpu6502.AsmGen
import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.CpuType
import prog8.compilerinterface.builtinFunctionReturnType
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen6502) {
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen) {
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen)

View File

@ -5,14 +5,14 @@ import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.Subroutine
import prog8.ast.toHex
import prog8.codegen.cpu6502.AsmGen6502
import prog8.codegen.cpu6502.AsmGen
import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.CpuType
internal class AugmentableAssignmentAsmGen(private val program: Program,
private val assignmentAsmGen: AssignmentAsmGen,
private val asmgen: AsmGen6502
private val asmgen: AsmGen
) {
fun translate(assign: AsmAssignment) {
require(assign.isAugmentable)

View File

@ -0,0 +1,18 @@
package prog8.codegen.experimental6502
import prog8.ast.Program
import prog8.compilerinterface.*
class AsmGen(internal val program: Program,
internal val errors: IErrorReporter,
internal val variables: IVariablesAndConsts,
internal val options: CompilationOptions): IAssemblyGenerator {
override fun compileToAssembly(): IAssemblyProgram? {
println("\n** experimental 65(c)02 code generator **\n")
println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
return AssemblyProgram("dummy")
}
}

View File

@ -1,20 +0,0 @@
package prog8.codegen.experimental6502
import prog8.ast.Program
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IAssemblyGenerator
import prog8.compilerinterface.IAssemblyProgram
import prog8.compilerinterface.IErrorReporter
class ExperimentalAsmGen6502(internal val program: Program,
internal val errors: IErrorReporter,
internal val options: CompilationOptions
): IAssemblyGenerator {
override fun compileToAssembly(): IAssemblyProgram? {
println("\n** experimental 65(c)02 code generator **\n")
println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
return AssemblyProgram("dummy")
}
}

View File

@ -9,8 +9,6 @@ import prog8.ast.base.Position
import prog8.ast.expressions.Expression
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.Directive
import prog8.codegen.cpu6502.AsmGen6502
import prog8.codegen.experimental6502.ExperimentalAsmGen6502
import prog8.codegen.target.C128Target
import prog8.codegen.target.C64Target
import prog8.codegen.target.Cx16Target
@ -21,6 +19,7 @@ import prog8.parser.ParseError
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.nameWithoutExtension
import kotlin.math.round
import kotlin.system.measureTimeMillis
@ -109,7 +108,8 @@ fun compileProgram(args: CompilerArguments): CompilationResult {
}
System.out.flush()
System.err.flush()
println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.")
val seconds = totalTime/1000.0
println("\nTotal compilation+assemble time: ${round(seconds*100.0)/100.0} sec.")
return CompilationResult(true, program, programName, compTarget, importedFiles)
} catch (px: ParseError) {
System.err.print("\u001b[91m") // bright red
@ -344,14 +344,13 @@ private fun writeAssembly(program: Program,
): WriteAssemblyResult {
// asm generation directly from the Ast
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
program.processAstBeforeAsmGeneration(compilerOptions, errors)
val variables = program.processAstBeforeAsmGeneration(compilerOptions, errors)
errors.report()
// TODO do something with the VariableAllocation, pass it to the asmgenerator
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
// printProgram(program)
val assembly = asmGeneratorFor(program, errors, compilerOptions).compileToAssembly()
val assembly = asmGeneratorFor(program, errors, variables, compilerOptions).compileToAssembly()
errors.report()
return if(assembly!=null && errors.noErrors()) {
@ -371,18 +370,14 @@ fun printProgram(program: Program) {
println()
}
internal fun asmGeneratorFor(
program: Program,
errors: IErrorReporter,
options: CompilationOptions,
): IAssemblyGenerator
internal fun asmGeneratorFor(program: Program, errors: IErrorReporter, variables: IVariablesAndConsts, options: CompilationOptions): IAssemblyGenerator
{
if(options.experimentalCodegen) {
if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
return ExperimentalAsmGen6502(program, errors, options)
return prog8.codegen.experimental6502.AsmGen(program, errors, variables, options)
} else {
if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
return AsmGen6502(program, errors, options)
return prog8.codegen.cpu6502.AsmGen(program, errors, variables, options)
}
throw NotImplementedError("no asm generator for cpu ${options.compTarget.machine.cpu}")

View File

@ -13,6 +13,7 @@ import prog8.ast.walk.IAstModification
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.IStringEncoding
import prog8.compilerinterface.IVariablesAndConsts
internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) {
@ -23,7 +24,7 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
checker.visit(this)
}
internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter) {
internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter): IVariablesAndConsts {
val fixer = BeforeAsmAstChanger(this, compilerOptions, errors)
fixer.visit(this)
while(errors.noErrors() && fixer.applyModifications()>0) {
@ -34,6 +35,7 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
while(errors.noErrors() && cleaner.applyModifications()>0) {
cleaner.visit(this)
}
return fixer.variables
}
internal fun Program.reorderStatements(errors: IErrorReporter, options: CompilationOptions) {

View File

@ -20,17 +20,14 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
private val allSubroutineVars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
private val allSubroutineConsts = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
private val allSubroutineMemoryvars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
internal lateinit var allocation: IVariableAllocation
internal lateinit var variables: IVariablesAndConsts
/* TODO complete the use of VariableAllocation and get rid of it from the AsmGen (and that should no longer use vardecl either):
override fun after(program: Program): Iterable<IAstModification> {
allocation = VariableAllocation(options,
variables = VariablesAndConsts(
allBlockVars, allBlockConsts, allBlockMemoryvars,
allSubroutineVars, allSubroutineConsts, allSubroutineMemoryvars)
allocation.dump(program.memsizer)
return super.after(program)
}
*/
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
throw FatalAstException("break should have been replaced by goto $breakStmt")
@ -446,46 +443,39 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
}
internal class VariableAllocation (
options: CompilationOptions,
internal class VariablesAndConsts (
astBlockVars: Map<Block, Set<VarDecl>>,
astBlockConsts: Map<Block, Set<VarDecl>>,
astBlockMemvars: Map<Block, Set<VarDecl>>,
astSubroutineVars: Map<Subroutine, Set<VarDecl>>,
astSubroutineConsts: Map<Subroutine, Set<VarDecl>>,
astSubroutineMemvars: Map<Subroutine, Set<VarDecl>>
) : IVariableAllocation
) : IVariablesAndConsts
{
override val zeropageVars: Set<IVariableAllocation.ZeropageVariable>
override val blockVars: Map<Block, Set<IVariableAllocation.StaticBlockVariable>>
override val blockConsts: Map<Block, Set<IVariableAllocation.ConstantNumberSymbol>>
override val blockMemvars: Map<Block, Set<IVariableAllocation.MemoryMappedSymbol>>
override val subroutineVars: Map<Subroutine, Set<IVariableAllocation.StaticSubroutineVariable>>
override val subroutineConsts: Map<Subroutine, Set<IVariableAllocation.ConstantNumberSymbol>>
override val subroutineMemvars: Map<Subroutine, Set<IVariableAllocation.MemoryMappedSymbol>>
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticBlockVariable>>
override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticSubroutineVariable>>
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
init {
if(options.zeropage!=ZeropageType.DONTUSE)
allocateVarsInZeropage(options.compTarget.machine.zeropage)
val zpv = mutableSetOf<IVariableAllocation.ZeropageVariable>()
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariableAllocation.StaticBlockVariable>() }
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariableAllocation.ConstantNumberSymbol>() }
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariableAllocation.MemoryMappedSymbol>() }
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariableAllocation.StaticSubroutineVariable>() }
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariableAllocation.ConstantNumberSymbol>() }
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariableAllocation.MemoryMappedSymbol>() }
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticBlockVariable>() }
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticSubroutineVariable>() }
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
astBlockVars.forEach { (block, decls) ->
val vars = bv.getValue(block)
vars.addAll(decls.map {
// TODO make sure the zp-allocated variables are not added here
IVariableAllocation.StaticBlockVariable(it.datatype, it.name, it.value, it.position, it)
IVariablesAndConsts.StaticBlockVariable(it.datatype, it.name, it.value, it.position, it)
})
}
astBlockConsts.forEach { (block, decls) ->
bc.getValue(block).addAll(
decls.map {
IVariableAllocation.ConstantNumberSymbol(
IVariablesAndConsts.ConstantNumberSymbol(
it.datatype,
it.name,
(it.value as NumericLiteralValue).number,
@ -496,7 +486,7 @@ internal class VariableAllocation (
astBlockMemvars.forEach { (block, decls) ->
bmv.getValue(block).addAll(
decls.map {
IVariableAllocation.MemoryMappedSymbol(
IVariablesAndConsts.MemoryMappedVariable(
it.datatype,
it.name,
(it.value as NumericLiteralValue).number.toUInt(),
@ -507,14 +497,13 @@ internal class VariableAllocation (
astSubroutineVars.forEach { (sub, decls) ->
val vars = sv.getValue(sub)
vars.addAll(decls.map {
// TODO make sure the zp-allocated variables are not added here
IVariableAllocation.StaticSubroutineVariable(it.datatype, it.name, it.position, it)
IVariablesAndConsts.StaticSubroutineVariable(it.datatype, it.name, it.position, it)
})
}
astSubroutineConsts.forEach { (sub, decls) ->
sc.getValue(sub).addAll(
decls.map {
IVariableAllocation.ConstantNumberSymbol(
IVariablesAndConsts.ConstantNumberSymbol(
it.datatype,
it.name,
(it.value as NumericLiteralValue).number,
@ -525,7 +514,7 @@ internal class VariableAllocation (
astSubroutineMemvars.forEach { (sub, decls) ->
smv.getValue(sub).addAll(
decls.map {
IVariableAllocation.MemoryMappedSymbol(
IVariablesAndConsts.MemoryMappedVariable(
it.datatype,
it.name,
(it.value as NumericLiteralValue).number.toUInt(),
@ -533,7 +522,6 @@ internal class VariableAllocation (
)
})
}
zeropageVars = zpv
blockVars = bv
blockConsts = bc
blockMemvars = bmv
@ -542,15 +530,7 @@ internal class VariableAllocation (
subroutineMemvars = smv
}
private fun allocateVarsInZeropage(zeropage: Zeropage) {
println("TODO: allocate vars on zeropage") // TODO
}
override fun dump(memsizer: IMemSizer) {
println("\nALL ZEROPAGE VARS:")
zeropageVars.forEach {
println(" ${it.type} ${it.scopedname} ${it.position}")
}
println("\nALL BLOCK VARS:")
blockVars.forEach { (block, vars) ->
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }

View File

@ -301,7 +301,7 @@ class TestOptimization: FunSpec({
expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, true, C64Target(), outputDir= outputDir)
result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
val allocation = result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
// assignment is now split into:
// bb = not bb
@ -326,7 +326,7 @@ class TestOptimization: FunSpec({
((bbAssigns1expr.right as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("ww")
bbAssigns1expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
val asm = generateAssembly(result.program, options)
val asm = generateAssembly(result.program, allocation, options)
asm shouldNotBe null
asm!!.name.shouldNotBeBlank()
}
@ -366,7 +366,7 @@ class TestOptimization: FunSpec({
test("asmgen correctly deals with float typecasting in augmented assignment") {
val src="""
%option enable_floats
%import floats
main {
sub start() {
@ -385,9 +385,7 @@ class TestOptimization: FunSpec({
(value.left as? IdentifierReference)?.nameInSource shouldBe listOf("ff")
value.right shouldBe instanceOf<TypecastExpression>()
val asm = generateAssembly(result.program)
asm shouldNotBe null
asm!!.name.shouldNotBeBlank()
compileText(C64Target(), optimize=false, src, writeAssembly = true).assertSuccess()
}
test("unused variable removal") {

View File

@ -12,22 +12,18 @@ import prog8.ast.expressions.AddressOf
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.*
import prog8.codegen.cpu6502.AsmGen6502
import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.target.C64Target
import prog8.codegen.target.c64.C64Zeropage
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.LauncherType
import prog8.compilerinterface.OutputType
import prog8.compilerinterface.ZeropageType
import prog8.compilerinterface.*
import prog8.parser.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
import prog8tests.helpers.ErrorReporterForTests
import java.nio.file.Path
class TestAsmGenSymbols: StringSpec({
fun createTestProgram(): Program {
fun createTestProgram(): Pair<Program, IVariablesAndConsts> {
/*
main {
@ -72,20 +68,42 @@ class TestAsmGenSymbols: StringSpec({
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
return Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder).addModule(module)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder).addModule(module)
val variables = object : IVariablesAndConsts {
override fun dump(memsizer: IMemSizer) { }
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticBlockVariable>>
override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticSubroutineVariable>>
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
init {
blockVars = mutableMapOf()
blockVars[block] = mutableSetOf(IVariablesAndConsts.StaticBlockVariable(varInBlock.datatype, varInBlock.name, varInBlock.value, varInBlock.position, varInBlock))
blockConsts = mutableMapOf()
blockMemvars = mutableMapOf()
subroutineVars = mutableMapOf()
subroutineVars[subroutine] = mutableSetOf(
IVariablesAndConsts.StaticSubroutineVariable(varInSub.datatype, varInSub.name, varInSub.position, varInSub),
IVariablesAndConsts.StaticSubroutineVariable(var2InSub.datatype, var2InSub.name, var2InSub.position, var2InSub)
)
subroutineConsts = mutableMapOf()
subroutineMemvars = mutableMapOf()
}
}
return Pair(program, variables)
}
fun createTestAsmGen(program: Program): AsmGen6502 {
fun createTestAsmGen(program: Program, allocation: IVariablesAndConsts): AsmGen {
val errors = ErrorReporterForTests()
val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target())
options.compTarget.machine.zeropage = C64Zeropage(options)
val asmgen = AsmGen6502(program, errors, options)
return asmgen
return AsmGen(program, errors, allocation, options)
}
"symbol and variable names from strings" {
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
val (program, variables) = createTestProgram()
val asmgen = createTestAsmGen(program, variables)
asmgen.asmSymbolName("name") shouldBe "name"
asmgen.asmSymbolName("name") shouldBe "name"
asmgen.asmSymbolName("<name>") shouldBe "prog8_name"
@ -97,8 +115,8 @@ class TestAsmGenSymbols: StringSpec({
}
"symbol and variable names from variable identifiers" {
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
val (program, variables) = createTestProgram()
val asmgen = createTestAsmGen(program, variables)
val sub = program.entrypoint
val localvarIdent = sub.statements.asSequence().filterIsInstance<Assignment>().first { it.value is IdentifierReference }.value as IdentifierReference
@ -117,8 +135,8 @@ class TestAsmGenSymbols: StringSpec({
}
"symbol and variable names from label identifiers" {
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
val (program, variables) = createTestProgram()
val asmgen = createTestAsmGen(program, variables)
val sub = program.entrypoint
val localLabelIdent = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("locallabel") }.value as AddressOf).identifier
@ -146,8 +164,8 @@ main {
prog8_lib.P8ZP_SCRATCH_W1 = 1
prog8_lib.P8ZP_SCRATCH_W2 = 1
*/
val program = createTestProgram()
val asmgen = createTestAsmGen(program)
val (program, variables) = createTestProgram()
val asmgen = createTestAsmGen(program, variables)
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"

View File

@ -11,7 +11,7 @@ import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
import prog8.compilerinterface.*
internal val DummyFunctions = object : IBuiltinFunctions {
internal object DummyFunctions : IBuiltinFunctions {
override val names: Set<String> = emptySet()
override val purefunctionNames: Set<String> = emptySet()
override fun constValue(
@ -23,12 +23,12 @@ internal val DummyFunctions = object : IBuiltinFunctions {
override fun returnType(name: String, args: MutableList<Expression>) = InferredTypes.InferredType.unknown()
}
internal val DummyMemsizer = object : IMemSizer {
internal object DummyMemsizer : IMemSizer {
override fun memorySize(dt: DataType) = 0
override fun memorySize(decl: VarDecl) = 0
}
internal val DummyStringEncoder = object : IStringEncoding {
internal object DummyStringEncoder : IStringEncoding {
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
return emptyList()
}
@ -38,7 +38,7 @@ internal val DummyStringEncoder = object : IStringEncoding {
}
}
internal val AsciiStringEncoder = object : IStringEncoding {
internal object AsciiStringEncoder : IStringEncoding {
override fun encodeString(str: String, encoding: Encoding): List<UByte> = str.map { it.code.toUByte() }
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String {
@ -46,7 +46,7 @@ internal val AsciiStringEncoder = object : IStringEncoding {
}
}
internal val DummyCompilationTarget = object : ICompilationTarget {
internal object DummyCompilationTarget : ICompilationTarget {
override val name: String = "dummy"
override val machine: IMachineDefinition
get() = throw NotImplementedError("dummy")
@ -75,4 +75,4 @@ internal val DummyCompilationTarget = object : ICompilationTarget {
override fun memorySize(decl: VarDecl): Int {
throw NotImplementedError("dummy")
}
}
}

View File

@ -3,7 +3,7 @@ package prog8tests.helpers
import io.kotest.assertions.withClue
import io.kotest.matchers.shouldBe
import prog8.ast.Program
import prog8.codegen.cpu6502.AsmGen6502
import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.target.C64Target
import prog8.codegen.target.c64.C64Zeropage
import prog8.compiler.CompilationResult
@ -83,10 +83,11 @@ internal fun compileText(
internal fun generateAssembly(
program: Program,
allocation: IVariablesAndConsts,
options: CompilationOptions? = null
): IAssemblyProgram? {
val coptions = options ?: CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, true, C64Target(), outputDir = outputDir)
coptions.compTarget.machine.zeropage = C64Zeropage(coptions)
val asmgen = AsmGen6502(program, ErrorReporterForTests(), coptions)
val asmgen = AsmGen(program, ErrorReporterForTests(), allocation, coptions)
return asmgen.compileToAssembly()
}

View File

@ -7,21 +7,24 @@ import prog8.ast.statements.Block
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
interface IVariableAllocation {
/**
* Experimental attempt for:
* A more convenient way to pass variable (and constant values) definitions to the code generator,
* so that it doesn't have to scavenge all VerDecl nodes in the AST for this information.
*/
interface IVariablesAndConsts {
data class ConstantNumberSymbol(val type: DataType, val name: String, val value: Double, val position: Position)
data class MemoryMappedSymbol(val type: DataType, val name: String, val address: UInt, val position: Position)
data class StaticBlockVariable(val type: DataType, val name: String, val initialValue: Expression?, val position: Position, val origVar: VarDecl) // TODO should get rid of origVar altogether
data class StaticSubroutineVariable(val type: DataType, val name: String, val position: Position, val origVar: VarDecl) // TODO should get rid of origVar altogether
data class ZeropageVariable(val type: DataType, val scopedname: List<String>, val position: Position)
data class MemoryMappedVariable(val type: DataType, val name: String, val address: UInt, val position: Position)
// TODO should get rid of origVar altogether in the following two:
data class StaticBlockVariable(val type: DataType, val name: String, val initialValue: Expression?, val position: Position, val origVar: VarDecl)
data class StaticSubroutineVariable(val type: DataType, val name: String, val position: Position, val origVar: VarDecl)
fun dump(memsizer: IMemSizer)
val zeropageVars: Set<ZeropageVariable> // also present in the Zeropage object after this allocation
val blockVars: Map<Block, Set<StaticBlockVariable>>
val blockConsts: Map<Block, Set<ConstantNumberSymbol>>
val blockMemvars: Map<Block, Set<MemoryMappedSymbol>>
val blockMemvars: Map<Block, Set<MemoryMappedVariable>>
val subroutineVars: Map<Subroutine, Set<StaticSubroutineVariable>>
val subroutineConsts: Map<Subroutine, Set<ConstantNumberSymbol>>
val subroutineMemvars: Map<Subroutine, Set<MemoryMappedSymbol>>
val subroutineMemvars: Map<Subroutine, Set<MemoryMappedVariable>>
}

View File

@ -20,12 +20,10 @@ Blocked by an official Commander-x16 r39 release
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Ast modifications done in AsmGen, that should be done BEFORE calling asmgen (so that it doesn't have to modify the Ast any longer):
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
Ast modifications done in AsmGen that perhaps should not be necessary:
- block2asm: after vardecls2asm it clears the vardecl.value of all variables
- Maybe don't rely on vardecls at all any longer but figure out the variable allocations (including ZP allocations) beforehand
and pass that via a new datastructure to asmgen? So that asmgen is no longer tasked with doing the allocations.
This could perhaps make it easer for the codegen as well to deal with sections, if any, in the future.
--> Don't rely on vardecls at all any longer but use the new IVariablesAndConsts object passed to the AsmGen, this will solve this item.
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
- remove support for old @"screencodes" string encoding syntax (parser+code+docs)
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type
@ -54,6 +52,7 @@ Ast modifications done in AsmGen, that should be done BEFORE calling asmgen (so
Perhaps replace all uses of .proc/.pend by .block/.bend will fix that?
(but we lose the optimizing aspect of the assembler where it strips out unused code.
There's not really a dynamic switch possible as all assembly lib code is static and uses one or the other)
- zig 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 this)
- get rid of all TODO's in the code ;)