From 067283834af6c7fe189cdbbbbc75c074d4f65236 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 5 Mar 2022 14:26:33 +0100 Subject: [PATCH] got rid of old IVariablesAndConsts object --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 3 +- .../codegen/cpu6502/ProgramAndVarsGen.kt | 2 +- .../codegen/cpu6502/VariableAllocator.kt | 60 +----- .../prog8/codegen/experimental6502/AsmGen.kt | 1 - compiler/src/prog8/compiler/Compiler.kt | 8 +- .../astprocessing/VariablesAndConsts.kt | 183 ------------------ compiler/test/TestOptimization.kt | 1 - .../test/codegeneration/TestAsmGenSymbols.kt | 4 +- compiler/test/helpers/compileXyz.kt | 4 +- .../compilerinterface/IVariablesAndConsts.kt | 35 ---- .../prog8/compilerinterface/SymbolTable.kt | 23 ++- 11 files changed, 30 insertions(+), 294 deletions(-) delete mode 100644 compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt delete mode 100644 compilerInterfaces/src/prog8/compilerinterface/IVariablesAndConsts.kt diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 5ad1ef3bb..f3c262571 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -24,14 +24,13 @@ internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2" class AsmGen(internal val program: Program, internal val errors: IErrorReporter, internal val symbolTable: SymbolTable, - internal val variables: IVariablesAndConsts, internal val options: CompilationOptions): 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) internal val loopEndLabels = ArrayDeque() private val zeropage = options.compTarget.machine.zeropage - private val allocator = VariableAllocator(variables, symbolTable, options, errors) + private val allocator = VariableAllocator(symbolTable, options, errors) private val assemblyLines = mutableListOf() private val breakpointLabels = mutableListOf() private val forloopsAsmGen = ForLoopsAsmGen(program, this, zeropage) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index e8ea36a93..2f5ea2bb2 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -25,7 +25,7 @@ internal class ProgramAndVarsGen( val program: Program, val options: CompilationOptions, val errors: IErrorReporter, - private val symboltable: SymbolTable, // TODO stick this in Program + private val symboltable: SymbolTable, private val functioncallAsmGen: FunctionCallAsmGen, private val asmgen: AsmGen, private val allocator: VariableAllocator, diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index 60a9a031b..b87e7e0d2 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -11,8 +11,7 @@ import prog8.ast.statements.ZeropageWish import prog8.compilerinterface.* -internal class VariableAllocator(private val vars: IVariablesAndConsts, - private val symboltable: SymbolTable, +internal class VariableAllocator(private val symboltable: SymbolTable, private val options: CompilationOptions, private val errors: IErrorReporter) { @@ -36,53 +35,19 @@ internal class VariableAllocator(private val vars: IVariablesAndConsts, if(options.zeropage== ZeropageType.DONTUSE) return - val allVariablesOld = ( - vars.blockVars.asSequence().flatMap { it.value } + - vars.subroutineVars.asSequence().flatMap { it.value } - ).toList() - val allVariables = collectAllVariables(symboltable) - require(allVariables.size == allVariablesOld.size) - require(allVariables.map{it.scopedName}.toSet()==allVariablesOld.map{it.scopedname}.toSet()) - val numberOfAllocatableVariables = allVariablesOld.size - val varsRequiringZp = allVariablesOld.filter { it.zp == ZeropageWish.REQUIRE_ZEROPAGE } - val varsPreferringZp = allVariablesOld.filter { it.zp == ZeropageWish.PREFER_ZEROPAGE } - val varsDontCare = allVariablesOld.filter { it.zp == ZeropageWish.DONTCARE } - val numberOfExplicitNonZpVariables = allVariablesOld.count { it.zp == ZeropageWish.NOT_IN_ZEROPAGE } + val numberOfAllocatableVariables = allVariables.size + val varsRequiringZp = allVariables.filter { it.zpw == ZeropageWish.REQUIRE_ZEROPAGE } + val varsPreferringZp = allVariables.filter { it.zpw == ZeropageWish.PREFER_ZEROPAGE } + val varsDontCare = allVariables.filter { it.zpw == ZeropageWish.DONTCARE } + val numberOfExplicitNonZpVariables = allVariables.count { it.zpw == ZeropageWish.NOT_IN_ZEROPAGE } require(varsDontCare.size + varsRequiringZp.size + varsPreferringZp.size + numberOfExplicitNonZpVariables == numberOfAllocatableVariables) - val numberOfAllocatableVariables2 = allVariables.size - val varsRequiringZp2 = allVariables.filter { it.zpw == ZeropageWish.REQUIRE_ZEROPAGE } - val varsPreferringZp2 = allVariables.filter { it.zpw == ZeropageWish.PREFER_ZEROPAGE } - val varsDontCare2 = allVariables.filter { it.zpw == ZeropageWish.DONTCARE } - val numberOfExplicitNonZpVariables2 = allVariables.count { it.zpw == ZeropageWish.NOT_IN_ZEROPAGE } - require(varsDontCare2.size + varsRequiringZp2.size + varsPreferringZp2.size + numberOfExplicitNonZpVariables2 == numberOfAllocatableVariables2) - require(varsDontCare2.size==varsDontCare.size) - require(varsRequiringZp2.size==varsRequiringZp.size) - require(varsPreferringZp2.size==varsPreferringZp.size) - require(numberOfExplicitNonZpVariables2==numberOfExplicitNonZpVariables) - require(numberOfAllocatableVariables2==numberOfAllocatableVariables) - - val oldvarsByName = varsDontCare.associateBy { it.scopedname } - val newvarsByName = varsDontCare2.associateBy { it.scopedName } - require(oldvarsByName.keys==newvarsByName.keys) - oldvarsByName.forEach { (name, oldvar) -> - val newvar = newvarsByName.getValue(name) - require(oldvar.scopedname==newvar.scopedName) - require(oldvar.type==newvar.dt) - require(oldvar.zp==newvar.zpw) - require(oldvar.initialValue==newvar.initialvalue) - require(oldvar.arraysize==newvar.arraysize) - require(oldvar.position==newvar.position) - require(numArrayElements(oldvar) == numArrayElements(newvar)) - } - - var numVariablesAllocatedInZP = 0 var numberOfNonIntegerVariables = 0 - varsRequiringZp2.forEach { variable -> + varsRequiringZp.forEach { variable -> val numElements = numArrayElements(variable) val result = zeropage.allocate( variable.scopedName, @@ -103,7 +68,7 @@ internal class VariableAllocator(private val vars: IVariablesAndConsts, } if(errors.noErrors()) { - varsPreferringZp2.forEach { variable -> + varsPreferringZp.forEach { variable -> val numElements = numArrayElements(variable) val result = zeropage.allocate( variable.scopedName, @@ -120,7 +85,7 @@ internal class VariableAllocator(private val vars: IVariablesAndConsts, // try to allocate any other interger variables into the zeropage until it is full. // TODO some form of intelligent priorization? most often used variables first? loopcounter vars first? ...? if(errors.noErrors()) { - for (variable in varsDontCare2.sortedWith(compareBy({it.scopedName.size}, {it.name}))) { + for (variable in varsDontCare.sortedBy { it.scopedName.size }) { if(variable.dt in IntegerDatatypes) { if(zeropage.free.isEmpty()) { break @@ -163,13 +128,6 @@ internal class VariableAllocator(private val vars: IVariablesAndConsts, internal fun isZpVar(scopedName: List) = scopedName in zeropage.allocatedVariables - private fun numArrayElements(variable: IVariablesAndConsts.StaticVariable) = - when(variable.type) { - DataType.STR -> (variable.initialValue as StringLiteral).value.length - in ArrayDatatypes -> variable.arraysize!! - else -> null - } - private fun numArrayElements(variable: StStaticVariable) = when(variable.dt) { DataType.STR -> (variable.initialvalue as StringLiteral).value.length diff --git a/codeGenExperimental6502/src/prog8/codegen/experimental6502/AsmGen.kt b/codeGenExperimental6502/src/prog8/codegen/experimental6502/AsmGen.kt index eed16fa89..c68b8e04a 100644 --- a/codeGenExperimental6502/src/prog8/codegen/experimental6502/AsmGen.kt +++ b/codeGenExperimental6502/src/prog8/codegen/experimental6502/AsmGen.kt @@ -6,7 +6,6 @@ import prog8.compilerinterface.* class AsmGen(internal val program: Program, internal val errors: IErrorReporter, internal val symbolTable: SymbolTable, - internal val variables: IVariablesAndConsts, internal val options: CompilationOptions): IAssemblyGenerator { override fun compileToAssembly(): IAssemblyProgram? { diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index fdee58e4c..a7544a159 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -363,7 +363,6 @@ private fun writeAssembly(program: Program, compilerOptions.compTarget.machine.initializeZeropage(compilerOptions) program.processAstBeforeAsmGeneration(compilerOptions, errors) errors.report() - val variables = VariableExtractor().extractFrom(program) val symbolTable = SymbolTableMaker().makeFrom(program) // TODO make removing all VarDecls work, but this needs inferType to be able to get its information from somewhere else as the VarDecl nodes in the Ast, @@ -375,7 +374,7 @@ private fun writeAssembly(program: Program, // println("*********** AST RIGHT BEFORE ASM GENERATION *************") // printProgram(program) - val assembly = asmGeneratorFor(program, errors, symbolTable, variables, compilerOptions).compileToAssembly() + val assembly = asmGeneratorFor(program, errors, symbolTable, compilerOptions).compileToAssembly() errors.report() return if(assembly!=null && errors.noErrors()) { @@ -418,15 +417,14 @@ fun printProgram(program: Program) { internal fun asmGeneratorFor(program: Program, errors: IErrorReporter, symbolTable: SymbolTable, - variables: IVariablesAndConsts, options: CompilationOptions): IAssemblyGenerator { if(options.experimentalCodegen) { if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) - return prog8.codegen.experimental6502.AsmGen(program, errors, symbolTable, variables, options) + return prog8.codegen.experimental6502.AsmGen(program, errors, symbolTable, options) } else { if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) - return prog8.codegen.cpu6502.AsmGen(program, errors, symbolTable, variables, options) + return prog8.codegen.cpu6502.AsmGen(program, errors, symbolTable, options) } throw NotImplementedError("no asm generator for cpu ${options.compTarget.machine.cpu}") diff --git a/compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt b/compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt deleted file mode 100644 index 25d394257..000000000 --- a/compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt +++ /dev/null @@ -1,183 +0,0 @@ -package prog8.compiler.astprocessing - -import prog8.ast.Program -import prog8.ast.base.FatalAstException -import prog8.ast.base.VarDeclType -import prog8.ast.expressions.NumericLiteral -import prog8.ast.statements.Block -import prog8.ast.statements.Subroutine -import prog8.ast.statements.VarDecl -import prog8.ast.walk.IAstVisitor -import prog8.compilerinterface.IVariablesAndConsts - - -internal class VariableExtractor: IAstVisitor { - private val allBlockVars = mutableMapOf>() - private val allBlockConsts = mutableMapOf>() - private val allBlockMemoryvars = mutableMapOf>() - private val allSubroutineVars = mutableMapOf>() - private val allSubroutineConsts = mutableMapOf>() - private val allSubroutineMemoryvars = mutableMapOf>() - - fun extractFrom(program: Program): IVariablesAndConsts { - this.visit(program) - return VariablesAndConsts( - allBlockVars, allBlockConsts, allBlockMemoryvars, - allSubroutineVars, allSubroutineConsts, allSubroutineMemoryvars) - } - - override fun visit(decl: VarDecl) { - val scope=decl.definingScope - when (decl.type) { - VarDeclType.VAR -> { - when (scope) { - is Block -> { - val decls = allBlockVars[scope] ?: mutableSetOf() - decls.add(decl) - allBlockVars[scope] = decls - } - is Subroutine -> { - val decls = allSubroutineVars[scope] ?: mutableSetOf() - decls.add(decl) - allSubroutineVars[scope] = decls - } - else -> { - throw FatalAstException("var can only occur in subroutine or block scope") - } - } - } - VarDeclType.CONST -> { - when(scope) { - is Block -> { - val decls = allBlockConsts[scope] ?: mutableSetOf() - decls.add(decl) - allBlockConsts[scope] = decls - } - is Subroutine -> { - val decls = allSubroutineConsts[scope] ?: mutableSetOf() - decls.add(decl) - allSubroutineConsts[scope] = decls - } - else -> { - throw FatalAstException("var can only occur in subroutine or block scope") - } - } - } - VarDeclType.MEMORY -> { - when(scope) { - is Block -> { - val decls = allBlockMemoryvars[scope] ?: mutableSetOf() - decls.add(decl) - allBlockMemoryvars[scope] = decls - } - is Subroutine -> { - val decls = allSubroutineMemoryvars[scope] ?: mutableSetOf() - decls.add(decl) - allSubroutineMemoryvars[scope] = decls - } - else -> { - throw FatalAstException("var can only occur in subroutine or block scope") - } - } - } - else -> { - throw FatalAstException("invalid var type") - } - } - super.visit(decl) - } -} - -internal class VariablesAndConsts ( - astBlockVars: Map>, - astBlockConsts: Map>, - astBlockMemvars: Map>, - astSubroutineVars: Map>, - astSubroutineConsts: Map>, - astSubroutineMemvars: Map> -) : IVariablesAndConsts -{ - override val blockVars: Map> - override val blockConsts: Map> - override val blockMemvars: Map> - override val subroutineVars: Map> - override val subroutineConsts: Map> - override val subroutineMemvars: Map> - - private val bv = astBlockVars.keys.associateWith { mutableSetOf() } - private val bc = astBlockConsts.keys.associateWith { mutableSetOf() } - private val bmv = astBlockMemvars.keys.associateWith { mutableSetOf() } - private val sv = astSubroutineVars.keys.associateWith { mutableSetOf() } - private val sc = astSubroutineConsts.keys.associateWith { mutableSetOf() } - private val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf() } - - init { - astBlockVars.forEach { (block, decls) -> - val vars = bv.getValue(block) - vars.addAll(decls.map { toStatic(it) }) - } - astBlockConsts.forEach { (block, decls) -> - bc.getValue(block).addAll( - decls.map { - IVariablesAndConsts.ConstantNumberSymbol( - it.datatype, - it.scopedName, - (it.value as NumericLiteral).number, - it.position - ) - }) - } - astBlockMemvars.forEach { (block, decls) -> - val vars = bmv.getValue(block) - for(decl in decls) { - // make sure the 'stubs' for the scratch variables in zeropage are not included as normal variables - if(!decl.name.startsWith("P8ZP_SCRATCH_")) { - vars.add( - IVariablesAndConsts.MemoryMappedVariable( - decl.datatype, - decl.scopedName, - (decl.value as NumericLiteral).number.toUInt(), - decl.position - ) - ) - } - } - } - astSubroutineVars.forEach { (sub, decls) -> - val vars = sv.getValue(sub) - vars.addAll(decls.map { toStatic(it) }) - } - astSubroutineConsts.forEach { (sub, decls) -> - sc.getValue(sub).addAll( - decls.map { - IVariablesAndConsts.ConstantNumberSymbol( - it.datatype, - it.scopedName, - (it.value as NumericLiteral).number, - it.position - ) - }) - } - astSubroutineMemvars.forEach { (sub, decls) -> - smv.getValue(sub).addAll( - decls.map { - IVariablesAndConsts.MemoryMappedVariable( - it.datatype, - it.scopedName, - (it.value as NumericLiteral).number.toUInt(), - it.position - ) - }) - } - blockVars = bv - blockConsts = bc - blockMemvars = bmv - subroutineVars = sv - subroutineConsts = sc - subroutineMemvars = smv - } - - private fun toStatic(decl: VarDecl) = - IVariablesAndConsts.StaticVariable(decl.datatype, decl.scopedName, decl.value, decl.arraysize?.constIndex(), decl.zeropage, decl.position) - -} diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index 66f0258aa..6bcde1dfc 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -16,7 +16,6 @@ import prog8.ast.base.Position import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.codegen.target.C64Target -import prog8.compiler.astprocessing.VariableExtractor import prog8.compiler.astprocessing.processAstBeforeAsmGeneration import prog8.compiler.printProgram import prog8.compilerinterface.CompilationOptions diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 6cb2761cd..79aa3dc85 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -16,7 +16,6 @@ import prog8.codegen.cpu6502.AsmGen import prog8.codegen.target.C64Target import prog8.codegen.target.c64.C64Zeropage import prog8.compiler.astprocessing.SymbolTableMaker -import prog8.compiler.astprocessing.VariableExtractor import prog8.compilerinterface.* import prog8.parser.SourceCode import prog8tests.helpers.DummyFunctions @@ -80,8 +79,7 @@ class TestAsmGenSymbols: StringSpec({ val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target()) options.compTarget.machine.zeropage = C64Zeropage(options) val st = SymbolTableMaker().makeFrom(program) - val allocation = VariableExtractor().extractFrom(program) - return AsmGen(program, errors, st, allocation, options) + return AsmGen(program, errors, st, options) } "symbol and variable names from strings" { diff --git a/compiler/test/helpers/compileXyz.kt b/compiler/test/helpers/compileXyz.kt index f99881fe1..8c598ab55 100644 --- a/compiler/test/helpers/compileXyz.kt +++ b/compiler/test/helpers/compileXyz.kt @@ -9,7 +9,6 @@ import prog8.codegen.target.c64.C64Zeropage import prog8.compiler.CompilationResult import prog8.compiler.CompilerArguments import prog8.compiler.astprocessing.SymbolTableMaker -import prog8.compiler.astprocessing.VariableExtractor import prog8.compiler.compileProgram import prog8.compilerinterface.* import java.nio.file.Path @@ -89,8 +88,7 @@ internal fun generateAssembly( ): IAssemblyProgram? { val coptions = options ?: CompilationOptions(OutputType.RAW, CbmPrgLauncherType.BASIC, ZeropageType.DONTUSE, emptyList(), true, true, C64Target(), outputDir = outputDir) coptions.compTarget.machine.zeropage = C64Zeropage(coptions) - val variables = VariableExtractor().extractFrom(program) val st = SymbolTableMaker().makeFrom(program) - val asmgen = AsmGen(program, ErrorReporterForTests(), st, variables, coptions) + val asmgen = AsmGen(program, ErrorReporterForTests(), st, coptions) return asmgen.compileToAssembly() } diff --git a/compilerInterfaces/src/prog8/compilerinterface/IVariablesAndConsts.kt b/compilerInterfaces/src/prog8/compilerinterface/IVariablesAndConsts.kt deleted file mode 100644 index 5a24aa93a..000000000 --- a/compilerInterfaces/src/prog8/compilerinterface/IVariablesAndConsts.kt +++ /dev/null @@ -1,35 +0,0 @@ -package prog8.compilerinterface - -import prog8.ast.base.DataType -import prog8.ast.base.Position -import prog8.ast.expressions.Expression -import prog8.ast.statements.Block -import prog8.ast.statements.Subroutine -import prog8.ast.statements.ZeropageWish - -/** - * A more convenient way to pass variable (and constant values) definitions to the code generator, - * so that it doesn't have to scavenge and manipulate the VerDecl nodes in the AST for this information. - * - * note: the string variables are in here as well, they're in blockVars for the block named 'prog8_interned_strings'. - */ - -// TODO remove this, and replace with SymbolTable - -interface IVariablesAndConsts { - data class ConstantNumberSymbol(val type: DataType, val scopedname: List, val value: Double, val position: Position) - data class MemoryMappedVariable(val type: DataType, val scopedname: List, val address: UInt, val position: Position) - data class StaticVariable(val type: DataType, - val scopedname: List, - val initialValue: Expression?, - val arraysize: Int?, - val zp: ZeropageWish, - val position: Position) - - val blockVars: Map> - val blockConsts: Map> - val blockMemvars: Map> - val subroutineVars: Map> - val subroutineConsts: Map> - val subroutineMemvars: Map> -} diff --git a/compilerInterfaces/src/prog8/compilerinterface/SymbolTable.kt b/compilerInterfaces/src/prog8/compilerinterface/SymbolTable.kt index 29f0857a0..fa8e9fc56 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/SymbolTable.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/SymbolTable.kt @@ -8,6 +8,19 @@ import prog8.ast.statements.ZeropageWish import prog8.ast.toHex +/** + * Tree structure containing all symbol definitions in the program + * (blocks, subroutines, variables (all types) and labels). + */ +class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) { + fun print() = printIndented(0) + + override fun printProperties() { } + + val origAstLinks = mutableMapOf() // links of the original Ast nodes to the symbol table node. +} + + enum class StNodeType { GLOBAL, // MODULE, // not used with current scoping rules @@ -81,7 +94,7 @@ open class StNode(val name: String, } } - fun printIndented(indent: Int) { + protected fun printIndented(indent: Int) { print(" ".repeat(indent)) when(type) { StNodeType.GLOBAL -> print("SYMBOL-TABLE:") @@ -108,14 +121,6 @@ open class StNode(val name: String, } } -class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) { - fun print() = printIndented(0) - - override fun printProperties() { } - - val origAstLinks = mutableMapOf() // link the original Ast nodes into the table. TODO is this really needed? -} - class StStaticVariable(name: String, val dt: DataType, val initialvalue: Expression?,