mirror of
https://github.com/irmen/prog8.git
synced 2025-01-23 15:30:10 +00:00
uniform symbol prefixing with p8_
This commit is contained in:
parent
cad18b8a3a
commit
bb95484c8a
@ -94,6 +94,9 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
initialString = null
|
||||
numElements = node.arraySize?.toInt()
|
||||
}
|
||||
// if(node.type in SplitWordArrayTypes) {
|
||||
// TODO("split array also add _lsb and _msb to symboltable")
|
||||
// }
|
||||
StStaticVariable(node.name, node.type, initialNumeric, initialString, initialArray, numElements, node.zeropage, node)
|
||||
}
|
||||
is PtBuiltinFunctionCall -> {
|
||||
|
@ -63,9 +63,9 @@ class PtProgram(
|
||||
children.asSequence().filterIsInstance<PtBlock>()
|
||||
|
||||
fun entrypoint(): PtSub? =
|
||||
allBlocks().firstOrNull { it.name == "main" || it.name=="p8_main" }
|
||||
allBlocks().firstOrNull { it.name == "main" }
|
||||
?.children
|
||||
?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="p8_start" || it.name=="main.start" || it.name=="p8_main.p8_start") } as PtSub?
|
||||
?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="main.start") } as PtSub?
|
||||
}
|
||||
|
||||
|
||||
@ -73,6 +73,7 @@ class PtBlock(name: String,
|
||||
val address: UInt?,
|
||||
val library: Boolean,
|
||||
val forceOutput: Boolean,
|
||||
val noSymbolPrefixing: Boolean,
|
||||
val alignment: BlockAlignment,
|
||||
val source: SourceCode, // taken from the module the block is defined in.
|
||||
position: Position
|
||||
|
@ -3,6 +3,7 @@ package prog8.codegen.cpu6502
|
||||
import com.github.michaelbull.result.fold
|
||||
import prog8.code.StNodeType
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.SymbolTableMaker
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.codegen.cpu6502.assignment.*
|
||||
@ -14,18 +15,162 @@ import kotlin.io.path.writeLines
|
||||
internal const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
|
||||
internal const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
|
||||
|
||||
class AsmGen6502: ICodeGeneratorBackend {
|
||||
class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
|
||||
override fun generate(
|
||||
program: PtProgram,
|
||||
symbolTable: SymbolTable,
|
||||
options: CompilationOptions,
|
||||
errors: IErrorReporter
|
||||
): IAssemblyProgram? {
|
||||
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
|
||||
val st = if(prefixSymbols) prefixSymbols(program, options, symbolTable) else symbolTable
|
||||
val asmgen = AsmGen6502Internal(program, st, options, errors)
|
||||
return asmgen.compileToAssembly()
|
||||
}
|
||||
|
||||
private fun prefixSymbols(program: PtProgram, options: CompilationOptions, st: SymbolTable): SymbolTable {
|
||||
|
||||
printAst(program, true, ::println)
|
||||
|
||||
val nodesToPrefix = mutableListOf<Pair<PtNode, Int>>()
|
||||
|
||||
fun prefixNamedNode(node: PtNamedNode) {
|
||||
node.name = "p8_${node.name}"
|
||||
}
|
||||
|
||||
fun prefixSymbols(node: PtNode) {
|
||||
when(node) {
|
||||
is PtAsmSub -> {
|
||||
prefixNamedNode(node)
|
||||
node.parameters.forEach { (_, param) -> prefixNamedNode(param) }
|
||||
}
|
||||
is PtSub -> {
|
||||
prefixNamedNode(node)
|
||||
node.parameters.forEach { prefixNamedNode(it) }
|
||||
}
|
||||
is PtFunctionCall -> {
|
||||
val stNode = st.lookup(node.name)!!
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
var lookupName = node.name
|
||||
if(node.type in SplitWordArrayTypes && (lookupName.endsWith("_lsb") || lookupName.endsWith("_msb"))) {
|
||||
lookupName = lookupName.dropLast(4)
|
||||
}
|
||||
val stNode = st.lookup(lookupName)!!
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
is PtJump -> {
|
||||
if(node.identifier!=null) {
|
||||
val stNode = st.lookup(node.identifier!!.name)!!
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
else if(node.generatedLabel!=null) {
|
||||
val stNode = st.lookup(node.generatedLabel!!)!!
|
||||
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
}
|
||||
is PtBlock -> prefixNamedNode(node)
|
||||
is PtConstant -> prefixNamedNode(node)
|
||||
is PtLabel -> prefixNamedNode(node)
|
||||
is PtMemMapped -> prefixNamedNode(node)
|
||||
is PtSubroutineParameter -> prefixNamedNode(node)
|
||||
is PtVariable -> {
|
||||
val index = node.parent.children.indexOf(node)
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
else -> { }
|
||||
}
|
||||
node.children.forEach { prefixSymbols(it) }
|
||||
}
|
||||
|
||||
program.allBlocks().forEach { block ->
|
||||
if (!block.noSymbolPrefixing) {
|
||||
prefixSymbols(block)
|
||||
}
|
||||
}
|
||||
|
||||
nodesToPrefix.forEach { (parent, index) ->
|
||||
val node = parent.children[index]
|
||||
when(node) {
|
||||
is PtIdentifier -> parent.children[index] = node.prefix(parent)
|
||||
is PtFunctionCall -> parent.children[index] = node.prefix(parent)
|
||||
is PtJump -> parent.children[index] = node.prefix(parent)
|
||||
is PtVariable -> parent.children[index] = node.prefix(parent)
|
||||
else -> throw AssemblyError("weird node to prefix $node")
|
||||
}
|
||||
}
|
||||
|
||||
return SymbolTableMaker(program, options).make()
|
||||
}
|
||||
}
|
||||
|
||||
private fun PtVariable.prefix(parent: PtNode): PtVariable {
|
||||
name = name.split('.').map {"p8_$it" }.joinToString(".")
|
||||
if(value==null)
|
||||
return this
|
||||
|
||||
val arrayValue = value as? PtArray
|
||||
return if(arrayValue!=null && arrayValue.children.any { it !is PtNumber} ) {
|
||||
val newValue = PtArray(arrayValue.type, arrayValue.position)
|
||||
arrayValue.children.forEach { elt ->
|
||||
when(elt) {
|
||||
is PtIdentifier -> newValue.add(elt.prefix(arrayValue))
|
||||
is PtNumber -> newValue.add(elt)
|
||||
is PtAddressOf -> {
|
||||
val newAddr = PtAddressOf(elt.position)
|
||||
newAddr.children.add(elt.identifier.prefix(newAddr))
|
||||
newAddr.parent = arrayValue
|
||||
newValue.add(newAddr)
|
||||
}
|
||||
else -> throw AssemblyError("weird array value element $elt")
|
||||
}
|
||||
}
|
||||
PtVariable(name, type, zeropage, newValue, arraySize, position)
|
||||
}
|
||||
else this
|
||||
}
|
||||
|
||||
private fun PtJump.prefix(parent: PtNode): PtJump {
|
||||
val jump = if(identifier!=null) {
|
||||
val prefixedIdent = identifier!!.prefix(this)
|
||||
PtJump(prefixedIdent, address, generatedLabel, position)
|
||||
} else {
|
||||
val prefixedLabel = generatedLabel!!.split('.').map {"p8_$it" }.joinToString(".")
|
||||
PtJump(null, address, prefixedLabel, position)
|
||||
}
|
||||
jump.parent = parent
|
||||
return jump
|
||||
}
|
||||
|
||||
private fun PtFunctionCall.prefix(parent: PtNode): PtFunctionCall {
|
||||
val newName = name.split('.').map {"p8_$it" }.joinToString(".")
|
||||
val call = PtFunctionCall(newName, void, type, position)
|
||||
call.children.addAll(children)
|
||||
call.children.forEach { it.parent = call }
|
||||
call.parent = parent
|
||||
return call
|
||||
}
|
||||
|
||||
private fun PtIdentifier.prefix(parent: PtNode): PtIdentifier {
|
||||
val newName = name.split('.').map {"p8_$it" }.joinToString(".")
|
||||
val node = PtIdentifier(newName, type, position)
|
||||
node.parent = parent
|
||||
return node
|
||||
}
|
||||
|
||||
|
||||
class AsmGen6502Internal (
|
||||
val program: PtProgram,
|
||||
internal val symbolTable: SymbolTable,
|
||||
|
@ -40,9 +40,9 @@ class TestCodegen: FunSpec({
|
||||
// xx += cx16.r0
|
||||
// }
|
||||
//}
|
||||
val codegen = AsmGen6502()
|
||||
val codegen = AsmGen6502(prefixSymbols = false)
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("pi", DataType.UBYTE, ZeropageWish.DONTCARE, PtNumber(DataType.UBYTE, 0.0, Position.DUMMY), null, Position.DUMMY))
|
||||
sub.add(PtVariable("particleX", DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, 3u, Position.DUMMY))
|
||||
@ -92,7 +92,7 @@ class TestCodegen: FunSpec({
|
||||
program.add(block)
|
||||
|
||||
// define the "cx16.r0" virtual register
|
||||
val cx16block = PtBlock("cx16", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val cx16block = PtBlock("cx16", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
cx16block.add(PtMemMapped("r0", DataType.UWORD, 100u, null, Position.DUMMY))
|
||||
program.add(cx16block)
|
||||
|
||||
|
@ -135,8 +135,8 @@ class IRUnusedCodeRemover(
|
||||
}
|
||||
|
||||
private fun removeUnreachable(allLabeledChunks: MutableMap<String, IRCodeChunkBase>): Int {
|
||||
val entrypointSub = irprog.blocks.single { it.label=="main" || it.label=="p8_main" }
|
||||
.children.single { it is IRSubroutine && (it.label=="main.start" || it.label=="p8_main.p8_start") }
|
||||
val entrypointSub = irprog.blocks.single { it.label=="main" }
|
||||
.children.single { it is IRSubroutine && it.label=="main.start" }
|
||||
val reachable = mutableSetOf((entrypointSub as IRSubroutine).chunks.first())
|
||||
|
||||
fun grow() {
|
||||
|
@ -41,7 +41,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("pi", DataType.UBYTE, ZeropageWish.DONTCARE, PtNumber(DataType.UBYTE, 0.0, Position.DUMMY), null, Position.DUMMY))
|
||||
sub.add(PtVariable("particleX", DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, 3u, Position.DUMMY))
|
||||
@ -91,7 +91,7 @@ class TestVmCodeGen: FunSpec({
|
||||
program.add(block)
|
||||
|
||||
// define the "cx16.r0" virtual register
|
||||
val cx16block = PtBlock("cx16", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val cx16block = PtBlock("cx16", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
cx16block.add(PtMemMapped("r0", DataType.UWORD, 100u, null, Position.DUMMY))
|
||||
program.add(cx16block)
|
||||
|
||||
@ -120,7 +120,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -183,7 +183,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -242,7 +242,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -289,7 +289,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -352,7 +352,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -411,7 +411,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("ub1", DataType.UBYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
@ -451,7 +451,7 @@ class TestVmCodeGen: FunSpec({
|
||||
//}
|
||||
val codegen = VmCodeGen()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val block = PtBlock("main", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("test"), Position.DUMMY)
|
||||
val romsub = PtAsmSub("routine", 0x5000u, setOf(CpuRegister.Y), emptyList(), emptyList(), false, Position.DUMMY)
|
||||
block.add(romsub)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
|
@ -6,10 +6,10 @@ package prog8.buildversion
|
||||
const val MAVEN_GROUP = "prog8"
|
||||
const val MAVEN_NAME = "compiler"
|
||||
const val VERSION = "9.1-SNAPSHOT"
|
||||
const val GIT_REVISION = 3909
|
||||
const val GIT_SHA = "04da44eb988e4c2abef4099f86888b95074cc453"
|
||||
const val GIT_DATE = "2023-06-29T20:56:26Z"
|
||||
const val GIT_REVISION = -1
|
||||
const val GIT_SHA = "bf86e1f41d9c97d3b56e91e5217bcda258fa3e09"
|
||||
const val GIT_DATE = "UNKNOWN"
|
||||
const val GIT_BRANCH = "prefixing"
|
||||
const val BUILD_DATE = "2023-06-29T21:18:59Z"
|
||||
const val BUILD_UNIX_TIME = 1688073539609L
|
||||
const val BUILD_DATE = "2023-06-30T23:38:56Z"
|
||||
const val BUILD_UNIX_TIME = 1688168336048L
|
||||
const val DIRTY = 1
|
||||
|
@ -406,7 +406,7 @@ private fun createAssemblyAndAssemble(program: PtProgram,
|
||||
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()
|
||||
prog8.codegen.cpu6502.AsmGen6502(prefixSymbols = true)
|
||||
else if (compilerOptions.compTarget.name == VMTarget.NAME)
|
||||
VmCodeGen()
|
||||
else
|
||||
|
@ -1,88 +0,0 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
|
||||
class AsmSymbolsPrefixer(val program: Program): AstWalker() {
|
||||
|
||||
override fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> {
|
||||
if("no_symbol_prefixing" in identifier.targetStatement(program)!!.definingBlock.options())
|
||||
return noModifications
|
||||
if(identifier.nameInSource.size==1 && identifier.nameInSource[0] in program.builtinFunctions.names)
|
||||
return noModifications
|
||||
|
||||
val newName = identifier.nameInSource.map { part -> "p8_$part" }
|
||||
return listOf(IAstModification.ReplaceNode(identifier, identifier.renamed(newName), parent))
|
||||
}
|
||||
|
||||
override fun after(label: Label, parent: Node): Iterable<IAstModification> {
|
||||
return if("no_symbol_prefixing" in label.definingBlock.options())
|
||||
noModifications
|
||||
else
|
||||
listOf(IAstModification.ReplaceNode(label, label.renamed("p8_${label.name}"), parent))
|
||||
}
|
||||
|
||||
override fun after(block: Block, parent: Node): Iterable<IAstModification> {
|
||||
return if("no_symbol_prefixing" in block.options())
|
||||
noModifications
|
||||
else
|
||||
listOf(IAstModification.ReplaceNode(block, block.renamed("p8_${block.name}"), parent))
|
||||
}
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
return if("no_symbol_prefixing" in decl.definingBlock.options())
|
||||
noModifications
|
||||
else
|
||||
listOf(IAstModification.ReplaceNode(decl, decl.renamed("p8_${decl.name}"), parent))
|
||||
}
|
||||
|
||||
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
||||
if("no_symbol_prefixing" in subroutine.definingBlock.options())
|
||||
return noModifications
|
||||
|
||||
val changedParams = mutableListOf<Pair<Int, SubroutineParameter>>()
|
||||
subroutine.parameters.withIndex().forEach { (index, param) ->
|
||||
if((param.name.length==3 || param.name.length==1) && param.name.all { it.isLetter() } && !param.definingModule.isLibrary) {
|
||||
changedParams.add(index to SubroutineParameter("p8_${param.name}", param.type, param.position))
|
||||
}
|
||||
}
|
||||
|
||||
changedParams.forEach { (index, newParam) -> subroutine.parameters[index] = newParam }
|
||||
val newName = "p8_${subroutine.name}"
|
||||
|
||||
return if(newName!=subroutine.name || changedParams.isNotEmpty()) {
|
||||
val newSub = Subroutine(newName, subroutine.parameters, subroutine.returntypes,
|
||||
subroutine.asmParameterRegisters, subroutine.asmReturnvaluesRegisters, subroutine.asmClobbers, subroutine.asmAddress, subroutine.isAsmSubroutine,
|
||||
subroutine.inline, false, subroutine.statements, subroutine.position)
|
||||
if(changedParams.isNotEmpty())
|
||||
subsWithParamRefsToFix += newSub
|
||||
listOf(IAstModification.ReplaceNode(subroutine, newSub, parent))
|
||||
} else {
|
||||
if(changedParams.isNotEmpty())
|
||||
subsWithParamRefsToFix += subroutine
|
||||
noModifications
|
||||
}
|
||||
}
|
||||
|
||||
private val subsWithParamRefsToFix = mutableListOf<Subroutine>()
|
||||
|
||||
override fun applyModifications(): Int {
|
||||
var count = super.applyModifications()
|
||||
subsWithParamRefsToFix.forEach { subroutine ->
|
||||
subroutine.statements.withIndex().reversed().forEach { (index,stmt) ->
|
||||
if(stmt is VarDecl && stmt.origin==VarDeclOrigin.SUBROUTINEPARAM) {
|
||||
val param = subroutine.parameters.single { it.name == stmt.name}
|
||||
val decl = VarDecl.fromParameter(param)
|
||||
subroutine.statements[index] = decl
|
||||
decl.linkParents(subroutine)
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
}
|
@ -24,16 +24,14 @@ internal class AstChecker(private val program: Program,
|
||||
override fun visit(program: Program) {
|
||||
require(program === this.program)
|
||||
// there must be a single 'main' block with a 'start' subroutine for the program entry point.
|
||||
val mainBlocks = program.modules.flatMap { it.statements }.filter { b -> b is Block && (b.name=="main" || b.name=="p8_main") }.map { it as Block }
|
||||
val mainBlocks = program.modules.flatMap { it.statements }.filter { b -> b is Block && b.name=="main" }.map { it as Block }
|
||||
if(mainBlocks.size>1)
|
||||
errors.err("more than one 'main' block", mainBlocks[0].position)
|
||||
if(mainBlocks.isEmpty())
|
||||
errors.err("there is no 'main' block", program.modules.firstOrNull()?.position ?: Position.DUMMY)
|
||||
|
||||
for(mainBlock in mainBlocks) {
|
||||
var startSub = mainBlock.subScope("start") as? Subroutine
|
||||
if(startSub==null)
|
||||
startSub = mainBlock.subScope("p8_start") as? Subroutine
|
||||
val startSub = mainBlock.subScope("start") as? Subroutine
|
||||
if (startSub == null) {
|
||||
errors.err("missing program entrypoint ('start' subroutine in 'main' block)", mainBlock.position)
|
||||
} else {
|
||||
|
@ -12,7 +12,6 @@ import prog8.ast.statements.VarDeclOrigin
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.VMTarget
|
||||
|
||||
|
||||
internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) {
|
||||
@ -28,12 +27,6 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
|
||||
boolRemover.visit(this)
|
||||
boolRemover.applyModifications()
|
||||
|
||||
if(compilerOptions.compTarget.name!=VMTarget.NAME) {
|
||||
val replacer = AsmSymbolsPrefixer(this)
|
||||
replacer.visit(this)
|
||||
replacer.applyModifications()
|
||||
}
|
||||
|
||||
val fixer = BeforeAsmAstChanger(this, compilerOptions, errors)
|
||||
fixer.visit(this)
|
||||
while (errors.noErrors() && fixer.applyModifications() > 0) {
|
||||
|
@ -161,21 +161,23 @@ class IntermediateAstMaker(private val program: Program, private val options: Co
|
||||
private fun transform(srcBlock: Block): PtBlock {
|
||||
var alignment = PtBlock.BlockAlignment.NONE
|
||||
var forceOutput = false
|
||||
var noSymbolPrefixing = false
|
||||
val directives = srcBlock.statements.filterIsInstance<Directive>()
|
||||
for (directive in directives.filter { it.directive == "%option" }) {
|
||||
for (arg in directive.args) {
|
||||
when (arg.name) {
|
||||
"align_word" -> alignment = PtBlock.BlockAlignment.WORD
|
||||
"align_page" -> alignment = PtBlock.BlockAlignment.PAGE
|
||||
"no_symbol_prefixing" -> noSymbolPrefixing = true
|
||||
"force_output" -> forceOutput=true
|
||||
"merge", "splitarrays", "no_symbol_prefixing" -> { /* ignore this one */ }
|
||||
"merge", "splitarrays" -> { /* ignore this one */ }
|
||||
else -> throw FatalAstException("weird directive option: ${arg.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
val (vardecls, statements) = srcBlock.statements.partition { it is VarDecl }
|
||||
val src = srcBlock.definingModule.source
|
||||
val block = PtBlock(srcBlock.name, srcBlock.address, srcBlock.isInLibrary, forceOutput, alignment, src, srcBlock.position)
|
||||
val block = PtBlock(srcBlock.name, srcBlock.address, srcBlock.isInLibrary, forceOutput, noSymbolPrefixing, alignment, src, srcBlock.position)
|
||||
makeScopeVarsDecls(vardecls).forEach { block.add(it) }
|
||||
for (stmt in statements)
|
||||
block.add(transformStatement(stmt))
|
||||
@ -434,11 +436,10 @@ class IntermediateAstMaker(private val program: Program, private val options: Co
|
||||
private fun transform(src: AddressOf): PtAddressOf {
|
||||
val addr = PtAddressOf(src.position)
|
||||
val (name, dt) = src.identifier.targetNameAndType(program)
|
||||
if(dt in SplitWordArrayTypes) {
|
||||
addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position))
|
||||
} else {
|
||||
if(dt in SplitWordArrayTypes)
|
||||
addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position)) // NOTE: assumes _lsb is first in memory! (immediately followed by _msb)
|
||||
else
|
||||
addr.add(transform(src.identifier))
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ internal class StatementReorderer(val program: Program,
|
||||
val (blocks, other) = module.statements.partition { it is Block }
|
||||
module.statements = other.asSequence().plus(blocks.sortedBy { (it as Block).address ?: UInt.MAX_VALUE }).toMutableList()
|
||||
|
||||
val mainBlock = module.statements.asSequence().filterIsInstance<Block>().firstOrNull { it.name=="main" || it.name=="p8_main"}
|
||||
val mainBlock = module.statements.asSequence().filterIsInstance<Block>().firstOrNull { it.name=="main" }
|
||||
if(mainBlock!=null && mainBlock.address==null) {
|
||||
module.statements.remove(mainBlock)
|
||||
module.statements.add(0, mainBlock)
|
||||
|
@ -90,7 +90,7 @@ private fun makeSt(): SymbolTable {
|
||||
|
||||
// first build the AST
|
||||
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val astBlock1 = PtBlock("block1", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block1"), Position.DUMMY)
|
||||
val astBlock1 = PtBlock("block1", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block1"), Position.DUMMY)
|
||||
val astConstant1 = PtConstant("c1", DataType.UWORD, 12345.0, Position.DUMMY)
|
||||
val astConstant2 = PtConstant("blockc", DataType.UWORD, 999.0, Position.DUMMY)
|
||||
astBlock1.add(astConstant1)
|
||||
@ -113,7 +113,7 @@ private fun makeSt(): SymbolTable {
|
||||
astBlock1.add(astSub2)
|
||||
val astBfunc = PtIdentifier("msb", DataType.UBYTE, Position.DUMMY)
|
||||
astBlock1.add(astBfunc)
|
||||
val astBlock2 = PtBlock("block2", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block2"), Position.DUMMY)
|
||||
val astBlock2 = PtBlock("block2", null, false, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block2"), Position.DUMMY)
|
||||
val astSub21 = PtSub("sub1", emptyList(), null, Position.DUMMY)
|
||||
val astSub22 = PtSub("sub2", emptyList(), null, Position.DUMMY)
|
||||
val astSub221 = PtSub("subsub", emptyList(), null, Position.DUMMY)
|
||||
|
@ -62,7 +62,7 @@ class TestTypecasts: FunSpec({
|
||||
val expr2 = (stmts2[4] as Assignment).value as BinaryExpression
|
||||
expr2.operator shouldBe "&"
|
||||
expr2.right shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY)
|
||||
(expr2.left as IdentifierReference).nameInSource shouldBe listOf("p8_bb")
|
||||
(expr2.left as IdentifierReference).nameInSource shouldBe listOf("bb")
|
||||
}
|
||||
|
||||
test("bool expressions with functioncalls") {
|
||||
@ -107,7 +107,7 @@ main {
|
||||
val assignValue1 = (stmts[7] as Assignment).value as IdentifierReference
|
||||
val assignValue2 = (stmts[11] as Assignment).value as BinaryExpression
|
||||
val assignValue3 = (stmts[12] as Assignment).value as BinaryExpression
|
||||
assignValue1.nameInSource shouldBe listOf("p8_ub1")
|
||||
assignValue1.nameInSource shouldBe listOf("ub1")
|
||||
assignValue2.operator shouldBe "^"
|
||||
assignValue3.operator shouldBe "&"
|
||||
val right2 = assignValue2.right as BinaryExpression
|
||||
|
@ -121,11 +121,11 @@ main {
|
||||
|
||||
sub start() {
|
||||
%asm {{
|
||||
lda normal
|
||||
lda uw_lsb
|
||||
lda uw_msb
|
||||
lda sw_lsb
|
||||
lda sw_msb
|
||||
lda p8_normal
|
||||
lda p8_uw_lsb
|
||||
lda p8_uw_msb
|
||||
lda p8_sw_lsb
|
||||
lda p8_sw_msb
|
||||
}}
|
||||
}
|
||||
}"""
|
||||
|
@ -12,6 +12,7 @@ import prog8.code.ast.PtAssignment
|
||||
import prog8.code.ast.PtVariable
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.Cx16Target
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
import prog8tests.helpers.compileText
|
||||
@ -202,4 +203,60 @@ block2 {
|
||||
compileText(C64Target(), true, src, writeAssembly = true) shouldNotBe null
|
||||
compileText(VMTarget(), true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
test("array with pointers") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
str localstr = "hello"
|
||||
ubyte[] otherarray = [1,2,3]
|
||||
uword[] words = [1111,2222,"three",&localstr,&otherarray]
|
||||
uword @shared zz = &words
|
||||
ubyte result = 2222 in words
|
||||
zz = words[2]
|
||||
zz++
|
||||
zz = words[3]
|
||||
}
|
||||
}"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
test("case sensitive symbols") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte bytevar = 11 ; var at 0
|
||||
ubyte byteVAR = 22 ; var at 1
|
||||
ubyte ByteVar = 33 ; var at 2
|
||||
ubyte @shared total = bytevar+byteVAR+ByteVar ; var at 3
|
||||
goto skipLABEL
|
||||
SkipLabel:
|
||||
return
|
||||
skipLABEL:
|
||||
bytevar = 42
|
||||
}
|
||||
}"""
|
||||
val target = Cx16Target()
|
||||
compileText(target, true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
test("addresses from labels/subroutines") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
mylabel:
|
||||
ubyte variable
|
||||
uword @shared pointer1 = &main.start
|
||||
uword @shared pointer2 = &start
|
||||
uword @shared pointer3 = &main.start.mylabel
|
||||
uword @shared pointer4 = &mylabel
|
||||
uword[] @shared ptrs = [&variable, &start, &main.start, &mylabel, &main.start.mylabel]
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
compileText(Cx16Target(), true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
})
|
@ -53,8 +53,6 @@ main {
|
||||
zz = words[3]
|
||||
}
|
||||
}"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
@ -165,10 +163,7 @@ skipLABEL:
|
||||
bytevar = 42
|
||||
}
|
||||
}"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val result = compileText(VMTarget(), true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
||||
vm.memory.getUB(0) shouldBe 42u
|
||||
@ -283,11 +278,7 @@ mylabel:
|
||||
}
|
||||
|
||||
"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true) shouldNotBe null
|
||||
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, false, src, writeAssembly = true)!!
|
||||
val result = compileText(VMTarget(), false, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir")
|
||||
val exc = shouldThrow<Exception> {
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
|
@ -55,12 +55,10 @@ class Program(val name: String,
|
||||
|
||||
val entrypoint: Subroutine
|
||||
get() {
|
||||
val mainBlocks = allBlocks.filter { it.name=="main" || it.name=="p8_main" }
|
||||
val mainBlocks = allBlocks.filter { it.name=="main" }
|
||||
return when (mainBlocks.size) {
|
||||
0 -> throw FatalAstException("no 'main' block")
|
||||
1 -> {
|
||||
mainBlocks[0].subScope("start") as? Subroutine ?: mainBlocks[0].subScope("p8_start") as Subroutine
|
||||
}
|
||||
1 -> mainBlocks[0].subScope("start") as Subroutine
|
||||
else -> throw FatalAstException("more than one 'main' block")
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- AsmSymbolsPrefixer not on compiler Ast but on PtProgram - remove all "p8_main" and "p8_start" checks again
|
||||
|
||||
- prog8->asm symbol name prefixing: prefix ALL symbols with p8_ Also update manual.
|
||||
- prog8->asm symbol name prefixing: prefix ALL symbols with p8_
|
||||
EXCEPTION: library symbols such as cbm.CHROUT, cx16.r0 etc. should NOT be prefixed.
|
||||
Solution: add %option no_symbol_prefix to those blocks?
|
||||
- Also update manual
|
||||
|
||||
...
|
||||
|
||||
|
@ -1,80 +1,9 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
uword count = 255
|
||||
cx16.r0 = 0
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
|
||||
count=256
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count = 257
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256+257)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count=1023
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256+257+1023)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count=1024
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256+257+1023+1024)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count = 1025
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(255+256+257+1023+1024+1025)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count = 65534
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(3838)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
count = 65535
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
count=0
|
||||
repeat count {
|
||||
cx16.r0++
|
||||
}
|
||||
repeat 0 {
|
||||
cx16.r0++
|
||||
}
|
||||
txt.print_uw(3837)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
str name1 = "name1"
|
||||
str name2 = "name2"
|
||||
uword[] @split names = [name1, name2, "name3"]
|
||||
cx16.r0++
|
||||
names = [1111,2222,3333]
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user