mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
docs about multi-assign
This commit is contained in:
parent
4700a239b9
commit
56f41d5e34
@ -654,6 +654,11 @@ a fixed amount of memory which will not change. (You *can* change the value of
|
||||
It is possible to "chain" assignments: ``x = y = z = 42``, this is just a shorthand
|
||||
for the three individual assignments with the same value 42.
|
||||
|
||||
Only for certain subroutines that return multiple values it is possible to write a "multi assign" statement
|
||||
with comma separated assignment targets, that assigns those multiple values to different targets in one statement.
|
||||
Details can be found here: :ref:`multiassign`.
|
||||
|
||||
|
||||
.. attention::
|
||||
**Data type conversion (in assignments):**
|
||||
When assigning a value with a 'smaller' datatype to variable with a 'larger' datatype,
|
||||
|
@ -665,25 +665,35 @@ takes no parameters. If the subroutine returns a value, usually you assign it t
|
||||
If you're not interested in the return value, prefix the function call with the ``void`` keyword.
|
||||
Otherwise the compiler will warn you about discarding the result of the call.
|
||||
|
||||
.. _multiassign:
|
||||
|
||||
Multiple return values
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
Normal subroutines can only return zero or one return values.
|
||||
However, the special ``asmsub`` routines (implemented in assembly code) or ``romsub`` routines
|
||||
(referencing a routine in Kernal ROM) can return more than one return value.
|
||||
For example a status in the carry bit and a number in A, or a 16-bit value in A/Y registers.
|
||||
It is not possible to process the results of a call to these kind of routines
|
||||
directly from the language, because only single value assignments are possible.
|
||||
You can still call the subroutine and not store the results.
|
||||
In these cases, it is possible to do a "multi assign" where the multiple return values of the subroutine call,
|
||||
are all assigned to individual assignment targets. You simply write them as a comma separated list, so for instance::
|
||||
|
||||
**There is an exception:** if there's just one return value in a register, and one or more others that are returned
|
||||
as bits in the status register (such as the Carry bit), the compiler allows you to call the subroutine.
|
||||
bool flag
|
||||
ubyte bytevar
|
||||
uword wordvar
|
||||
|
||||
wordvar, flag, bytevar = multisub() ; call and assign the three result values
|
||||
|
||||
asmsub multisub() -> uword @AY, bool @Pc, ubyte @X { ... }
|
||||
|
||||
**There is also a special rule:** if there's just one return value in a register, and one or more others that are returned
|
||||
as bits in the status register (such as the Carry bit), the compiler *also* allows you to call the subroutine and just assign a *single* return value.
|
||||
It will then store the result value in a variable if required, and *try to keep the status register untouched
|
||||
after the call* so you can often use a conditional branch statement for that. But the latter is tricky,
|
||||
make sure you check the generated assembly code.
|
||||
|
||||
If there really are multiple relevant return values (other than a combined 16 bit return value in 2 registers),
|
||||
you'll have to write a small block of custom inline assembly that does the call and stores the values
|
||||
appropriately. Don't forget to save/restore any registers that are modified.
|
||||
.. note::
|
||||
For asmsubs or romsubs that return a boolean status flag in a cpu status register such as the Carry flag,
|
||||
it is always more efficient to use a conditional branch like `if_cs` to act on that value, than storing
|
||||
it in a variable and then adding an `if flag...` statement afterwards.
|
||||
|
||||
|
||||
Subroutine definitions
|
||||
|
@ -1,7 +1,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
add docs for multi-assigns.
|
||||
make it possible to omit the Status Register values in multi-assigns regardless of the number of return values (is now 1 value)
|
||||
|
||||
...
|
||||
|
||||
|
@ -1,17 +1,42 @@
|
||||
%import textio
|
||||
%import test_stack
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
bool @shared flag
|
||||
ubyte @shared bytevar
|
||||
uword @shared wordvar
|
||||
|
||||
cx16.r1=9999
|
||||
flag = test(42)
|
||||
cx16.r0L, flag = test2(12345, 5566, flag, -42)
|
||||
cx16.r1, flag = test3()
|
||||
; cx16.r1=9999
|
||||
; flag = test(42)
|
||||
; cx16.r0L, flag = test2(12345, 5566, flag, -42)
|
||||
; cx16.r1, flag = test3()
|
||||
|
||||
wordvar, bytevar, flag = test4()
|
||||
wordvar, bytevar, flag = test4()
|
||||
|
||||
txt.print_uwhex(wordvar, true)
|
||||
txt.spc()
|
||||
txt.print_bool(flag)
|
||||
txt.spc()
|
||||
txt.print_ub(bytevar)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
romsub $8000 = test(ubyte arg @A) -> bool @Pc
|
||||
romsub $8002 = test2(uword arg @AY, uword arg2 @R1, bool flag @Pc, byte value @X) -> ubyte @A, bool @Pc
|
||||
romsub $8003 = test3() -> uword @R1, bool @Pc
|
||||
|
||||
|
||||
asmsub test4() -> uword @AY, ubyte @X, bool @Pc {
|
||||
%asm {{
|
||||
lda #<$11ee
|
||||
ldy #>$11ee
|
||||
ldx #42
|
||||
sec
|
||||
rts
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user