working on new Ast and XML export to test it

This commit is contained in:
Irmen de Jong 2022-03-12 19:44:51 +01:00
parent e227cc92ff
commit 40e9fba312
11 changed files with 848 additions and 144 deletions

View File

@ -3,6 +3,7 @@ package prog8.code.ast
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.core.Position
import java.util.*
// New (work-in-progress) simplified AST for the code generator.
@ -62,6 +63,9 @@ class PtProgram(
print("'$name'")
}
fun allModuleDirectives(): Sequence<PtDirective> =
children.asSequence().flatMap { it.children }.filterIsInstance<PtDirective>().distinct()
fun allBlocks(): Sequence<PtBlock> =
children.asSequence().flatMap { it.children }.filterIsInstance<PtBlock>()
@ -72,7 +76,7 @@ class PtProgram(
class PtModule(
name: String,
val loadAddress: UInt,
val loadAddress: UInt?,
val library: Boolean,
position: Position
) : PtNamedNode(name, position) {
@ -100,6 +104,18 @@ class PtDirective(var name: String, position: Position) : PtNode(position) {
override fun printProperties() {
print(name)
}
override fun hashCode(): Int {
return Objects.hash(name, args)
}
override fun equals(other: Any?): Boolean {
if(other !is PtDirective)
return false
if(other===this)
return true
return(name==other.name && args.zip(other.args).all { it.first==it.second })
}
}
@ -111,6 +127,18 @@ class PtDirectiveArg(val str: String?,
override fun printProperties() {
print("str=$str name=$name int=$int")
}
override fun hashCode(): Int {
return Objects.hash(str, name, int)
}
override fun equals(other: Any?): Boolean {
if(other !is PtDirectiveArg)
return false
if(other===this)
return true
return str==other.str || name==other.name || int==other.int
}
}

View File

@ -5,76 +5,115 @@ import prog8.code.core.Encoding
import prog8.code.core.Position
class PtAddressOf(position: Position) : PtNode(position) {
val identifier: PtIdentifier
get() = children.single() as PtIdentifier
override fun printProperties() {}
}
class PtArrayIndexer(position: Position): PtNode(position) {
val variable: PtIdentifier
get() = children[0] as PtIdentifier
val index: PtNode
get() = children[1]
override fun printProperties() {}
}
class PtArrayLiteral(val type: DataType, position: Position): PtNode(position) {
sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) {
override fun printProperties() {
print(type)
}
}
class PtBinaryExpression(val operator: String, position: Position): PtNode(position) {
val left: PtNode
get() = children[0]
val right: PtNode
get() = children[1]
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
val identifier: PtIdentifier
get() = children.single() as PtIdentifier
}
class PtArrayIndexer(type: DataType, position: Position): PtExpression(type, position) {
val variable: PtIdentifier
get() = children[0] as PtIdentifier
val index: PtExpression
get() = children[1] as PtExpression
}
class PtArrayLiteral(type: DataType, position: Position): PtExpression(type, position)
class PtBuiltinFunctionCall(val name: String, val void: Boolean, type: DataType, position: Position) : PtExpression(type, position) {
init {
if(!void)
require(type!=DataType.UNDEFINED)
}
val args: List<PtExpression>
get() = children.map { it as PtExpression }
override fun printProperties() {
print(operator)
print("$name void=$void")
}
}
class PtContainmentCheck(position: Position): PtNode(position) {
val element: PtNode
get() = children[0]
val iterable: PtNode
get() = children[0]
override fun printProperties() {}
}
class PtBinaryExpression(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
val left: PtExpression
get() = children[0] as PtExpression
val right: PtExpression
get() = children[1] as PtExpression
class PtIdentifier(val ref: List<String>, val targetName: List<String>, position: Position) : PtNode(position) {
override fun printProperties() {
print("$ref --> $targetName")
print("$operator -> $type")
}
}
class PtMemoryByte(position: Position) : PtNode(position) {
val address: PtNode
get() = children.single()
class PtContainmentCheck(position: Position): PtExpression(DataType.UBYTE, position) {
val element: PtExpression
get() = children[0] as PtExpression
val iterable: PtExpression
get() = children[0] as PtExpression
}
class PtFunctionCall(val functionName: List<String>,
val void: Boolean,
type: DataType,
position: Position) : PtExpression(type, position) {
init {
if(!void)
require(type!=DataType.UNDEFINED)
}
val args: List<PtExpression>
get() = children.map { it as PtExpression }
override fun printProperties() {
print("${functionName.joinToString(".")} void=$void")
}
}
class PtIdentifier(val ref: List<String>, val targetName: List<String>, type: DataType, position: Position) : PtExpression(type, position) {
override fun printProperties() {
print("$ref --> $targetName $type")
}
}
class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position) {
val address: PtExpression
get() = children.single() as PtExpression
override fun printProperties() {}
}
class PtNumber(val type: DataType, val number: Double, position: Position) : PtNode(position) {
class PtNumber(type: DataType, val number: Double, position: Position) : PtExpression(type, position) {
override fun printProperties() {
print("$number ($type)")
}
}
class PtPrefix(val operator: String, position: Position): PtNode(position) {
val value: PtNode
get() = children.single()
class PtPipe(type: DataType, val void: Boolean, position: Position) : PtExpression(type, position) {
init {
if(!void)
require(type!=DataType.UNDEFINED)
}
override fun printProperties() {}
}
class PtPrefix(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
val value: PtExpression
get() = children.single() as PtExpression
override fun printProperties() {
print(operator)
@ -82,27 +121,26 @@ class PtPrefix(val operator: String, position: Position): PtNode(position) {
}
class PtRange(position: Position) : PtNode(position) {
val from: PtNode
get() = children[0]
val to: PtNode
get() = children[1]
val step: PtNode
get() = children[2]
class PtRange(type: DataType, position: Position) : PtExpression(type, position) {
val from: PtExpression
get() = children[0] as PtExpression
val to: PtExpression
get() = children[1] as PtExpression
val step: PtExpression
get() = children[2] as PtExpression
override fun printProperties() {}
}
class PtString(val value: String, val encoding: Encoding, position: Position) : PtNode(position) {
class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.STR, position) {
override fun printProperties() {
print("$encoding:\"$value\"")
}
}
class PtTypeCast(val type: DataType, position: Position) : PtNode(position) {
override fun printProperties() {
print(type)
}
}
class PtTypeCast(type: DataType, position: Position) : PtExpression(type, position) {
val value: PtExpression
get() = children.single() as PtExpression
}

View File

@ -1,13 +1,14 @@
package prog8.code.ast
import prog8.code.core.*
import javax.xml.crypto.Data
class PtAsmSub(
name: String,
val address: UInt?,
val clobbers: Set<CpuRegister>,
val paramRegisters: List<RegisterOrStatusflag>,
val parameters: List<Pair<PtSubroutineParameter, RegisterOrStatusflag>>,
val retvalRegisters: List<RegisterOrStatusflag>,
val inline: Boolean,
position: Position
@ -41,8 +42,8 @@ class PtSubroutineParameter(val name: String, val type: DataType, position: Posi
class PtAssignment(val augmentable: Boolean, position: Position) : PtNode(position) {
val target: PtAssignTarget
get() = children[0] as PtAssignTarget
val value: PtNode
get() = children[1]
val value: PtExpression
get() = children[1] as PtExpression
override fun printProperties() {
print("aug=$augmentable")
@ -62,13 +63,6 @@ class PtAssignTarget(position: Position) : PtNode(position) {
}
class PtBuiltinFunctionCall(val name: String, position: Position) : PtNode(position) {
override fun printProperties() {
print(name)
}
}
class PtConditionalBranch(val condition: BranchCondition, position: Position) : PtNode(position) {
val trueScope: PtNodeGroup
get() = children[0] as PtNodeGroup
@ -84,8 +78,8 @@ class PtConditionalBranch(val condition: BranchCondition, position: Position) :
class PtForLoop(position: Position) : PtNode(position) {
val variable: PtIdentifier
get() = children[0] as PtIdentifier
val iterable: PtNode
get() = children[1]
val iterable: PtExpression
get() = children[1] as PtExpression
val statements: PtNodeGroup
get() = children[2] as PtNodeGroup
@ -93,18 +87,6 @@ class PtForLoop(position: Position) : PtNode(position) {
}
class PtFunctionCall(val void: Boolean, position: Position) : PtNode(position) {
val target: PtIdentifier
get() = children[0] as PtIdentifier
val args: PtNodeGroup
get() = children[1] as PtNodeGroup
override fun printProperties() {
print("void=$void")
}
}
class PtGosub(val identifier: PtIdentifier?,
val address: UInt?,
val generatedLabel: String?,
@ -118,8 +100,8 @@ class PtGosub(val identifier: PtIdentifier?,
class PtIfElse(position: Position) : PtNode(position) {
val condition: PtNode
get() = children[0]
val condition: PtExpression
get() = children[0] as PtExpression
val ifScope: PtNodeGroup
get() = children[1] as PtNodeGroup
val elseScope: PtNodeGroup
@ -141,11 +123,6 @@ class PtJump(val identifier: PtIdentifier?,
}
class PtPipe(position: Position) : PtNode(position) {
override fun printProperties() {}
}
class PtPostIncrDecr(val operator: String, position: Position) : PtNode(position) {
val target: PtAssignTarget
get() = children.single() as PtAssignTarget
@ -157,8 +134,10 @@ class PtPostIncrDecr(val operator: String, position: Position) : PtNode(position
class PtRepeatLoop(position: Position) : PtNode(position) {
val count: PtNode
get() = children.single()
val count: PtExpression
get() = children[0] as PtExpression
val statements: PtNodeGroup
get() = children[1] as PtNodeGroup
override fun printProperties() {}
}
@ -166,10 +145,10 @@ class PtRepeatLoop(position: Position) : PtNode(position) {
class PtReturn(position: Position) : PtNode(position) {
val hasValue = children.any()
val value: PtNode?
val value: PtExpression?
get() {
return if(children.any())
children.single()
children.single() as PtExpression
else
null
}
@ -200,8 +179,8 @@ class PtMemMapped(name: String, val type: DataType, val address: UInt, position:
class PtWhen(position: Position) : PtNode(position) {
val value: PtNode
get() = children[0]
val value: PtExpression
get() = children[0] as PtExpression
val choices: PtNodeGroup
get() = children[1] as PtNodeGroup
@ -210,5 +189,9 @@ class PtWhen(position: Position) : PtNode(position) {
class PtWhenChoice(val isElse: Boolean, position: Position) : PtNode(position) {
val values: PtNodeGroup
get() = children[0] as PtNodeGroup
val statements: PtNodeGroup
get() = children[1] as PtNodeGroup
override fun printProperties() {}
}

View File

@ -65,7 +65,7 @@ internal class ProgramAndVarsGen(
asmgen.out("")
asmgen.out(".cpu '$cpu'\n.enc 'none'\n")
program.actualLoadAddress = program.definedLoadAddress
program.actualLoadAddress = program.definedLoadAddress ?: 0u
if (program.actualLoadAddress == 0u) {
when(options.output) {
OutputType.RAW -> {

View File

@ -1,11 +1,11 @@
package prog8.codegen.experimental
import prog8.code.SymbolTable
import prog8.code.ast.PtProgram
import prog8.code.core.CompilationOptions
import prog8.code.core.IAssemblyGenerator
import prog8.code.core.IAssemblyProgram
import prog8.code.core.IErrorReporter
import prog8.code.ast.*
import prog8.code.core.*
import javax.xml.stream.XMLOutputFactory
import kotlin.io.path.Path
import kotlin.io.path.div
/*
@ -17,21 +17,578 @@ import prog8.code.core.IErrorReporter
*/
class AsmGen(internal val program: PtProgram,
internal val errors: IErrorReporter,
internal val symbolTable: SymbolTable,
internal val options: CompilationOptions
): IAssemblyGenerator {
private lateinit var xml: IndentingXmlWriter
override fun compileToAssembly(): IAssemblyProgram? {
println("\n** experimental code generator **\n")
symbolTable.print()
symbolTable.flat.forEach { println(it) }
program.print()
val writer = (options.outputDir / Path(program.name+"-ast.xml")).toFile().printWriter()
xml = IndentingXmlWriter(XMLOutputFactory.newFactory().createXMLStreamWriter(writer))
xml.doc()
xml.elt("program")
xml.attr("name", program.name)
xml.startChildren()
program.allModuleDirectives().forEach { writeNode(it) }
program.children.forEach { writeNode(it) }
xml.endElt()
xml.endDoc()
xml.close()
println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
return AssemblyProgram("dummy")
}
private fun writeNode(it: PtNode) {
when(it) {
is PtModule -> write(it)
is PtBlock -> write(it)
is PtDirective -> write(it)
is PtSub -> write(it)
is PtVariable -> write(it)
is PtAssignment -> write(it)
is PtConstant -> write(it)
is PtAsmSub -> write(it)
is PtAddressOf -> write(it)
is PtArrayIndexer -> write(it)
is PtArrayLiteral -> write(it)
is PtBinaryExpression -> write(it)
is PtBuiltinFunctionCall -> write(it)
is PtConditionalBranch -> write(it)
is PtContainmentCheck -> write(it)
is PtForLoop -> write(it)
is PtFunctionCall -> write(it)
is PtGosub -> write(it)
is PtIdentifier -> write(it)
is PtIfElse -> write(it)
is PtInlineAssembly -> write(it)
is PtJump -> write(it)
is PtMemoryByte -> write(it)
is PtMemMapped -> write(it)
is PtNumber -> write(it)
is PtPipe -> write(it)
is PtPostIncrDecr -> write(it)
is PtPrefix -> write(it)
is PtRange -> write(it)
is PtRepeatLoop -> write(it)
is PtReturn -> write(it)
is PtString -> write(it)
is PtTypeCast -> write(it)
is PtWhen -> write(it)
is PtWhenChoice -> write(it)
is PtLabel -> write(it)
is PtNodeGroup -> it.children.forEach { writeNode(it) }
else -> TODO("$it")
}
}
private fun write(pipe: PtPipe) {
xml.elt("pipe")
xml.attr("type", pipe.type.name)
xml.startChildren()
pipe.children.forEach { writeNode(it) }
xml.endElt()
}
private fun write(array: PtArrayLiteral) {
xml.elt("array")
xml.attr("type", array.type.name)
xml.startChildren()
array.children.forEach { writeNode(it) }
xml.endElt()
}
private fun write(prefix: PtPrefix) {
xml.elt("prefix")
xml.attr("op", prefix.operator)
xml.attr("type", prefix.type.name)
xml.startChildren()
xml.elt("value")
xml.startChildren()
writeNode(prefix.value)
xml.endElt()
xml.endElt()
}
private fun write(string: PtString) {
xml.elt("string")
xml.attr("encoding", string.encoding.name)
xml.startChildren()
xml.text(string.value)
xml.endElt()
}
private fun write(rept: PtRepeatLoop) {
xml.elt("repeat")
xml.startChildren()
xml.pos(rept.position)
xml.elt("count")
xml.startChildren()
writeNode(rept.count)
xml.endElt()
xml.elt("statements")
writeNode(rept.statements)
xml.endElt()
xml.endElt()
}
private fun write(branch: PtConditionalBranch) {
xml.elt("conditionalbranch")
xml.attr("condition", branch.condition.name)
xml.startChildren()
xml.pos(branch.position)
xml.elt("true")
xml.startChildren()
writeNode(branch.trueScope)
xml.endElt()
if(branch.falseScope.children.isNotEmpty()) {
xml.elt("false")
xml.startChildren()
writeNode(branch.falseScope)
xml.endElt()
}
xml.endElt()
}
private fun write(check: PtContainmentCheck) {
xml.elt("containment")
xml.attr("type", check.type.name)
xml.startChildren()
xml.elt("element")
xml.startChildren()
writeNode(check.element)
xml.endElt()
xml.elt("iterable")
xml.startChildren()
writeNode(check.iterable)
xml.endElt()
xml.endElt()
}
private fun write(range: PtRange) {
xml.elt("range")
xml.attr("type", range.type.name)
xml.startChildren()
xml.elt("from")
xml.startChildren()
writeNode(range.from)
xml.endElt()
xml.elt("to")
xml.startChildren()
writeNode(range.to)
xml.endElt()
xml.elt("step")
xml.startChildren()
writeNode(range.step)
xml.endElt()
xml.endElt()
}
private fun write(forLoop: PtForLoop) {
xml.elt("for")
xml.attr("var", strTargetName(forLoop.variable))
xml.startChildren()
xml.pos(forLoop.position)
xml.elt("iterable")
xml.startChildren()
writeNode(forLoop.iterable)
xml.endElt()
xml.elt("statements")
xml.startChildren()
writeNode(forLoop.statements)
xml.endElt()
xml.endElt()
}
private fun write(membyte: PtMemoryByte) {
xml.elt("membyte")
xml.attr("type", membyte.type.name)
xml.startChildren()
xml.elt("address")
xml.startChildren()
writeNode(membyte.address)
xml.endElt()
xml.endElt()
}
private fun write(whenStmt: PtWhen) {
xml.elt("when")
xml.startChildren()
xml.pos(whenStmt.position)
xml.elt("value")
xml.startChildren()
writeNode(whenStmt.value)
xml.endElt()
xml.elt("choices")
xml.startChildren()
writeNode(whenStmt.choices)
xml.endElt()
xml.endElt()
}
private fun write(choice: PtWhenChoice) {
xml.elt("choice")
if(choice.isElse) {
xml.attr("else", "true")
xml.startChildren()
} else {
xml.startChildren()
xml.elt("values")
xml.startChildren()
writeNode(choice.values)
xml.endElt()
}
xml.elt("statements")
xml.startChildren()
writeNode(choice.statements)
xml.endElt()
xml.endElt()
}
private fun write(inlineAsm: PtInlineAssembly) {
xml.elt("assembly")
xml.startChildren()
xml.pos(inlineAsm.position)
xml.elt("code")
xml.text(inlineAsm.assembly)
xml.endElt()
xml.endElt()
}
private fun write(fcall: PtBuiltinFunctionCall) {
xml.elt("builtinfcall")
xml.attr("name", fcall.name)
if(fcall.void)
xml.attr("type", "VOID")
else
xml.attr("type", fcall.type.name)
xml.startChildren()
fcall.children.forEach { writeNode(it) }
xml.endElt()
}
private fun write(cast: PtTypeCast) {
xml.elt("cast")
xml.attr("type", cast.type.name)
xml.startChildren()
writeNode(cast.value)
xml.endElt()
}
private fun write(aix: PtArrayIndexer) {
xml.elt("arrayindexed")
xml.attr("type", aix.type.name)
xml.startChildren()
write(aix.variable)
writeNode(aix.index)
xml.endElt()
}
private fun write(binexpr: PtBinaryExpression) {
xml.elt("binexpr")
xml.attr("op", binexpr.operator)
xml.attr("type", binexpr.type.name)
xml.startChildren()
writeNode(binexpr.left)
writeNode(binexpr.right)
xml.endElt()
}
private fun write(addrof: PtAddressOf) {
xml.elt("addrof")
xml.startChildren()
write(addrof.identifier)
xml.endElt()
}
private fun write(fcall: PtFunctionCall) {
xml.elt("fcall")
xml.attr("name", strTargetName(fcall))
if(fcall.void)
xml.attr("type", "VOID")
else
xml.attr("type", fcall.type.name)
xml.startChildren()
xml.pos(fcall.position)
fcall.children.forEach { writeNode(it) }
xml.endElt()
}
private fun write(number: PtNumber) {
xml.elt("number")
xml.attr("type", number.type.name)
xml.attr("value", intOrDouble(number.type, number.number).toString())
xml.endElt()
}
private fun write(symbol: PtIdentifier) {
xml.elt("symbol")
xml.attr("name", strTargetName(symbol))
xml.attr("type", symbol.type.name)
xml.endElt()
}
private fun write(assign: PtAssignment) {
xml.elt("assign")
xml.attr("aug", assign.augmentable.toString())
xml.startChildren()
xml.pos(assign.position)
write(assign.target)
writeNode(assign.value)
xml.endElt()
}
private fun write(ifElse: PtIfElse) {
xml.elt("ifelse")
xml.startChildren()
xml.pos(ifElse.position)
xml.elt("condition")
xml.startChildren()
writeNode(ifElse.condition)
xml.endElt()
xml.elt("true")
xml.startChildren()
xml.pos(ifElse.ifScope.position)
writeNode(ifElse.ifScope)
xml.endElt()
if(ifElse.elseScope.children.isNotEmpty()) {
xml.elt("false")
xml.startChildren()
xml.pos(ifElse.elseScope.position)
writeNode(ifElse.elseScope)
xml.endElt()
}
xml.endElt()
}
private fun write(ret: PtReturn) {
xml.elt("return")
if(ret.hasValue) {
xml.startChildren()
writeNode(ret.value!!)
}
xml.endElt()
}
private fun write(incdec: PtPostIncrDecr) {
if(incdec.operator=="++") xml.elt("inc") else xml.elt("dec")
xml.startChildren()
write(incdec.target)
xml.endElt()
}
private fun write(label: PtLabel) {
xml.elt("label")
xml.attr("name", label.name)
xml.startChildren()
xml.pos(label.position)
xml.endElt()
}
private fun write(module: PtModule) {
xml.elt("module")
xml.attr("name", module.name)
xml.attr("library", module.library.toString())
if(module.loadAddress!=null)
xml.attr("loadaddress", module.loadAddress.toString())
xml.startChildren()
xml.pos(module.position)
module.children.asSequence().filter { it !is PtDirective }.forEach { write(it as PtBlock) }
xml.endElt()
}
private fun write(block: PtBlock) {
xml.elt("block")
xml.attr("name", block.name)
if(block.address!=null)
xml.attr("address", block.address!!.toString())
xml.attr("library", block.library.toString())
xml.startChildren()
xml.pos(block.position)
block.children.forEach { writeNode(it) }
xml.endElt()
}
private fun write(memMapped: PtMemMapped) {
xml.elt("memvar")
xml.attr("type", memMapped.type.name)
xml.attr("name", memMapped.name)
xml.attr("address", memMapped.address.toString())
xml.endElt()
}
private fun write(target: PtAssignTarget) {
xml.elt("target")
xml.startChildren()
if(target.identifier!=null) {
writeNode(target.identifier!!)
} else if(target.memory!=null) {
writeNode(target.memory!!)
} else if(target.array!=null) {
writeNode(target.array!!)
} else
throw InternalCompilerException("weird assign target")
xml.endElt()
}
private fun write(jump: PtJump) {
xml.elt("jump")
if(jump.identifier!=null) xml.attr("symbol", strTargetName(jump.identifier!!))
else if(jump.address!=null) xml.attr("address", jump.address!!.toString())
else if(jump.generatedLabel!=null) xml.attr("label", jump.generatedLabel!!)
else
throw InternalCompilerException("weird jump target")
xml.endElt()
}
private fun write(gosub: PtGosub) {
xml.elt("gosub")
if(gosub.identifier!=null) xml.attr("symbol", strTargetName(gosub.identifier!!))
else if(gosub.address!=null) xml.attr("address", gosub.address!!.toString())
else if(gosub.generatedLabel!=null) xml.attr("label", gosub.generatedLabel!!)
else
throw InternalCompilerException("weird jump target")
xml.endElt()
}
private fun write(sub: PtSub) {
xml.elt("sub")
xml.attr("name", sub.name)
if(sub.inline)
xml.attr("inline", "true")
xml.attr("returntype", sub.returntype?.toString() ?: "VOID")
xml.startChildren()
xml.pos(sub.position)
if(sub.parameters.isNotEmpty()) {
xml.elt("parameters")
xml.startChildren()
sub.parameters.forEach { write(it) }
xml.endElt()
}
xml.elt("statements")
xml.startChildren()
sub.children.forEach { writeNode(it) }
xml.endElt()
xml.endElt()
}
private fun write(parameter: PtSubroutineParameter, registerOrStatusflag: RegisterOrStatusflag? = null) {
xml.elt("param")
xml.attr("name", parameter.name)
xml.attr("type", parameter.type.name)
if(registerOrStatusflag?.statusflag!=null) {
xml.attr("statusflag", registerOrStatusflag.statusflag!!.toString())
}
if(registerOrStatusflag?.registerOrPair!=null){
xml.attr("registers", registerOrStatusflag.registerOrPair!!.name)
}
xml.endElt()
}
private fun write(asmSub: PtAsmSub) {
if(asmSub.address!=null) {
xml.elt("romsub")
xml.attr("name", asmSub.name)
xml.attr("address", asmSub.address!!.toString())
if(asmSub.inline)
xml.attr("inline", "true")
xml.startChildren()
xml.pos(asmSub.position)
paramsEtcetera(asmSub)
xml.endElt()
}
else {
xml.elt("asmsub")
xml.attr("name", asmSub.name)
if(asmSub.inline)
xml.attr("inline", "true")
xml.startChildren()
xml.pos(asmSub.position)
paramsEtcetera(asmSub)
xml.elt("code")
xml.startChildren()
asmSub.children.forEach { writeNode(it) }
xml.endElt()
xml.endElt()
}
}
private fun paramsEtcetera(asmSub: PtAsmSub) {
if(asmSub.parameters.isNotEmpty()) {
xml.elt("parameters")
xml.startChildren()
asmSub.parameters.forEach { (param, reg) -> write(param, reg) }
xml.endElt()
}
if(asmSub.clobbers.isNotEmpty()) {
xml.elt("clobbers")
xml.attr("registers", asmSub.clobbers.map {it.name}.joinToString(","))
xml.endElt()
}
if(asmSub.retvalRegisters.isNotEmpty()) {
xml.elt("returns")
xml.startChildren()
asmSub.retvalRegisters.forEach {
xml.elt("register")
if(it.statusflag!=null)
xml.attr("statusflag", it.statusflag!!.toString())
if(it.registerOrPair!=null)
xml.attr("registers", it.registerOrPair!!.toString())
xml.endElt()
}
xml.endElt()
}
}
private fun write(constant: PtConstant) {
xml.elt("const")
xml.attr("name", constant.name)
xml.attr("type", constant.type.name)
xml.attr("value", intOrDouble(constant.type, constant.value).toString())
xml.endElt()
}
private fun write(variable: PtVariable) {
// TODO get this from the AST only?
xml.elt("var")
xml.attr("name", variable.name)
xml.attr("type", variable.type.name)
xml.endElt()
}
private fun write(directive: PtDirective) {
if(directive.name=="%import")
return
xml.elt("directive")
xml.attr("name", directive.name.substring(1))
if(directive.args.isNotEmpty()) {
xml.startChildren()
directive.args.forEach {
xml.elt("arg")
if(it.name!=null)
xml.attr("name", it.name!!)
if(it.str!=null)
xml.attr("string", it.str!!)
if(it.int!=null)
xml.attr("number", it.int!!.toString())
xml.endElt()
}
}
xml.endElt()
}
private fun strTargetName(ident: PtIdentifier): String = ident.targetName.joinToString(".")
private fun strTargetName(call: PtFunctionCall): String = call.functionName.joinToString(".")
private fun intOrDouble(type: DataType, value: Double): Number =
if(type in IntegerDatatypes) value.toInt() else value
}

View File

@ -0,0 +1,80 @@
package prog8.codegen.experimental
import prog8.code.core.Position
import java.util.*
import javax.xml.stream.XMLStreamWriter
class IndentingXmlWriter(val xml: XMLStreamWriter): XMLStreamWriter by xml {
private var indent = 0
private var content = Stack<Boolean>()
fun doc(version: String? = null) = if(version==null) writeStartDocument() else writeStartDocument(version)
fun endDoc() = writeEndDocument()
fun elt(name: String) = writeStartElement(name)
fun attr(name: String, value: String) = writeAttribute(name, value)
fun attrs(attributes: List<Pair<String, String>>) = attributes.forEach { writeAttribute(it.first, it.second) }
fun text(text: String) = writeCData(text)
fun startChildren() {
xml.writeCharacters("\n")
content.pop()
content.push(true)
}
fun endElt() = this.writeEndElement()
fun pos(pos: Position) {
elt("src")
attr("pos", pos.toString())
endElt()
}
fun comment(text: String) {
writeComment(text)
writeCharacters("\n")
}
override fun writeStartDocument() {
xml.writeStartDocument()
xml.writeCharacters("\n")
content.push(true)
}
override fun writeStartDocument(version: String) {
xml.writeStartDocument(version)
xml.writeCharacters("\n")
content.push(true)
}
override fun writeEndDocument() {
xml.writeEndDocument()
xml.writeCharacters("\n")
require(indent==0)
require(content.size==1)
}
override fun writeStartElement(name: String) {
xml.writeCharacters(" ".repeat(indent))
xml.writeStartElement(name)
indent++
content.push(false)
}
override fun writeStartElement(name: String, ns: String) {
xml.writeCharacters(" ".repeat(indent))
xml.writeStartElement(name, ns)
indent++
content.push(false)
}
override fun writeEndElement() {
indent--
if(content.pop())
xml.writeCharacters(" ".repeat(indent))
xml.writeEndElement()
xml.writeCharacters("\n")
}
override fun writeStartElement(name: String, ns: String, p2: String) {
xml.writeCharacters(" ".repeat(indent))
xml.writeStartElement(name, ns, p2)
indent++
content.push(false)
}
}

View File

@ -6,21 +6,22 @@ import prog8.ast.base.FatalAstException
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.code.ast.*
import prog8.code.core.DataType
class IntermediateAstMaker(val srcProgram: Program) {
class IntermediateAstMaker(val program: Program) {
fun transform(): PtProgram {
val program = PtProgram(
srcProgram.name,
srcProgram.memsizer,
srcProgram.encoding
val ptProgram = PtProgram(
program.name,
program.memsizer,
program.encoding
)
for (module in srcProgram.modules) {
program.add(transform(module))
for (module in program.modules) {
ptProgram.add(transform(module))
}
return program
return ptProgram
}
private fun transform(srcModule: Module): PtModule {
@ -71,7 +72,7 @@ class IntermediateAstMaker(val srcProgram: Program) {
}
}
private fun transformExpression(expr: Expression): PtNode {
private fun transformExpression(expr: Expression): PtExpression {
return when(expr) {
is AddressOf -> transform(expr)
is ArrayIndexedExpression -> transform(expr)
@ -112,13 +113,19 @@ class IntermediateAstMaker(val srcProgram: Program) {
return target
}
private fun transform(identifier: IdentifierReference): PtIdentifier {
val target=identifier.targetStatement(srcProgram)!! as INamedStatement
val targetname = if(target.name in srcProgram.builtinFunctions.names)
private fun targetOf(identifier: IdentifierReference): Pair<List<String>, DataType> {
val target=identifier.targetStatement(program)!! as INamedStatement
val targetname = if(target.name in program.builtinFunctions.names)
listOf("<builtin>", target.name)
else
target.scopedName
return PtIdentifier(identifier.nameInSource, targetname, identifier.position)
val type = identifier.inferType(program).getOr(DataType.UNDEFINED)
return Pair(targetname, type)
}
private fun transform(identifier: IdentifierReference): PtIdentifier {
val (target, type) = targetOf(identifier)
return PtIdentifier(identifier.nameInSource, target, type, identifier.position)
}
private fun transform(srcBlock: Block): PtBlock {
@ -131,7 +138,8 @@ class IntermediateAstMaker(val srcProgram: Program) {
}
private fun transform(srcNode: BuiltinFunctionCallStatement): PtBuiltinFunctionCall {
val call = PtBuiltinFunctionCall(srcNode.name, srcNode.position)
val type = builtinFunctionReturnType(srcNode.name, srcNode.args, program).getOr(DataType.UNDEFINED)
val call = PtBuiltinFunctionCall(srcNode.name, true, type, srcNode.position)
for (arg in srcNode.args)
call.add(transformExpression(arg))
return call
@ -173,22 +181,19 @@ class IntermediateAstMaker(val srcProgram: Program) {
}
private fun transform(srcCall: FunctionCallStatement): PtFunctionCall {
val call = PtFunctionCall(true, srcCall.position)
call.add(transform(srcCall.target))
val args = PtNodeGroup()
val (target, type) = targetOf(srcCall.target)
val call = PtFunctionCall(target,true, type, srcCall.position)
for (arg in srcCall.args)
args.add(transformExpression(arg))
call.add(args)
call.add(transformExpression(arg))
return call
}
private fun transform(srcCall: FunctionCallExpression): PtFunctionCall {
val call = PtFunctionCall(false, srcCall.position)
call.add(transform(srcCall.target))
val args = PtNodeGroup()
val (target, _) = targetOf(srcCall.target)
val type = srcCall.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val call = PtFunctionCall(target, false, type, srcCall.position)
for (arg in srcCall.args)
args.add(transformExpression(arg))
call.add(args)
call.add(transformExpression(arg))
return call
}
@ -229,7 +234,8 @@ class IntermediateAstMaker(val srcProgram: Program) {
PtLabel(label.name, label.position)
private fun transform(srcPipe: Pipe): PtPipe {
val pipe = PtPipe(srcPipe.position)
val type = srcPipe.segments.last().inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val pipe = PtPipe(type, true, srcPipe.position)
pipe.add(transformExpression(srcPipe.source))
for (segment in srcPipe.segments)
pipe.add(transformExpression(segment))
@ -247,9 +253,11 @@ class IntermediateAstMaker(val srcProgram: Program) {
throw FatalAstException("repeat-forever loop should have been replaced with label+jump")
val repeat = PtRepeatLoop(srcRepeat.position)
repeat.add(transformExpression(srcRepeat.iterations!!))
val scope = PtNodeGroup()
for (statement in srcRepeat.body.statements) {
repeat.add(transformStatement(statement))
scope.add(transformStatement(statement))
}
repeat.add(scope)
return repeat
}
@ -261,10 +269,13 @@ class IntermediateAstMaker(val srcProgram: Program) {
}
private fun transformAsmSub(srcSub: Subroutine): PtAsmSub {
val params = srcSub.parameters
.map { PtSubroutineParameter(it.name, it.type, it.position) }
.zip(srcSub.asmParameterRegisters)
val sub = PtAsmSub(srcSub.name,
srcSub.asmAddress,
srcSub.asmClobbers,
srcSub.asmParameterRegisters,
params,
srcSub.asmReturnvaluesRegisters,
srcSub.inline,
srcSub.position)
@ -334,7 +345,8 @@ class IntermediateAstMaker(val srcProgram: Program) {
}
private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer {
val array = PtArrayIndexer(srcArr.position)
val type = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val array = PtArrayIndexer(type, srcArr.position)
array.add(transform(srcArr.arrayvar))
array.add(transformExpression(srcArr.indexer.indexExpr))
return array
@ -348,14 +360,16 @@ class IntermediateAstMaker(val srcProgram: Program) {
}
private fun transform(srcExpr: BinaryExpression): PtBinaryExpression {
val expr = PtBinaryExpression(srcExpr.operator, srcExpr.position)
val type = srcExpr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val expr = PtBinaryExpression(srcExpr.operator, type, srcExpr.position)
expr.add(transformExpression(srcExpr.left))
expr.add(transformExpression(srcExpr.right))
return expr
}
private fun transform(srcCall: BuiltinFunctionCall): PtBuiltinFunctionCall {
val call = PtBuiltinFunctionCall(srcCall.name, srcCall.position)
val type = srcCall.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val call = PtBuiltinFunctionCall(srcCall.name, false, type, srcCall.position)
for (arg in srcCall.args)
call.add(transformExpression(arg))
return call
@ -384,7 +398,8 @@ class IntermediateAstMaker(val srcProgram: Program) {
PtNumber(number.type, number.number, number.position)
private fun transform(srcPipe: PipeExpression): PtPipe {
val pipe = PtPipe(srcPipe.position)
val type = srcPipe.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val pipe = PtPipe(type, false, srcPipe.position)
pipe.add(transformExpression(srcPipe.source))
for (segment in srcPipe.segments)
pipe.add(transformExpression(segment))
@ -392,13 +407,15 @@ class IntermediateAstMaker(val srcProgram: Program) {
}
private fun transform(srcPrefix: PrefixExpression): PtPrefix {
val prefix = PtPrefix(srcPrefix.operator, srcPrefix.position)
val type = srcPrefix.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val prefix = PtPrefix(srcPrefix.operator, type, srcPrefix.position)
prefix.add(transformExpression(srcPrefix.expression))
return prefix
}
private fun transform(srcRange: RangeExpression): PtRange {
val range=PtRange(srcRange.position)
val type = srcRange.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val range=PtRange(type, srcRange.position)
range.add(transformExpression(srcRange.from))
range.add(transformExpression(srcRange.to))
range.add(transformExpression(srcRange.step))

View File

@ -285,9 +285,8 @@ open class Module(final override var statements: MutableList<Statement>,
.substringAfterLast("/")
.substringAfterLast("\\")
val loadAddress: UInt by lazy {
val address = (statements.singleOrNull { it is Directive && it.directive == "%address" } as? Directive)?.args?.single()?.int ?: 0u
address
val loadAddress: UInt? by lazy {
(statements.singleOrNull { it is Directive && it.directive == "%address" } as? Directive)?.args?.single()?.int
}
override fun linkParents(parent: Node) {

View File

@ -67,7 +67,7 @@ class Program(val name: String,
val toplevelModule: Module
get() = modules.first { it.name!= internedStringsModuleName }
val definedLoadAddress: UInt
val definedLoadAddress: UInt?
get() = toplevelModule.loadAddress
var actualLoadAddress = 0u

View File

@ -3,6 +3,8 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- unit test for PtProgram AST: should also test new things such as the Datatype in nodes.
...

View File

@ -28,11 +28,11 @@ main {
txt.print_ub(amount)
txt.nl()
; test_stack.test()
}
uword[] @shared array = [111,222,333,444,555]
sub derp() -> ubyte, ubyte {
return 0, 1
amount = amount |> sin8u() |> cos8u() |> sin8u()
; test_stack.test()
}
sub find_next_prime() -> ubyte {