mirror of
https://github.com/irmen/prog8.git
synced 2024-08-02 07:29:05 +00:00
improve ast check for multiple returnvalues assignment
This commit is contained in:
parent
1e5b2e0be3
commit
747c9604dd
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user