diff --git a/codeAst/src/prog8/code/ast/AstStatements.kt b/codeAst/src/prog8/code/ast/AstStatements.kt index 9f9a12d07..085c9aef1 100644 --- a/codeAst/src/prog8/code/ast/AstStatements.kt +++ b/codeAst/src/prog8/code/ast/AstStatements.kt @@ -8,7 +8,7 @@ class PtAsmSub( val address: UInt?, val clobbers: Set, val parameters: List>, - val returnTypes: List, + val returnTypes: List, // TODO join with register as Pairs ? val retvalRegisters: List, val inline: Boolean, position: Position diff --git a/codeGenExperimental/src/prog8/codegen/experimental/CodeGen.kt b/codeGenExperimental/src/prog8/codegen/experimental/CodeGen.kt index 7c0a320d4..9ebde884a 100644 --- a/codeGenExperimental/src/prog8/codegen/experimental/CodeGen.kt +++ b/codeGenExperimental/src/prog8/codegen/experimental/CodeGen.kt @@ -863,14 +863,14 @@ class CodeGen(internal val program: PtProgram, } private fun translate(block: PtBlock): IRBlock { - val vmblock = IRBlock(block.name, block.address, block.alignment, block.position) // no use for other attributes yet? + val vmblock = IRBlock(block.name, block.address, translate(block.alignment), block.position) // no use for other attributes yet? for (child in block.children) { when(child) { is PtNop -> { /* nothing */ } is PtAssignment -> { /* global variable initialization is done elsewhere */ } is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ } is PtSub -> { - val vmsub = IRSubroutine(child.name, child.returntype, child.position) + val vmsub = IRSubroutine(child.name, translate(child.parameters), child.returntype, child.position) for (subchild in child.children) { val translated = translateNode(subchild) if(translated.isNotEmpty()) @@ -880,7 +880,11 @@ class CodeGen(internal val program: PtProgram, } is PtAsmSub -> { val assembly = if(child.children.isEmpty()) "" else (child.children.single() as PtInlineAssembly).assembly - vmblock += IRAsmSubroutine(child.name, child.position, child.address, assembly) + vmblock += IRAsmSubroutine(child.name, child.position, child.address, + child.clobbers, + child.parameters.map { IRAsmSubroutine.IRAsmSubParam(it.first.name, it.first.type, it.second) }, + child.returnTypes.zip(child.retvalRegisters), + assembly) } is PtInlineAssembly -> { vmblock += IRInlineAsmChunk(child.assembly, child.position) @@ -891,6 +895,20 @@ class CodeGen(internal val program: PtProgram, return vmblock } + private fun translate(parameters: List) = + parameters.map { + val flattenedName = (it.definingSub()!!.scopedName + it.name) + symbolTable.flat.getValue(flattenedName) as StStaticVariable + } + + private fun translate(alignment: PtBlock.BlockAlignment): IRBlock.BlockAlignment { + return when(alignment) { + PtBlock.BlockAlignment.NONE -> IRBlock.BlockAlignment.NONE + PtBlock.BlockAlignment.WORD -> IRBlock.BlockAlignment.WORD + PtBlock.BlockAlignment.PAGE -> IRBlock.BlockAlignment.PAGE + } + } + internal fun vmType(type: DataType): VmDataType { return when(type) { diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index 9d6976b51..6e957fd4d 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -302,6 +302,8 @@ class IntermediateAstMaker(val program: Program) { srcSub.asmReturnvaluesRegisters, srcSub.inline, srcSub.position) + sub.parameters.forEach { it.first.parent=sub } + if(srcSub.asmAddress==null) { var combinedAsm = "" for (asm in srcSub.statements) @@ -322,6 +324,7 @@ class IntermediateAstMaker(val program: Program) { srcSub.returntypes.singleOrNull(), srcSub.inline, srcSub.position) + sub.parameters.forEach { it.parent=sub } if(vardecls.isNotEmpty()) sub.add(makeScopeVarsDecls(vardecls, sub.position)) for (statement in statements) diff --git a/examples/test.p8 b/examples/test.p8 index b8574fad7..ee1676e23 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -55,10 +55,10 @@ a_label: qq=global1 qq=other.global2 - nested() + nested(11,22) main.start.nested.nested2() - sub nested() { + sub nested(ubyte a1, ubyte a2) { qq++ txt.print("zzz") nested2() diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 3e93ed6b1..24c85a0ac 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -1,7 +1,6 @@ package prog8.intermediate import prog8.code.* -import prog8.code.ast.PtBlock import prog8.code.core.* import prog8.code.target.* import java.nio.file.Path @@ -30,7 +29,7 @@ class IRFileReader(outputDir: Path, programName: String) { val memorymapped = parseMemMapped(lines) val slabs = parseSlabs(lines) val initGlobals = parseInitGlobals(lines) - val blocks = parseBlocksUntilProgramEnd(lines) + val blocks = parseBlocksUntilProgramEnd(lines, variables) val st = SymbolTable() variables.forEach { st.add(it) } @@ -226,7 +225,7 @@ class IRFileReader(outputDir: Path, programName: String) { return chunk } - private fun parseBlocksUntilProgramEnd(lines: Iterator): List { + private fun parseBlocksUntilProgramEnd(lines: Iterator, variables: List): List { val blocks = mutableListOf() while(true) { var line = lines.next() @@ -234,27 +233,27 @@ class IRFileReader(outputDir: Path, programName: String) { line = lines.next() if (line == "") break - blocks.add(parseBlock(line, lines)) + blocks.add(parseBlock(line, lines, variables)) } return blocks } private val blockPattern = Regex("") private val inlineAsmPattern = Regex("") - private val asmsubPattern = Regex("") + private val asmsubPattern = Regex("") private val subPattern = Regex("") private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]") private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE) private val labelPattern = Regex("""_([a-zA-Z\d\._]+):""") - private fun parseBlock(startline: String, lines: Iterator): IRBlock { + private fun parseBlock(startline: String, lines: Iterator, variables: List): IRBlock { var line = startline if(!line.startsWith("") return block if(line.startsWith("): IRAsmSubroutine { - // - // TODO parse more signature stuff once it's there. + // val match = asmsubPattern.matchEntire(startline) ?: throw IRParseException("invalid ASMSUB") - val (scopedname, address, pos) = match.destructured + val (scopedname, address, clobbers, pos) = match.destructured var line = lines.next() val asm = parseInlineAssembly(line, lines) while(line!="") line = lines.next() - return IRAsmSubroutine(scopedname, parsePosition(pos), if(address=="null") null else address.toUInt(), asm.asm) + val clobberRegs = clobbers.split(',').map { CpuRegister.valueOf(it) } + // TODO parse this additional signature stuff once it's there. + val parameters = mutableListOf() + val returns = mutableListOf>() + return IRAsmSubroutine(scopedname, + parsePosition(pos), if(address=="null") null else address.toUInt(), + clobberRegs.toSet(), + parameters, + returns, + asm.asm) } - private fun parseSubroutine(startline: String, lines: Iterator): IRSubroutine { + private fun parseSubroutine(startline: String, lines: Iterator, variables: List): IRSubroutine { // - // TODO parse more signature stuff once it's there. val match = subPattern.matchEntire(startline) ?: throw IRParseException("invalid SUB") val (name, returntype, pos) = match.destructured - val sub = IRSubroutine(name, if(returntype=="null") null else parseDatatype(returntype, false), parsePosition(pos)) + val sub = IRSubroutine(name, + parseParameters(lines, variables), + if(returntype=="null") null else parseDatatype(returntype, false), + parsePosition(pos)) while(true) { val line = lines.next() if(line=="") @@ -328,6 +337,21 @@ class IRFileReader(outputDir: Path, programName: String) { return sub } + private fun parseParameters(lines: Iterator, variables: List): List { + var line = lines.next() + if(line!="") + throw IRParseException("missing PARAMS") + val params = mutableListOf() + while(true) { + line = lines.next() + if(line=="") + return params + val (datatype, name) = line.split(' ') + val dt = parseDatatype(datatype, datatype.contains('[')) + params.add(variables.single { it.dt==dt && it.name==name}) + } + } + private fun parseCodeChunk(firstline: String, lines: Iterator): IRCodeChunk? { if(firstline!="") { if(firstline=="") diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index b978abd9a..167ff348b 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -39,7 +39,9 @@ class IRFileWriter(private val irProgram: IRProgram) { } block.subroutines.forEach { out.write("\n") - // TODO rest of the signature + out.write("\n") + it.parameters.forEach { param -> out.write("${getTypeString(param)} ${param.scopedName.joinToString(".")}\n") } + out.write("\n") it.chunks.forEach { chunk -> if(chunk is IRInlineAsmChunk) { writeInlineAsm(chunk) @@ -54,8 +56,9 @@ class IRFileWriter(private val irProgram: IRProgram) { out.write("\n") } block.asmSubroutines.forEach { - out.write("\n") - // TODO rest of the signature + val clobbers = it.clobbers.joinToString(",") + out.write("\n") + // TODO rest of the signature: RETURNS = it.returns out.write("\n") out.write(it.assembly.trimStart('\n').trimEnd(' ', '\n')) out.write("\n\n\n") @@ -130,6 +133,22 @@ class IRFileWriter(private val irProgram: IRProgram) { out.write("\n") } + private fun getTypeString(dt : DataType): String { + return when(dt) { + DataType.UBYTE -> "ubyte" + DataType.BYTE -> "byte" + DataType.UWORD -> "uword" + DataType.WORD -> "word" + DataType.FLOAT -> "float" + DataType.ARRAY_UB, DataType.STR -> "ubyte[]" + DataType.ARRAY_B -> "byte[]" + DataType.ARRAY_UW -> "uword[]" + DataType.ARRAY_W -> "word[]" + DataType.ARRAY_F -> "float[]" + else -> throw InternalCompilerException("weird dt") + } + } + private fun getTypeString(memvar: StMemVar): String { return when(memvar.dt) { DataType.UBYTE -> "ubyte" diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index e61327604..5c39c575b 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -1,11 +1,8 @@ package prog8.intermediate +import prog8.code.StStaticVariable import prog8.code.SymbolTable -import prog8.code.ast.PtBlock -import prog8.code.core.CompilationOptions -import prog8.code.core.DataType -import prog8.code.core.IStringEncoding -import prog8.code.core.Position +import prog8.code.core.* /* @@ -25,6 +22,7 @@ PROGRAM: INLINEASM INLINEASM SUB + PARAMS INLINEASM INLINEASM C (CODE) @@ -65,13 +63,19 @@ class IRProgram(val name: String, class IRBlock( val name: String, val address: UInt?, - val alignment: PtBlock.BlockAlignment, + val alignment: BlockAlignment, val position: Position ) { val subroutines = mutableListOf() val asmSubroutines = mutableListOf() val inlineAssembly = mutableListOf() + enum class BlockAlignment { + NONE, + WORD, + PAGE + } + operator fun plusAssign(sub: IRSubroutine) { subroutines += sub } @@ -80,8 +84,10 @@ class IRBlock( } class IRSubroutine(val name: String, + val parameters: List, // NOTE: these are the same objects as their occurrences as variables in the symbol table val returnType: DataType?, val position: Position) { + val chunks = mutableListOf() init { @@ -97,6 +103,9 @@ class IRSubroutine(val name: String, class IRAsmSubroutine(val name: String, val position: Position, val address: UInt?, + val clobbers: Set, + val parameters: List, + val returns: List>, val assembly: String) { val lines = mutableListOf() @@ -106,6 +115,8 @@ class IRAsmSubroutine(val name: String, if(name.startsWith("main.main.")) throw IllegalArgumentException("subroutine name invalid main prefix: $name") } + + class IRAsmSubParam(val name: String, val dt: DataType, val reg: RegisterOrStatusflag) } sealed class IRCodeLine