improve ast check for multiple returnvalues assignment

This commit is contained in:
Irmen de Jong 2019-03-18 04:01:25 +01:00
parent 1e5b2e0be3
commit 747c9604dd
4 changed files with 38 additions and 19 deletions

View File

@ -355,7 +355,7 @@ private class AstChecker(private val namespace: INameScope,
// assigning from a functioncall COULD return multiple values (from an asm subroutine) // assigning from a functioncall COULD return multiple values (from an asm subroutine)
if(assignment.value is FunctionCall) { if(assignment.value is FunctionCall) {
val stmt = (assignment.value as FunctionCall).target.targetStatement(namespace) val stmt = (assignment.value as FunctionCall).target.targetStatement(namespace)
if (stmt is Subroutine && stmt.returntypes.size > 1) { if (stmt is Subroutine) {
if (stmt.isAsmSubroutine) { if (stmt.isAsmSubroutine) {
if (stmt.returntypes.size != assignment.targets.size) if (stmt.returntypes.size != assignment.targets.size)
checkResult.add(ExpressionError("number of return values doesn't match number of assignment targets", assignment.value.position)) checkResult.add(ExpressionError("number of return values doesn't match number of assignment targets", assignment.value.position))
@ -371,7 +371,7 @@ private class AstChecker(private val namespace: INameScope,
checkResult.add(ExpressionError("return type mismatch for target ${thing.second.shortString()}", assignment.value.position)) checkResult.add(ExpressionError("return type mismatch for target ${thing.second.shortString()}", assignment.value.position))
} }
} }
} else } else if(assignment.targets.size>1)
checkResult.add(ExpressionError("only asmsub subroutines can return multiple values", assignment.value.position)) checkResult.add(ExpressionError("only asmsub subroutines can return multiple values", assignment.value.position))
} }
} }

View File

@ -644,10 +644,8 @@ internal class Compiler(private val rootModule: Module,
val funcname = expr.target.nameInSource[0] val funcname = expr.target.nameInSource[0]
translateBuiltinFunctionCall(funcname, expr.arglist) translateBuiltinFunctionCall(funcname, expr.arglist)
} else { } else {
when(target) { if (target is Subroutine) translateSubroutineCall(target, expr.arglist, expr.position)
is Subroutine -> translateSubroutineCall(target, expr.arglist, expr.position) else TODO("non-builtin-function call to $target")
else -> TODO("non-builtin-function call to $target")
}
} }
} }
is IdentifierReference -> translate(expr) is IdentifierReference -> translate(expr)
@ -670,7 +668,7 @@ internal class Compiler(private val rootModule: Module,
in ArrayDatatypes -> { in ArrayDatatypes -> {
if(lv.heapId==null) if(lv.heapId==null)
throw CompilerException("array should have been moved into heap ${lv.position}") throw CompilerException("array should have been moved into heap ${lv.position}")
TODO("push address of array with PUSH_WORD") TODO("push address of array with PUSH_ADDR_HEAPVAR")
} }
else -> throw CompilerException("weird datatype") else -> throw CompilerException("weird datatype")
} }
@ -1013,7 +1011,7 @@ internal class Compiler(private val rootModule: Module,
// (in reversed order) otherwise the asm-subroutine can't be used in expressions. // (in reversed order) otherwise the asm-subroutine can't be used in expressions.
for(rv in subroutine.asmReturnvaluesRegisters.reversed()) { for(rv in subroutine.asmReturnvaluesRegisters.reversed()) {
if(rv.statusflag!=null) if(rv.statusflag!=null)
TODO("not yet supported: return values in cpu status flag $rv $subroutine") TODO("not yet supported: return values in cpu status flag $rv ($subroutine)")
when(rv.registerOrPair) { when(rv.registerOrPair) {
A,X,Y -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = rv.registerOrPair.name) A,X,Y -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = rv.registerOrPair.name)
AX -> prog.instr(Opcode.PUSH_REGAX_WORD) AX -> prog.instr(Opcode.PUSH_REGAX_WORD)

View File

@ -362,14 +362,13 @@ Operators
.. todo:: .. todo::
address-of: ``#`` or ``&`` (to stay close to C) address-of: ``#`` or ``&`` (to stay close to C)
Takes the address of the symbol following it: ``word address = &somevar`` Takes the address of the symbol following it: ``word address = &somevar``
Perhaps requires an explicit pointer type as well instead of just word? Perhaps requires an explicit pointer type as well instead of just word?
This can replace the ``memory`` var decl prefix as well, instead of This can replace the ``memory`` var decl prefix as well, instead of
``memory uword var = $c000`` we could write ``&uword var = $c000`` ``memory uword var = $c000`` we could write ``&uword var = $c000``
arithmetic: ``+`` ``-`` ``*`` ``/`` ``**`` ``%`` arithmetic: ``+`` ``-`` ``*`` ``/`` ``**`` ``%``
``+``, ``-``, ``*``, ``/`` are the familiar arithmetic operations. ``+``, ``-``, ``*``, ``/`` are the familiar arithmetic operations.
``/`` is division (will result in integer division when using on integer operands, and a floating point division when at least one of the operands is a float) ``/`` is division (will result in integer division when using on integer operands, and a floating point division when at least one of the operands is a float)
@ -436,10 +435,20 @@ You call a subroutine like this::
[ result = ] subroutinename_or_address ( [argument...] ) [ result = ] subroutinename_or_address ( [argument...] )
; example: ; example:
resultvariable = subroutine ( arg1, arg2, arg3 ) resultvariable = subroutine(arg1, arg2, arg3)
Arguments are separated by commas. The argument list can also be empty if the subroutine Arguments are separated by commas. The argument list can also be empty if the subroutine
takes no parameters. takes no parameters. If the subroutine returns a value, you can still omit the assignment to
a result variable (but the compiler will warn you about discarding the result of the call).
Normal subroutines can only return zero or one return values.
However, the special ``asmsub`` routines (implemented in assembly code or referencing
a routine in kernel ROM) can return more than one return values, for instance a status
in the carry bit and a number in A, or a 16-bit value in A/Y registers.
Only for these kind of subroutines it is possible to write a multi value assignment to
store the resulting values::
var1, var2, var3 = asmsubroutine()

View File

@ -6,14 +6,26 @@
; @todo see problem in looplabelproblem.p8 ; @todo see problem in looplabelproblem.p8
sub start() { sub start() {
for ubyte i in "hello\n" { str text = "hello"
c64.CHROUT(i) ubyte ub1
} ubyte ub2
ubyte ub3
ubyte ub4
ubyte ub5
for ubyte j in [1,2,3,4,5] { ub1, ub2, ub3, ub4, ub5 = test()
c64scr.print_ub(j) }
c64.CHROUT('\n')
} sub test1() -> ubyte {
return 99
}
asmsub test() -> clobbers() -> (ubyte @Pc, ubyte @Pz, ubyte @Pn, ubyte @Pv, ubyte @A) {
%asm {{
lda #99
sec
rts
}}
} }
} }