mirror of
https://github.com/irmen/prog8.git
synced 2024-07-05 06:29:02 +00:00
merge asmsub and normal sub
This commit is contained in:
parent
34fb82969c
commit
4df397d057
@ -1,7 +1,18 @@
|
||||
%option enable_floats
|
||||
|
||||
|
||||
|
||||
~ main {
|
||||
|
||||
asmsub MOVFM (mflpt: word @ AY) -> clobbers(A,Y) -> () = $bba2 ; load mflpt value from memory in A/Y into fac1
|
||||
asmsub FREADMEM () -> clobbers(A,Y) -> () = $bba6 ; load mflpt value from memory in $22/$23 into fac1
|
||||
asmsub CONUPK (mflpt: word @ AY) -> clobbers(A,Y) -> () = $ba8c ; load mflpt value from memory in A/Y into fac2
|
||||
asmsub FAREADMEM () -> clobbers(A,Y) -> () = $ba90 ; load mflpt value from memory in $22/$23 into fac2
|
||||
asmsub MOVFA () -> clobbers(A,X) -> () = $bbfc ; copy fac2 to fac1
|
||||
asmsub MOVAF () -> clobbers(A,X) -> () = $bc0c ; copy fac1 to fac2 (rounded)
|
||||
asmsub MOVEF () -> clobbers(A,X) -> () = $bc0f ; copy fac1 to fac2
|
||||
asmsub FTOMEMXY (mflpt: word @ XY) -> clobbers(A,Y) -> () = $bbd4 ; store fac1 to memory X/Y as 5-byte mflpt
|
||||
|
||||
|
||||
sub start() {
|
||||
|
||||
@ -22,6 +33,8 @@ sub start() {
|
||||
fvar = bvar
|
||||
fvar = wvar
|
||||
|
||||
MOVAF()
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
@ -217,10 +217,6 @@ interface IAstProcessor {
|
||||
return returnStmt
|
||||
}
|
||||
|
||||
fun process(asmSubroutine: AsmSubroutine): IStatement {
|
||||
return asmSubroutine
|
||||
}
|
||||
|
||||
fun process(arrayIndexedExpression: ArrayIndexedExpression): IExpression {
|
||||
arrayIndexedExpression.identifier?.process(this)
|
||||
arrayIndexedExpression.array.process(this)
|
||||
@ -1314,15 +1310,20 @@ class InlineAssembly(val assembly: String, override val position: Position) : IS
|
||||
}
|
||||
|
||||
|
||||
class RegisterOrStatusflag(val register: Register?, val statusflag: Statusflag?)
|
||||
|
||||
class Subroutine(override val name: String,
|
||||
val parameters: List<SubroutineParameter>,
|
||||
val returnvalues: List<DataType>,
|
||||
val asmParameterRegisters: List<RegisterOrStatusflag>,
|
||||
val asmReturnvaluesRegisters: List<RegisterOrStatusflag>,
|
||||
val asmClobbers: Set<Register>,
|
||||
val asmAddress: Int?,
|
||||
override var statements: MutableList<IStatement>,
|
||||
override val position: Position) : IStatement, INameScope {
|
||||
override lateinit var parent: Node
|
||||
val scopedname: String by lazy { makeScopedName(name).joinToString(".") }
|
||||
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
parameters.forEach { it.linkParents(this) }
|
||||
@ -1332,7 +1333,7 @@ class Subroutine(override val name: String,
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return "Subroutine(name=$name, parameters=$parameters, returnvalues=$returnvalues, ${statements.size} statements)"
|
||||
return "Subroutine(name=$name, parameters=$parameters, returnvalues=$returnvalues, ${statements.size} statements, address=$asmAddress)"
|
||||
}
|
||||
|
||||
override fun registerUsedName(name: String) = throw NotImplementedError("not implemented on sub-scopes")
|
||||
@ -1349,45 +1350,6 @@ open class SubroutineParameter(val name: String,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// @todo merge this with normal Subroutine?
|
||||
class AsmSubroutine(val name: String,
|
||||
val address: Int?,
|
||||
val params: List<AsmSubroutineParameter>,
|
||||
val returns: List<AsmSubroutineReturn>,
|
||||
val clobbers: Set<Register>,
|
||||
val statements: MutableList<IStatement>,
|
||||
override val position: Position) : IStatement {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
params.forEach { it.linkParents(this) }
|
||||
returns.forEach { it.linkParents(this) }
|
||||
statements.forEach { it.linkParents(this) }
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
}
|
||||
|
||||
class AsmSubroutineParameter(name: String,
|
||||
type: DataType,
|
||||
val register: Register?,
|
||||
val statusflag: Statusflag?,
|
||||
position: Position) : SubroutineParameter(name, type, position)
|
||||
|
||||
|
||||
class AsmSubroutineReturn(val type: DataType,
|
||||
val register: Register?,
|
||||
val statusflag: Statusflag?,
|
||||
override val position: Position): Node {
|
||||
override lateinit var parent: Node
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IfStatement(var condition: IExpression,
|
||||
var statements: List<IStatement>,
|
||||
var elsepart: List<IStatement>,
|
||||
@ -1619,11 +1581,25 @@ private fun prog8Parser.AsmsubroutineContext.toAst(): IStatement {
|
||||
val address = asmsub_address()?.address?.toAst()?.number?.toInt()
|
||||
val params = asmsub_params()?.toAst() ?: emptyList()
|
||||
val returns = asmsub_returns()?.toAst() ?: emptyList()
|
||||
val normalParameters = params.map { SubroutineParameter(it.name, it.type, it.position) }
|
||||
val normalReturnvalues = returns.map { it.type }
|
||||
val paramRegisters = params.map { RegisterOrStatusflag(it.register, it.statusflag) }
|
||||
val returnRegisters = returns.map { RegisterOrStatusflag(it.register, it.statusflag) }
|
||||
val clobbers = clobber()?.toAst() ?: emptySet()
|
||||
val statements = statement_block()?.toAst() ?: mutableListOf()
|
||||
return AsmSubroutine(name, address, params, returns, clobbers, statements, toPosition())
|
||||
return Subroutine(name, normalParameters, normalReturnvalues, paramRegisters, returnRegisters, clobbers, address, statements, toPosition())
|
||||
}
|
||||
|
||||
private class AsmSubroutineParameter(name: String,
|
||||
type: DataType,
|
||||
val register: Register?,
|
||||
val statusflag: Statusflag?,
|
||||
position: Position) : SubroutineParameter(name, type, position)
|
||||
|
||||
private class AsmSubroutineReturn(val type: DataType,
|
||||
val register: Register?,
|
||||
val statusflag: Statusflag?,
|
||||
val position: Position)
|
||||
|
||||
private fun prog8Parser.ClobberContext.toAst(): Set<Register>
|
||||
= this.register().asSequence().map { it.toAst() }.toSet()
|
||||
@ -1686,6 +1662,10 @@ private fun prog8Parser.SubroutineContext.toAst() : Subroutine {
|
||||
return Subroutine(identifier().text,
|
||||
sub_params()?.toAst() ?: emptyList(),
|
||||
sub_return_part()?.toAst() ?: emptyList(),
|
||||
emptyList(),
|
||||
emptyList(),
|
||||
emptySet(),
|
||||
null,
|
||||
statement_block()?.toAst() ?: mutableListOf(),
|
||||
toPosition())
|
||||
}
|
||||
|
@ -82,8 +82,9 @@ class AstChecker(private val namespace: INameScope,
|
||||
|
||||
override fun process(returnStmt: Return): IStatement {
|
||||
val expectedReturnValues = (returnStmt.definingScope() as? Subroutine)?.returnvalues ?: emptyList()
|
||||
if(expectedReturnValues.size != returnStmt.values.size)
|
||||
if(expectedReturnValues.size != returnStmt.values.size) {
|
||||
checkResult.add(SyntaxError("number of return values doesn't match subroutine return spec", returnStmt.position))
|
||||
}
|
||||
|
||||
for (rv in expectedReturnValues.withIndex().zip(returnStmt.values)) {
|
||||
if(rv.first.value!=rv.second.resultingDatatype(namespace, heap))
|
||||
@ -210,10 +211,14 @@ class AstChecker(private val namespace: INameScope,
|
||||
.map { (it as InlineAssembly).assembly }
|
||||
.count { "rts" in it || "\trts" in it || "jmp" in it || "\tjmp" in it }
|
||||
if (amount == 0) {
|
||||
if(subroutine.returnvalues.isNotEmpty())
|
||||
err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
|
||||
// if there's no return statement, we add the implicit one at the end.
|
||||
subroutine.statements.add(Return(emptyList(), subroutine.position))
|
||||
if(subroutine.returnvalues.isNotEmpty()) {
|
||||
// for asm subroutines with an address, no statement check is possible.
|
||||
if(subroutine.asmAddress==null)
|
||||
err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
|
||||
}
|
||||
// if there's no return statement, we add the implicit one at the end, but only if it's not a kernel routine.
|
||||
if(subroutine.asmAddress==null)
|
||||
subroutine.statements.add(Return(emptyList(), subroutine.position))
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,7 +236,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
var checkNext = false
|
||||
for (stmt in statements) {
|
||||
if(checkNext) {
|
||||
if(stmt !is Label && stmt !is Subroutine && stmt !is AsmSubroutine)
|
||||
if(stmt !is Label && stmt !is Subroutine)
|
||||
checkResult.add(SyntaxError("preceding subroutine definition at line ${preceding.position.line} must be followed here by a label, another subroutine statement, or nothing", stmt.position))
|
||||
return
|
||||
}
|
||||
@ -239,7 +244,6 @@ class AstChecker(private val namespace: INameScope,
|
||||
if(preceding !is Return
|
||||
&& preceding !is Jump
|
||||
&& preceding !is Subroutine
|
||||
&& preceding !is AsmSubroutine
|
||||
&& preceding !is VarDecl
|
||||
&& preceding !is BuiltinFunctionStatementPlaceholder) {
|
||||
checkResult.add(SyntaxError("subroutine definition must be preceded by a return, jump, vardecl, or another subroutine statement", stmt.position))
|
||||
|
@ -86,14 +86,16 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
nameError(name.key, name.value.position, subroutine)
|
||||
}
|
||||
|
||||
// inject subroutine params as local variables (if they're not there yet)
|
||||
subroutine.parameters
|
||||
.filter { !definedNames.containsKey(it.name) }
|
||||
.forEach {
|
||||
val vardecl = VarDecl(VarDeclType.VAR, it.type, null, it.name, null, subroutine.position)
|
||||
vardecl.linkParents(subroutine)
|
||||
subroutine.statements.add(0, vardecl)
|
||||
}
|
||||
// inject subroutine params as local variables (if they're not there yet) (for non-kernel subroutines)
|
||||
if(subroutine.asmAddress==null) {
|
||||
subroutine.parameters
|
||||
.filter { !definedNames.containsKey(it.name) }
|
||||
.forEach {
|
||||
val vardecl = VarDecl(VarDeclType.VAR, it.type, null, it.name, null, subroutine.position)
|
||||
vardecl.linkParents(subroutine)
|
||||
subroutine.statements.add(0, vardecl)
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.process(subroutine)
|
||||
}
|
||||
|
@ -246,18 +246,14 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
val continueStmtLabelStack : Stack<String> = Stack()
|
||||
|
||||
override fun process(subroutine: Subroutine): IStatement {
|
||||
stackvmProg.label(subroutine.scopedname)
|
||||
// note: the caller has already written the arguments into the subroutine's parameter variables.
|
||||
translate(subroutine.statements)
|
||||
return super.process(subroutine)
|
||||
}
|
||||
|
||||
override fun process(asmSubroutine: AsmSubroutine): IStatement {
|
||||
if(asmSubroutine.statements.isNotEmpty()) {
|
||||
stackvmProg.label(asmSubroutine.makeScopedName(asmSubroutine.name).joinToString("."))
|
||||
translate(asmSubroutine.statements)
|
||||
if(subroutine.asmAddress==null) {
|
||||
stackvmProg.label(subroutine.scopedname)
|
||||
// note: the caller has already written the arguments into the subroutine's parameter variables.
|
||||
translate(subroutine.statements)
|
||||
} else {
|
||||
throw CompilerException("kernel subroutines (with memory address and no body) are not supported by StackVM: $subroutine")
|
||||
}
|
||||
return super.process(asmSubroutine)
|
||||
return super.process(subroutine)
|
||||
}
|
||||
|
||||
override fun process(block: Block): IStatement {
|
||||
@ -297,7 +293,6 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
is WhileLoop -> translate(stmt)
|
||||
is RepeatLoop -> translate(stmt)
|
||||
is Directive, is VarDecl, is Subroutine -> {} // skip this, already processed these.
|
||||
is AsmSubroutine -> {}
|
||||
is InlineAssembly -> throw CompilerException("inline assembly is not supported by the StackVM")
|
||||
else -> TODO("translate statement $stmt to stackvm")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user