mirror of
https://github.com/irmen/prog8.git
synced 2024-06-11 11:29:31 +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
|
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.
|
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::
|
.. attention::
|
||||||
**Data type conversion (in assignments):**
|
**Data type conversion (in assignments):**
|
||||||
When assigning a value with a 'smaller' datatype to variable with a 'larger' datatype,
|
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.
|
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.
|
Otherwise the compiler will warn you about discarding the result of the call.
|
||||||
|
|
||||||
|
.. _multiassign:
|
||||||
|
|
||||||
Multiple return values
|
Multiple return values
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Normal subroutines can only return zero or one return values.
|
Normal subroutines can only return zero or one return values.
|
||||||
However, the special ``asmsub`` routines (implemented in assembly code) or ``romsub`` routines
|
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.
|
(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.
|
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
|
In these cases, it is possible to do a "multi assign" where the multiple return values of the subroutine call,
|
||||||
directly from the language, because only single value assignments are possible.
|
are all assigned to individual assignment targets. You simply write them as a comma separated list, so for instance::
|
||||||
You can still call the subroutine and not store the results.
|
|
||||||
|
|
||||||
**There is an exception:** if there's just one return value in a register, and one or more others that are returned
|
bool flag
|
||||||
as bits in the status register (such as the Carry bit), the compiler allows you to call the subroutine.
|
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
|
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,
|
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.
|
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),
|
.. note::
|
||||||
you'll have to write a small block of custom inline assembly that does the call and stores the values
|
For asmsubs or romsubs that return a boolean status flag in a cpu status register such as the Carry flag,
|
||||||
appropriately. Don't forget to save/restore any registers that are modified.
|
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
|
Subroutine definitions
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
TODO
|
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
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
bool @shared flag
|
bool @shared flag
|
||||||
|
ubyte @shared bytevar
|
||||||
|
uword @shared wordvar
|
||||||
|
|
||||||
cx16.r1=9999
|
; cx16.r1=9999
|
||||||
flag = test(42)
|
; flag = test(42)
|
||||||
cx16.r0L, flag = test2(12345, 5566, flag, -42)
|
; cx16.r0L, flag = test2(12345, 5566, flag, -42)
|
||||||
cx16.r1, flag = test3()
|
; 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 $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 $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
|
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…
Reference in New Issue
Block a user