no more Gosub node in new Ast, back to Functioncalls there.

This commit is contained in:
Irmen de Jong 2022-03-22 22:48:07 +01:00
parent 7b27d270a2
commit dbc7ad2ec4
7 changed files with 93 additions and 72 deletions

View File

@ -86,13 +86,6 @@ class PtForLoop(position: Position) : PtNode(position) {
}
class PtGosub(val identifier: PtIdentifier, position: Position) : PtNode(position) {
override fun printProperties() {
identifier.printProperties()
}
}
class PtIfElse(position: Position) : PtNode(position) {
val condition: PtExpression
get() = children[0] as PtExpression

View File

@ -164,7 +164,6 @@ class AstToXmlConverter(internal val program: PtProgram,
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)
@ -554,12 +553,6 @@ class AstToXmlConverter(internal val program: PtProgram,
xml.endElt()
}
private fun write(gosub: PtGosub) {
xml.elt("gosub")
xml.attr("symbol", strTargetName(gosub.identifier))
xml.endElt()
}
private fun write(sub: PtSub) {
xml.elt("sub")
xml.attr("name", sub.scopedName.joinToString("."))

View File

@ -1,43 +0,0 @@
package prog8.codegen.virtual
import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.ast.PtNumber
import prog8.vm.Instruction
import prog8.vm.Opcode
internal class BuiltinFunctionsGen(val codegen: CodeGen) {
fun translate(call: PtBuiltinFunctionCall): VmCodeChunk {
val chunk = VmCodeChunk()
when(call.name) {
"syscall" -> {
val vExpr = call.args.single() as PtNumber
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall1" -> {
val vExpr = call.args[0] as PtNumber
val vExpr1 = call.args[1] as PtNumber
// TODO assign regs
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall2" -> {
val vExpr = call.args[0] as PtNumber
val vExpr1 = call.args[1] as PtNumber
val vExpr2 = call.args[2] as PtNumber
// TODO assign regs
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall3" -> {
val vExpr = call.args[0] as PtNumber
val vExpr1 = call.args[1] as PtNumber
val vExpr2 = call.args[2] as PtNumber
val vExpr3 = call.args[3] as PtNumber
// TODO assign regs
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
else -> {
TODO("builtinfunc ${call.name}")
}
}
return chunk
}
}

View File

@ -15,8 +15,7 @@ class CodeGen(internal val program: PtProgram,
): IAssemblyGenerator {
internal val allocations = VariableAllocator(symbolTable, program, errors)
private val builtinFunctions = BuiltinFunctionsGen(this)
private val expressionEval = ExpressionGen(this, builtinFunctions)
private val expressionEval = ExpressionGen(this)
private val instructions = mutableListOf<String>()
init {
@ -93,7 +92,7 @@ class CodeGen(internal val program: PtProgram,
is PtArrayIndexer -> TODO()
is PtArrayLiteral -> TODO()
is PtBinaryExpression -> TODO()
is PtBuiltinFunctionCall -> builtinFunctions.translate(node)
is PtBuiltinFunctionCall -> expressionEval.translate(node)
is PtContainmentCheck -> TODO()
is PtFunctionCall -> translate(node)
is PtIdentifier -> TODO()
@ -105,7 +104,6 @@ class CodeGen(internal val program: PtProgram,
is PtString -> TODO()
is PtTypeCast -> TODO()
is PtForLoop -> TODO()
is PtGosub -> translate(node)
is PtIfElse -> TODO()
is PtJump -> TODO()
is PtNodeGroup -> TODO()
@ -128,17 +126,17 @@ class CodeGen(internal val program: PtProgram,
private fun translate(fcall: PtFunctionCall): VmCodeChunk {
val chunk = VmCodeChunk()
// TODO evaluate function call arguments
for ((index, arg) in fcall.args.withIndex()) {
// TODO make sure the expressions code doesn't clobber the previous registers, and doesn't use the r0, r1, r2... which are needed to pass the args
val (expressionChunk, resultRegister) = expressionEval.translateExpression(arg)
chunk += expressionChunk
if(resultRegister!=index)
chunk += VmCodeInstruction(Instruction(Opcode.LOADR, vmType(arg.type), reg1=0, reg2=resultRegister))
}
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(fcall.functionName))
return chunk
}
private fun translate(gosub: PtGosub): VmCodeChunk {
val chunk = VmCodeChunk()
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(gosub.identifier.targetName))
return chunk
}
private fun translate(ret: PtReturn): VmCodeChunk {
val chunk = VmCodeChunk()
val value = ret.value

View File

@ -5,7 +5,7 @@ import prog8.code.core.AssemblyError
import prog8.vm.Instruction
import prog8.vm.Opcode
internal class ExpressionGen(val codeGen: CodeGen, val builtinFunctions: BuiltinFunctionsGen) {
internal class ExpressionGen(val codeGen: CodeGen) {
fun translateExpression(expr: PtExpression): Pair<VmCodeChunk, Int> {
// TODO("Not yet implemented")
val chunk = VmCodeChunk()
@ -80,4 +80,50 @@ internal class ExpressionGen(val codeGen: CodeGen, val builtinFunctions: Builtin
return Pair(chunk, 0) // TODO function result always in r0?
}
fun translate(call: PtBuiltinFunctionCall): VmCodeChunk {
val chunk = VmCodeChunk()
when(call.name) {
"syscall" -> {
val vExpr = call.args.single() as PtNumber
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall1" -> {
val vExpr = call.args[0] as PtNumber
// TODO make sure it evaluates into r0
val (expressionChunk0, resultRegister0) = translateExpression(call.args[1])
chunk += expressionChunk0
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall2" -> {
val vExpr = call.args[0] as PtNumber
// TODO make sure it evaluates into r0
val (expressionChunk0, resultRegister0) = translateExpression(call.args[1])
chunk += expressionChunk0
// TODO make sure it evaluates into r1
val (expressionChunk1, resultRegister1) = translateExpression(call.args[2])
chunk += expressionChunk1
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall3" -> {
val vExpr = call.args[0] as PtNumber
// TODO make sure it evaluates into r0
val (expressionChunk0, resultRegister0) = translateExpression(call.args[1])
chunk += expressionChunk0
// TODO make sure it evaluates into r1
val (expressionChunk1, resultRegister1) = translateExpression(call.args[2])
chunk += expressionChunk1
// TODO make sure it evaluates into r2
val (expressionChunk2, resultRegister2) = translateExpression(call.args[3])
chunk += expressionChunk2
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
else -> {
TODO("builtinfunc ${call.name}")
}
}
return chunk
}
}

View File

@ -4,6 +4,7 @@ import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.getOrElse
import com.github.michaelbull.result.mapError
import prog8.ast.IStatementContainer
import prog8.ast.Program
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.*
@ -87,7 +88,13 @@ class IntermediateAstMaker(val program: Program) {
}
}
private fun transform(srcAssign: Assignment): PtAssignment {
private fun transform(srcAssign: Assignment): PtNode {
if(srcAssign.origin==AssignmentOrigin.PARAMETERASSIGN) {
// assignments that are setting the parameters for a function call,
// will be gathered at the GoSub itself later.
return PtNop(srcAssign.position)
}
val assign = PtAssignment(srcAssign.isAugmentable, srcAssign.position)
assign.add(transform(srcAssign.target))
assign.add(transformExpression(srcAssign.value))
@ -222,7 +229,35 @@ class IntermediateAstMaker(val program: Program) {
return call
}
private fun transform(gosub: GoSub): PtGosub = PtGosub(transform(gosub.identifier), gosub.position)
private fun transform(gosub: GoSub): PtFunctionCall {
// Gather the Goto and any preceding parameter assignments back into a single Function call node.
// (the reason it was split up in the first place, is because the Compiler Ast optimizers
// can then work on any complex expressions that are used as arguments.)
val parent = gosub.parent as IStatementContainer
val gosubIdx = parent.statements.indexOf(gosub)
val previousNodes = parent.statements.subList(0, gosubIdx).reversed()
val paramAssigns = mutableListOf<Assignment>()
for (node in previousNodes) {
if(node !is Assignment || node.origin!=AssignmentOrigin.PARAMETERASSIGN)
break
paramAssigns += node
}
val parameters = gosub.identifier.targetSubroutine(program)!!.parameters
if(paramAssigns.size != parameters.size)
throw FatalAstException("mismatched number of parameter assignments for function call")
val target = transform(gosub.identifier)
val call = PtFunctionCall(target.targetName, true, DataType.UNDEFINED, gosub.position)
// put arguments in correct order for the parameters
val namedAssigns = paramAssigns.associate { it.target.identifier!!.targetVarDecl(program)!!.name to it.value }
parameters.forEach {
val argument = namedAssigns.getValue(it.name)
call.add(transformExpression(argument))
}
return call
}
private fun transform(srcIf: IfElse): PtIfElse {
val ifelse = PtIfElse(srcIf.position)

View File

@ -3,7 +3,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- in new AST: combine param assignments + GoSub, back into PtFunctionCall node. PtGosub node should not exist.
...