From 747c9604ddb2d406e8e6c640b812f2c48895cbfb Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 18 Mar 2019 04:01:25 +0100 Subject: [PATCH] improve ast check for multiple returnvalues assignment --- compiler/src/prog8/ast/AstChecker.kt | 4 ++-- compiler/src/prog8/compiler/Compiler.kt | 10 ++++------ docs/source/syntaxreference.rst | 17 ++++++++++++---- examples/test.p8 | 26 ++++++++++++++++++------- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 8b0b26e64..e9b5223d5 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -355,7 +355,7 @@ private class AstChecker(private val namespace: INameScope, // assigning from a functioncall COULD return multiple values (from an asm subroutine) if(assignment.value is FunctionCall) { 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.returntypes.size != assignment.targets.size) 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)) } } - } else + } else if(assignment.targets.size>1) checkResult.add(ExpressionError("only asmsub subroutines can return multiple values", assignment.value.position)) } } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index ee2ccb660..3f8f72143 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -644,10 +644,8 @@ internal class Compiler(private val rootModule: Module, val funcname = expr.target.nameInSource[0] translateBuiltinFunctionCall(funcname, expr.arglist) } else { - when(target) { - is Subroutine -> translateSubroutineCall(target, expr.arglist, expr.position) - else -> TODO("non-builtin-function call to $target") - } + if (target is Subroutine) translateSubroutineCall(target, expr.arglist, expr.position) + else TODO("non-builtin-function call to $target") } } is IdentifierReference -> translate(expr) @@ -670,7 +668,7 @@ internal class Compiler(private val rootModule: Module, in ArrayDatatypes -> { if(lv.heapId==null) 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") } @@ -1013,7 +1011,7 @@ internal class Compiler(private val rootModule: Module, // (in reversed order) otherwise the asm-subroutine can't be used in expressions. for(rv in subroutine.asmReturnvaluesRegisters.reversed()) { 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) { A,X,Y -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = rv.registerOrPair.name) AX -> prog.instr(Opcode.PUSH_REGAX_WORD) diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index f6b821d76..b2998663c 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -362,14 +362,13 @@ Operators .. todo:: 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? This can replace the ``memory`` var decl prefix as well, instead of ``memory uword var = $c000`` we could write ``&uword var = $c000`` - arithmetic: ``+`` ``-`` ``*`` ``/`` ``**`` ``%`` ``+``, ``-``, ``*``, ``/`` 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) @@ -436,10 +435,20 @@ You call a subroutine like this:: [ result = ] subroutinename_or_address ( [argument...] ) ; 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 -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() diff --git a/examples/test.p8 b/examples/test.p8 index 9d2ff0f97..0c23b6a6e 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,14 +6,26 @@ ; @todo see problem in looplabelproblem.p8 sub start() { - for ubyte i in "hello\n" { - c64.CHROUT(i) - } + str text = "hello" + ubyte ub1 + ubyte ub2 + ubyte ub3 + ubyte ub4 + ubyte ub5 - for ubyte j in [1,2,3,4,5] { - c64scr.print_ub(j) - c64.CHROUT('\n') - } + ub1, ub2, ub3, ub4, ub5 = test() + } + + sub test1() -> ubyte { + return 99 + } + + asmsub test() -> clobbers() -> (ubyte @Pc, ubyte @Pz, ubyte @Pn, ubyte @Pv, ubyte @A) { + %asm {{ + lda #99 + sec + rts + }} } }