mirror of
https://github.com/irmen/prog8.git
synced 2024-09-08 10:55:08 +00:00
improved string constant interning; no longer output duplicate strings in the Ast
This commit is contained in:
parent
fa527f8624
commit
ab544ee965
@ -178,7 +178,7 @@ c64 {
|
|||||||
|
|
||||||
; ---- C64 ROM kernal routines ----
|
; ---- C64 ROM kernal routines ----
|
||||||
|
|
||||||
romsub $AB1E = STROUT(uword strptr @ AY) clobbers(A, X, Y) ; print null-terminated string (use c64scr.print instead)
|
romsub $AB1E = STROUT(uword strptr @ AY) clobbers(A, X, Y) ; print null-terminated string (use txt.print instead)
|
||||||
romsub $E544 = CLEARSCR() clobbers(A,X,Y) ; clear the screen
|
romsub $E544 = CLEARSCR() clobbers(A,X,Y) ; clear the screen
|
||||||
romsub $E566 = HOMECRSR() clobbers(A,X,Y) ; cursor to top left of screen
|
romsub $E566 = HOMECRSR() clobbers(A,X,Y) ; cursor to top left of screen
|
||||||
romsub $EA31 = IRQDFRT() clobbers(A,X,Y) ; default IRQ routine
|
romsub $EA31 = IRQDFRT() clobbers(A,X,Y) ; default IRQ routine
|
||||||
|
@ -172,7 +172,6 @@ private fun parseImports(filepath: Path, errors: ErrorReporter): Triple<Program,
|
|||||||
errors.handle()
|
errors.handle()
|
||||||
|
|
||||||
val importedFiles = programAst.modules.filter { !it.source.startsWith("@embedded@") }.map { it.source }
|
val importedFiles = programAst.modules.filter { !it.source.startsWith("@embedded@") }.map { it.source }
|
||||||
|
|
||||||
val compilerOptions = determineCompilationOptions(programAst)
|
val compilerOptions = determineCompilationOptions(programAst)
|
||||||
if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG)
|
if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG)
|
||||||
throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.")
|
throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.")
|
||||||
@ -188,7 +187,7 @@ private fun parseImports(filepath: Path, errors: ErrorReporter): Triple<Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun determineCompilationOptions(program: Program): CompilationOptions {
|
private fun determineCompilationOptions(program: Program): CompilationOptions {
|
||||||
val mainModule = program.modules.first()
|
val mainModule = program.mainModule
|
||||||
val outputType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" }
|
val outputType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" }
|
||||||
as? Directive)?.args?.single()?.name?.toUpperCase()
|
as? Directive)?.args?.single()?.name?.toUpperCase()
|
||||||
val launcherType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" }
|
val launcherType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" }
|
||||||
|
@ -17,13 +17,10 @@ internal class LiteralsToAutoVars(private val program: Program) : AstWalker() {
|
|||||||
|
|
||||||
override fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> {
|
override fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> {
|
||||||
if(string.parent !is VarDecl && string.parent !is WhenChoice) {
|
if(string.parent !is VarDecl && string.parent !is WhenChoice) {
|
||||||
// replace the literal string by a identifier reference to a new local vardecl
|
// replace the literal string by a identifier reference to the interned string
|
||||||
val vardecl = VarDecl.createAuto(string)
|
val scopedName = program.internString(string)
|
||||||
val identifier = IdentifierReference(listOf(vardecl.name), vardecl.position)
|
val identifier = IdentifierReference(scopedName, string.position)
|
||||||
return listOf(
|
return listOf(IAstModification.ReplaceNode(string, identifier, parent))
|
||||||
IAstModification.ReplaceNode(string, identifier, parent),
|
|
||||||
IAstModification.InsertFirst(vardecl, string.definingScope())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package prog8.ast
|
package prog8.ast
|
||||||
|
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.expressions.Expression
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.expressions.IdentifierReference
|
|
||||||
import prog8.ast.expressions.InferredTypes
|
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstVisitor
|
import prog8.ast.walk.IAstVisitor
|
||||||
@ -258,10 +255,26 @@ interface IBuiltinFunctions {
|
|||||||
class Program(val name: String, val modules: MutableList<Module>, val builtinFunctions: IBuiltinFunctions): Node {
|
class Program(val name: String, val modules: MutableList<Module>, val builtinFunctions: IBuiltinFunctions): Node {
|
||||||
val namespace = GlobalNamespace(modules, builtinFunctions.names)
|
val namespace = GlobalNamespace(modules, builtinFunctions.names)
|
||||||
|
|
||||||
|
val mainModule: Module
|
||||||
|
get() = modules.first { it.name!=internedStringsModuleName }
|
||||||
val definedLoadAddress: Int
|
val definedLoadAddress: Int
|
||||||
get() = modules.first().loadAddress
|
get() = mainModule.loadAddress
|
||||||
|
|
||||||
var actualLoadAddress: Int = 0
|
var actualLoadAddress: Int = 0
|
||||||
|
private val internedStrings = mutableMapOf<String, List<String>>()
|
||||||
|
val internedStringsModuleName = "prog8_interned_strings"
|
||||||
|
|
||||||
|
init {
|
||||||
|
// insert a container module for all interned strings later
|
||||||
|
if(modules.firstOrNull()?.name != internedStringsModuleName) {
|
||||||
|
val internedStringsModule = Module(internedStringsModuleName, mutableListOf(), Position.DUMMY, false, Path.of(""))
|
||||||
|
modules.add(0, internedStringsModule)
|
||||||
|
val block = Block(internedStringsModuleName, null, mutableListOf(), false, Position.DUMMY)
|
||||||
|
internedStringsModule.statements.add(block)
|
||||||
|
internedStringsModule.linkParents(this)
|
||||||
|
internedStringsModule.program = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun entrypoint(): Subroutine? {
|
fun entrypoint(): Subroutine? {
|
||||||
val mainBlocks = allBlocks().filter { it.name=="main" }
|
val mainBlocks = allBlocks().filter { it.name=="main" }
|
||||||
@ -274,6 +287,21 @@ class Program(val name: String, val modules: MutableList<Module>, val builtinFun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun internString(string: StringLiteralValue): List<String> {
|
||||||
|
val existing = internedStrings[string.value]
|
||||||
|
if(existing!=null)
|
||||||
|
return existing
|
||||||
|
|
||||||
|
val decl = VarDecl(VarDeclType.VAR, DataType.STR, ZeropageWish.NOT_IN_ZEROPAGE, null, "string_${internedStrings.size}", null, string,
|
||||||
|
isArray = false, autogeneratedDontRemove = true, position = string.position)
|
||||||
|
val internedStringsBlock = modules.first { it.name==internedStringsModuleName }.statements.first { it is Block && it.name == internedStringsModuleName}
|
||||||
|
(internedStringsBlock as Block).statements.add(decl)
|
||||||
|
decl.linkParents(internedStringsBlock)
|
||||||
|
val scopedName = listOf(internedStringsModuleName, decl.name)
|
||||||
|
internedStrings[string.value] = scopedName
|
||||||
|
return scopedName
|
||||||
|
}
|
||||||
|
|
||||||
fun allBlocks(): List<Block> = modules.flatMap { it.statements.filterIsInstance<Block>() }
|
fun allBlocks(): List<Block> = modules.flatMap { it.statements.filterIsInstance<Block>() }
|
||||||
|
|
||||||
override val position: Position = Position.DUMMY
|
override val position: Position = Position.DUMMY
|
||||||
|
@ -176,12 +176,6 @@ open class VarDecl(val type: VarDeclType,
|
|||||||
companion object {
|
companion object {
|
||||||
private var autoHeapValueSequenceNumber = 0
|
private var autoHeapValueSequenceNumber = 0
|
||||||
|
|
||||||
fun createAuto(string: StringLiteralValue): VarDecl {
|
|
||||||
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
|
||||||
return VarDecl(VarDeclType.VAR, DataType.STR, ZeropageWish.NOT_IN_ZEROPAGE, null, autoVarName, null, string,
|
|
||||||
isArray = false, autogeneratedDontRemove = true, position = string.position)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createAuto(array: ArrayLiteralValue): VarDecl {
|
fun createAuto(array: ArrayLiteralValue): VarDecl {
|
||||||
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
||||||
val arrayDt =
|
val arrayDt =
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
- auto_heap_value for strings: avoid creating multiple values for identical strings (or fix it at the end)
|
|
||||||
- add sound to the cx16 tehtriz
|
- add sound to the cx16 tehtriz
|
||||||
- refactor the asmgen into their own submodule?
|
- refactor the asmgen into their own submodule?
|
||||||
- refactor the compiler optimizers into their own submodule?
|
- refactor the compiler optimizers into their own submodule?
|
||||||
|
Loading…
Reference in New Issue
Block a user