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.IMemSizer
import prog8.code.core.IStringEncoding import prog8.code.core.IStringEncoding
import prog8.code.core.Position import prog8.code.core.Position
import java.util.*
// New (work-in-progress) simplified AST for the code generator. // New (work-in-progress) simplified AST for the code generator.
@ -62,6 +63,9 @@ class PtProgram(
print("'$name'") print("'$name'")
} }
fun allModuleDirectives(): Sequence<PtDirective> =
children.asSequence().flatMap { it.children }.filterIsInstance<PtDirective>().distinct()
fun allBlocks(): Sequence<PtBlock> = fun allBlocks(): Sequence<PtBlock> =
children.asSequence().flatMap { it.children }.filterIsInstance<PtBlock>() children.asSequence().flatMap { it.children }.filterIsInstance<PtBlock>()
@ -72,7 +76,7 @@ class PtProgram(
class PtModule( class PtModule(
name: String, name: String,
val loadAddress: UInt, val loadAddress: UInt?,
val library: Boolean, val library: Boolean,
position: Position position: Position
) : PtNamedNode(name, position) { ) : PtNamedNode(name, position) {
@ -100,6 +104,18 @@ class PtDirective(var name: String, position: Position) : PtNode(position) {
override fun printProperties() { override fun printProperties() {
print(name) 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() { override fun printProperties() {
print("str=$str name=$name int=$int") 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 import prog8.code.core.Position
class PtAddressOf(position: Position) : PtNode(position) { sealed class PtExpression(val type: DataType, 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) {
override fun printProperties() { override fun printProperties() {
print(type) print(type)
} }
} }
class PtBinaryExpression(val operator: String, position: Position): PtNode(position) { class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
val left: PtNode val identifier: PtIdentifier
get() = children[0] get() = children.single() as PtIdentifier
val right: PtNode }
get() = children[1]
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() { override fun printProperties() {
print(operator) print("$name void=$void")
} }
} }
class PtContainmentCheck(position: Position): PtNode(position) { class PtBinaryExpression(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
val element: PtNode val left: PtExpression
get() = children[0] get() = children[0] as PtExpression
val iterable: PtNode val right: PtExpression
get() = children[0] get() = children[1] as PtExpression
override fun printProperties() {}
}
class PtIdentifier(val ref: List<String>, val targetName: List<String>, position: Position) : PtNode(position) {
override fun printProperties() { override fun printProperties() {
print("$ref --> $targetName") print("$operator -> $type")
} }
} }
class PtMemoryByte(position: Position) : PtNode(position) { class PtContainmentCheck(position: Position): PtExpression(DataType.UBYTE, position) {
val address: PtNode val element: PtExpression
get() = children.single() 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() {} 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() { override fun printProperties() {
print("$number ($type)") print("$number ($type)")
} }
} }
class PtPrefix(val operator: String, position: Position): PtNode(position) { class PtPipe(type: DataType, val void: Boolean, position: Position) : PtExpression(type, position) {
val value: PtNode init {
get() = children.single() 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() { override fun printProperties() {
print(operator) print(operator)
@ -82,27 +121,26 @@ class PtPrefix(val operator: String, position: Position): PtNode(position) {
} }
class PtRange(position: Position) : PtNode(position) { class PtRange(type: DataType, position: Position) : PtExpression(type, position) {
val from: PtNode val from: PtExpression
get() = children[0] get() = children[0] as PtExpression
val to: PtNode val to: PtExpression
get() = children[1] get() = children[1] as PtExpression
val step: PtNode val step: PtExpression
get() = children[2] get() = children[2] as PtExpression
override fun printProperties() {} 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() { override fun printProperties() {
print("$encoding:\"$value\"") print("$encoding:\"$value\"")
} }
} }
class PtTypeCast(val type: DataType, position: Position) : PtNode(position) { class PtTypeCast(type: DataType, position: Position) : PtExpression(type, position) {
override fun printProperties() { val value: PtExpression
print(type) get() = children.single() as PtExpression
} }
}

View File

@ -1,13 +1,14 @@
package prog8.code.ast package prog8.code.ast
import prog8.code.core.* import prog8.code.core.*
import javax.xml.crypto.Data
class PtAsmSub( class PtAsmSub(
name: String, name: String,
val address: UInt?, val address: UInt?,
val clobbers: Set<CpuRegister>, val clobbers: Set<CpuRegister>,
val paramRegisters: List<RegisterOrStatusflag>, val parameters: List<Pair<PtSubroutineParameter, RegisterOrStatusflag>>,
val retvalRegisters: List<RegisterOrStatusflag>, val retvalRegisters: List<RegisterOrStatusflag>,
val inline: Boolean, val inline: Boolean,
position: Position 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) { class PtAssignment(val augmentable: Boolean, position: Position) : PtNode(position) {
val target: PtAssignTarget val target: PtAssignTarget
get() = children[0] as PtAssignTarget get() = children[0] as PtAssignTarget
val value: PtNode val value: PtExpression
get() = children[1] get() = children[1] as PtExpression
override fun printProperties() { override fun printProperties() {
print("aug=$augmentable") 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) { class PtConditionalBranch(val condition: BranchCondition, position: Position) : PtNode(position) {
val trueScope: PtNodeGroup val trueScope: PtNodeGroup
get() = children[0] as PtNodeGroup get() = children[0] as PtNodeGroup
@ -84,8 +78,8 @@ class PtConditionalBranch(val condition: BranchCondition, position: Position) :
class PtForLoop(position: Position) : PtNode(position) { class PtForLoop(position: Position) : PtNode(position) {
val variable: PtIdentifier val variable: PtIdentifier
get() = children[0] as PtIdentifier get() = children[0] as PtIdentifier
val iterable: PtNode val iterable: PtExpression
get() = children[1] get() = children[1] as PtExpression
val statements: PtNodeGroup val statements: PtNodeGroup
get() = children[2] as 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?, class PtGosub(val identifier: PtIdentifier?,
val address: UInt?, val address: UInt?,
val generatedLabel: String?, val generatedLabel: String?,
@ -118,8 +100,8 @@ class PtGosub(val identifier: PtIdentifier?,
class PtIfElse(position: Position) : PtNode(position) { class PtIfElse(position: Position) : PtNode(position) {
val condition: PtNode val condition: PtExpression
get() = children[0] get() = children[0] as PtExpression
val ifScope: PtNodeGroup val ifScope: PtNodeGroup
get() = children[1] as PtNodeGroup get() = children[1] as PtNodeGroup
val elseScope: 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) { class PtPostIncrDecr(val operator: String, position: Position) : PtNode(position) {
val target: PtAssignTarget val target: PtAssignTarget
get() = children.single() as 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) { class PtRepeatLoop(position: Position) : PtNode(position) {
val count: PtNode val count: PtExpression
get() = children.single() get() = children[0] as PtExpression
val statements: PtNodeGroup
get() = children[1] as PtNodeGroup
override fun printProperties() {} override fun printProperties() {}
} }
@ -166,10 +145,10 @@ class PtRepeatLoop(position: Position) : PtNode(position) {
class PtReturn(position: Position) : PtNode(position) { class PtReturn(position: Position) : PtNode(position) {
val hasValue = children.any() val hasValue = children.any()
val value: PtNode? val value: PtExpression?
get() { get() {
return if(children.any()) return if(children.any())
children.single() children.single() as PtExpression
else else
null null
} }
@ -200,8 +179,8 @@ class PtMemMapped(name: String, val type: DataType, val address: UInt, position:
class PtWhen(position: Position) : PtNode(position) { class PtWhen(position: Position) : PtNode(position) {
val value: PtNode val value: PtExpression
get() = children[0] get() = children[0] as PtExpression
val choices: PtNodeGroup val choices: PtNodeGroup
get() = children[1] as 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) { 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() {} override fun printProperties() {}
} }

View File

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

View File

@ -1,11 +1,11 @@
package prog8.codegen.experimental package prog8.codegen.experimental
import prog8.code.SymbolTable import prog8.code.SymbolTable
import prog8.code.ast.PtProgram import prog8.code.ast.*
import prog8.code.core.CompilationOptions import prog8.code.core.*
import prog8.code.core.IAssemblyGenerator import javax.xml.stream.XMLOutputFactory
import prog8.code.core.IAssemblyProgram import kotlin.io.path.Path
import prog8.code.core.IErrorReporter import kotlin.io.path.div
/* /*
@ -17,21 +17,578 @@ import prog8.code.core.IErrorReporter
*/ */
class AsmGen(internal val program: PtProgram, class AsmGen(internal val program: PtProgram,
internal val errors: IErrorReporter, internal val errors: IErrorReporter,
internal val symbolTable: SymbolTable, internal val symbolTable: SymbolTable,
internal val options: CompilationOptions internal val options: CompilationOptions
): IAssemblyGenerator { ): IAssemblyGenerator {
private lateinit var xml: IndentingXmlWriter
override fun compileToAssembly(): IAssemblyProgram? { override fun compileToAssembly(): IAssemblyProgram? {
println("\n** experimental code generator **\n") println("\n** experimental code generator **\n")
symbolTable.print() val writer = (options.outputDir / Path(program.name+"-ast.xml")).toFile().printWriter()
symbolTable.flat.forEach { println(it) } xml = IndentingXmlWriter(XMLOutputFactory.newFactory().createXMLStreamWriter(writer))
program.print() 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()}..") println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
return AssemblyProgram("dummy") 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.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.DataType
class IntermediateAstMaker(val srcProgram: Program) { class IntermediateAstMaker(val program: Program) {
fun transform(): PtProgram { fun transform(): PtProgram {
val program = PtProgram( val ptProgram = PtProgram(
srcProgram.name, program.name,
srcProgram.memsizer, program.memsizer,
srcProgram.encoding program.encoding
) )
for (module in srcProgram.modules) { for (module in program.modules) {
program.add(transform(module)) ptProgram.add(transform(module))
} }
return program return ptProgram
} }
private fun transform(srcModule: Module): PtModule { 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) { return when(expr) {
is AddressOf -> transform(expr) is AddressOf -> transform(expr)
is ArrayIndexedExpression -> transform(expr) is ArrayIndexedExpression -> transform(expr)
@ -112,13 +113,19 @@ class IntermediateAstMaker(val srcProgram: Program) {
return target return target
} }
private fun transform(identifier: IdentifierReference): PtIdentifier { private fun targetOf(identifier: IdentifierReference): Pair<List<String>, DataType> {
val target=identifier.targetStatement(srcProgram)!! as INamedStatement val target=identifier.targetStatement(program)!! as INamedStatement
val targetname = if(target.name in srcProgram.builtinFunctions.names) val targetname = if(target.name in program.builtinFunctions.names)
listOf("<builtin>", target.name) listOf("<builtin>", target.name)
else else
target.scopedName 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 { private fun transform(srcBlock: Block): PtBlock {
@ -131,7 +138,8 @@ class IntermediateAstMaker(val srcProgram: Program) {
} }
private fun transform(srcNode: BuiltinFunctionCallStatement): PtBuiltinFunctionCall { 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) for (arg in srcNode.args)
call.add(transformExpression(arg)) call.add(transformExpression(arg))
return call return call
@ -173,22 +181,19 @@ class IntermediateAstMaker(val srcProgram: Program) {
} }
private fun transform(srcCall: FunctionCallStatement): PtFunctionCall { private fun transform(srcCall: FunctionCallStatement): PtFunctionCall {
val call = PtFunctionCall(true, srcCall.position) val (target, type) = targetOf(srcCall.target)
call.add(transform(srcCall.target)) val call = PtFunctionCall(target,true, type, srcCall.position)
val args = PtNodeGroup()
for (arg in srcCall.args) for (arg in srcCall.args)
args.add(transformExpression(arg)) call.add(transformExpression(arg))
call.add(args)
return call return call
} }
private fun transform(srcCall: FunctionCallExpression): PtFunctionCall { private fun transform(srcCall: FunctionCallExpression): PtFunctionCall {
val call = PtFunctionCall(false, srcCall.position) val (target, _) = targetOf(srcCall.target)
call.add(transform(srcCall.target)) val type = srcCall.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val args = PtNodeGroup() val call = PtFunctionCall(target, false, type, srcCall.position)
for (arg in srcCall.args) for (arg in srcCall.args)
args.add(transformExpression(arg)) call.add(transformExpression(arg))
call.add(args)
return call return call
} }
@ -229,7 +234,8 @@ class IntermediateAstMaker(val srcProgram: Program) {
PtLabel(label.name, label.position) PtLabel(label.name, label.position)
private fun transform(srcPipe: Pipe): PtPipe { 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)) pipe.add(transformExpression(srcPipe.source))
for (segment in srcPipe.segments) for (segment in srcPipe.segments)
pipe.add(transformExpression(segment)) 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") throw FatalAstException("repeat-forever loop should have been replaced with label+jump")
val repeat = PtRepeatLoop(srcRepeat.position) val repeat = PtRepeatLoop(srcRepeat.position)
repeat.add(transformExpression(srcRepeat.iterations!!)) repeat.add(transformExpression(srcRepeat.iterations!!))
val scope = PtNodeGroup()
for (statement in srcRepeat.body.statements) { for (statement in srcRepeat.body.statements) {
repeat.add(transformStatement(statement)) scope.add(transformStatement(statement))
} }
repeat.add(scope)
return repeat return repeat
} }
@ -261,10 +269,13 @@ class IntermediateAstMaker(val srcProgram: Program) {
} }
private fun transformAsmSub(srcSub: Subroutine): PtAsmSub { 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, val sub = PtAsmSub(srcSub.name,
srcSub.asmAddress, srcSub.asmAddress,
srcSub.asmClobbers, srcSub.asmClobbers,
srcSub.asmParameterRegisters, params,
srcSub.asmReturnvaluesRegisters, srcSub.asmReturnvaluesRegisters,
srcSub.inline, srcSub.inline,
srcSub.position) srcSub.position)
@ -334,7 +345,8 @@ class IntermediateAstMaker(val srcProgram: Program) {
} }
private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer { 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(transform(srcArr.arrayvar))
array.add(transformExpression(srcArr.indexer.indexExpr)) array.add(transformExpression(srcArr.indexer.indexExpr))
return array return array
@ -348,14 +360,16 @@ class IntermediateAstMaker(val srcProgram: Program) {
} }
private fun transform(srcExpr: BinaryExpression): PtBinaryExpression { 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.left))
expr.add(transformExpression(srcExpr.right)) expr.add(transformExpression(srcExpr.right))
return expr return expr
} }
private fun transform(srcCall: BuiltinFunctionCall): PtBuiltinFunctionCall { 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) for (arg in srcCall.args)
call.add(transformExpression(arg)) call.add(transformExpression(arg))
return call return call
@ -384,7 +398,8 @@ class IntermediateAstMaker(val srcProgram: Program) {
PtNumber(number.type, number.number, number.position) PtNumber(number.type, number.number, number.position)
private fun transform(srcPipe: PipeExpression): PtPipe { 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)) pipe.add(transformExpression(srcPipe.source))
for (segment in srcPipe.segments) for (segment in srcPipe.segments)
pipe.add(transformExpression(segment)) pipe.add(transformExpression(segment))
@ -392,13 +407,15 @@ class IntermediateAstMaker(val srcProgram: Program) {
} }
private fun transform(srcPrefix: PrefixExpression): PtPrefix { 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)) prefix.add(transformExpression(srcPrefix.expression))
return prefix return prefix
} }
private fun transform(srcRange: RangeExpression): PtRange { 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.from))
range.add(transformExpression(srcRange.to)) range.add(transformExpression(srcRange.to))
range.add(transformExpression(srcRange.step)) range.add(transformExpression(srcRange.step))

View File

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

View File

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

View File

@ -3,6 +3,8 @@ TODO
For next release 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.print_ub(amount)
txt.nl() txt.nl()
; test_stack.test() uword[] @shared array = [111,222,333,444,555]
}
sub derp() -> ubyte, ubyte { amount = amount |> sin8u() |> cos8u() |> sin8u()
return 0, 1
; test_stack.test()
} }
sub find_next_prime() -> ubyte { sub find_next_prime() -> ubyte {