mirror of
https://github.com/irmen/prog8.git
synced 2025-02-19 11:31:07 +00:00
return statement only has one single possible value
astvm can now more or less run all examples
This commit is contained in:
parent
3d7a4bf81a
commit
845a99d623
2
clean.sh
2
clean.sh
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
rm *.jar *.asm *.prg *.vm.txt *.vice-mon-list
|
rm *.jar *.asm *.prg *.vm.txt *.vice-mon-list
|
||||||
rm -r build
|
rm -rf build out
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
1.10-dev
|
1.10
|
||||||
|
@ -246,8 +246,7 @@ private fun prog8Parser.InlineasmContext.toAst() =
|
|||||||
|
|
||||||
|
|
||||||
private fun prog8Parser.ReturnstmtContext.toAst() : Return {
|
private fun prog8Parser.ReturnstmtContext.toAst() : Return {
|
||||||
val values = expression_list()
|
return Return(expression()?.toAst(), toPosition())
|
||||||
return Return(values?.toAst() ?: emptyList(), toPosition())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prog8Parser.UnconditionaljumpContext.toAst(): Jump {
|
private fun prog8Parser.UnconditionaljumpContext.toAst(): Jump {
|
||||||
|
@ -90,20 +90,20 @@ internal class AstChecker(private val program: Program,
|
|||||||
|
|
||||||
override fun visit(returnStmt: Return): IStatement {
|
override fun visit(returnStmt: Return): IStatement {
|
||||||
val expectedReturnValues = returnStmt.definingSubroutine()?.returntypes ?: emptyList()
|
val expectedReturnValues = returnStmt.definingSubroutine()?.returntypes ?: emptyList()
|
||||||
if(expectedReturnValues.size != returnStmt.values.size) {
|
if(expectedReturnValues.size>1) {
|
||||||
// if the return value is a function call, check the result of that call instead
|
throw AstException("cannot use a return with one value in a subroutine that has multiple return values: $returnStmt")
|
||||||
if(returnStmt.values.size==1 && returnStmt.values[0] is FunctionCall) {
|
|
||||||
val dt = (returnStmt.values[0] as FunctionCall).inferType(program)
|
|
||||||
if(dt!=null && expectedReturnValues.isEmpty())
|
|
||||||
checkResult.add(SyntaxError("invalid number of return values", returnStmt.position))
|
|
||||||
} else
|
|
||||||
checkResult.add(SyntaxError("invalid number of return values", returnStmt.position))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (rv in expectedReturnValues.withIndex().zip(returnStmt.values)) {
|
if(expectedReturnValues.isEmpty() && returnStmt.value!=null) {
|
||||||
val valueDt=rv.second.inferType(program)
|
checkResult.add(SyntaxError("invalid number of return values", returnStmt.position))
|
||||||
if(rv.first.value!=valueDt)
|
}
|
||||||
checkResult.add(ExpressionError("type $valueDt of return value #${rv.first.index + 1} doesn't match subroutine return type ${rv.first.value}", rv.second.position))
|
if(expectedReturnValues.isNotEmpty() && returnStmt.value==null) {
|
||||||
|
checkResult.add(SyntaxError("invalid number of return values", returnStmt.position))
|
||||||
|
}
|
||||||
|
if(expectedReturnValues.size==1 && returnStmt.value!=null) {
|
||||||
|
val valueDt = returnStmt.value!!.inferType(program)
|
||||||
|
if(expectedReturnValues[0]!=valueDt)
|
||||||
|
checkResult.add(ExpressionError("type $valueDt of return value doesn't match subroutine's return type", returnStmt.value!!.position))
|
||||||
}
|
}
|
||||||
return super.visit(returnStmt)
|
return super.visit(returnStmt)
|
||||||
}
|
}
|
||||||
|
@ -168,25 +168,23 @@ internal class AstIdentifiersChecker(private val namespace: INameScope) : IAstMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(returnStmt: Return): IStatement {
|
override fun visit(returnStmt: Return): IStatement {
|
||||||
if(returnStmt.values.isNotEmpty()) {
|
if(returnStmt.value!=null) {
|
||||||
// possibly adjust any literal values returned, into the desired returning data type
|
// possibly adjust any literal values returned, into the desired returning data type
|
||||||
val subroutine = returnStmt.definingSubroutine()!!
|
val subroutine = returnStmt.definingSubroutine()!!
|
||||||
if(subroutine.returntypes.size!=returnStmt.values.size)
|
if(subroutine.returntypes.size!=1)
|
||||||
return returnStmt // mismatch in number of return values, error will be printed later.
|
return returnStmt // mismatch in number of return values, error will be printed later.
|
||||||
val newValues = mutableListOf<IExpression>()
|
val newValue: IExpression
|
||||||
for(returnvalue in returnStmt.values.zip(subroutine.returntypes)) {
|
val lval = returnStmt.value as? LiteralValue
|
||||||
val lval = returnvalue.first as? LiteralValue
|
if(lval!=null) {
|
||||||
if(lval!=null) {
|
val adjusted = lval.cast(subroutine.returntypes.single())
|
||||||
val adjusted = lval.cast(returnvalue.second)
|
if(adjusted!=null && adjusted !== lval)
|
||||||
if(adjusted!=null && adjusted !== lval)
|
newValue = adjusted
|
||||||
newValues.add(adjusted)
|
|
||||||
else
|
|
||||||
newValues.add(lval)
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
newValues.add(returnvalue.first)
|
newValue = lval
|
||||||
}
|
} else
|
||||||
returnStmt.values = newValues
|
newValue = returnStmt.value!!
|
||||||
|
|
||||||
|
returnStmt.value = newValue
|
||||||
}
|
}
|
||||||
return super.visit(returnStmt)
|
return super.visit(returnStmt)
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ interface IAstModifyingVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun visit(returnStmt: Return): IStatement {
|
fun visit(returnStmt: Return): IStatement {
|
||||||
returnStmt.values = returnStmt.values.map { it.accept(this) }
|
returnStmt.value = returnStmt.value?.accept(this)
|
||||||
return returnStmt
|
return returnStmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ interface IAstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun visit(returnStmt: Return) {
|
fun visit(returnStmt: Return) {
|
||||||
returnStmt.values.forEach { it.accept(this) }
|
returnStmt.value?.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
|
fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
|
||||||
|
@ -89,7 +89,7 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
|||||||
&& stmtBeforeFirstSub !is Jump
|
&& stmtBeforeFirstSub !is Jump
|
||||||
&& stmtBeforeFirstSub !is Subroutine
|
&& stmtBeforeFirstSub !is Subroutine
|
||||||
&& stmtBeforeFirstSub !is BuiltinFunctionStatementPlaceholder) {
|
&& stmtBeforeFirstSub !is BuiltinFunctionStatementPlaceholder) {
|
||||||
val ret = Return(emptyList(), stmtBeforeFirstSub.position)
|
val ret = Return(null, stmtBeforeFirstSub.position)
|
||||||
ret.linkParents(block)
|
ret.linkParents(block)
|
||||||
block.statements.add(block.statements.size - numSubroutinesAtEnd, ret)
|
block.statements.add(block.statements.size - numSubroutinesAtEnd, ret)
|
||||||
}
|
}
|
||||||
@ -137,7 +137,7 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
|||||||
// and if an assembly block doesn't contain a rts/rti
|
// and if an assembly block doesn't contain a rts/rti
|
||||||
if(subroutine.asmAddress==null && subroutine.amountOfRtsInAsm()==0) {
|
if(subroutine.asmAddress==null && subroutine.amountOfRtsInAsm()==0) {
|
||||||
if (subroutine.statements.lastOrNull {it !is VarDecl } !is Return) {
|
if (subroutine.statements.lastOrNull {it !is VarDecl } !is Return) {
|
||||||
val returnStmt = Return(emptyList(), subroutine.position)
|
val returnStmt = Return(null, subroutine.position)
|
||||||
returnStmt.linkParents(subroutine)
|
returnStmt.linkParents(subroutine)
|
||||||
subroutine.statements.add(returnStmt)
|
subroutine.statements.add(returnStmt)
|
||||||
}
|
}
|
||||||
|
@ -84,24 +84,24 @@ data class Label(val name: String, override val position: Position) : IStatement
|
|||||||
val scopedname: String by lazy { makeScopedName(name) }
|
val scopedname: String by lazy { makeScopedName(name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open class Return(var values: List<IExpression>, override val position: Position) : IStatement {
|
open class Return(var value: IExpression?, override val position: Position) : IStatement {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
override val expensiveToInline = values.any { it !is LiteralValue }
|
override val expensiveToInline = value!=null && value !is LiteralValue
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
override fun linkParents(parent: Node) {
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
values.forEach {it.linkParents(this)}
|
value?.linkParents(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Return(values: $values, pos=$position)"
|
return "Return($value, pos=$position)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnFromIrq(override val position: Position) : Return(emptyList(), position) {
|
class ReturnFromIrq(override val position: Position) : Return(null, position) {
|
||||||
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
|
|
||||||
|
@ -327,11 +327,7 @@ class AstToSourceCode(val output: (text: String) -> Unit): IAstVisitor {
|
|||||||
|
|
||||||
override fun visit(returnStmt: Return) {
|
override fun visit(returnStmt: Return) {
|
||||||
output("return ")
|
output("return ")
|
||||||
for(v in returnStmt.values) {
|
returnStmt.value?.accept(this)
|
||||||
v.accept(this)
|
|
||||||
if(v!==returnStmt.values.last())
|
|
||||||
output(", ")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
|
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
|
||||||
|
@ -1517,9 +1517,8 @@ internal class Compiler(private val program: Program) {
|
|||||||
|
|
||||||
private fun translate(stmt: Return) {
|
private fun translate(stmt: Return) {
|
||||||
// put the return values on the stack, in reversed order. The caller will accept them.
|
// put the return values on the stack, in reversed order. The caller will accept them.
|
||||||
for(value in stmt.values.reversed()) {
|
if(stmt.value!=null)
|
||||||
translate(value)
|
translate(stmt.value!!)
|
||||||
}
|
|
||||||
prog.line(stmt.position)
|
prog.line(stmt.position)
|
||||||
prog.instr(Opcode.RETURN)
|
prog.instr(Opcode.RETURN)
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ fun compileProgram(filepath: Path,
|
|||||||
programAst.checkValid(compilerOptions) // check if final tree is valid
|
programAst.checkValid(compilerOptions) // check if final tree is valid
|
||||||
programAst.checkRecursion() // check if there are recursive subroutine calls
|
programAst.checkRecursion() // check if there are recursive subroutine calls
|
||||||
|
|
||||||
printAst(programAst)
|
// printAst(programAst)
|
||||||
// namespace.debugPrint()
|
// namespace.debugPrint()
|
||||||
|
|
||||||
if(generateVmCode) {
|
if(generateVmCode) {
|
||||||
|
@ -79,7 +79,6 @@ internal class StatementOptimizer(private val program: Program, private val opti
|
|||||||
}
|
}
|
||||||
val returns = inlined.statements.withIndex().filter { iv -> iv.value is Return }.map { iv -> Pair(iv.index, iv.value as Return)}
|
val returns = inlined.statements.withIndex().filter { iv -> iv.value is Return }.map { iv -> Pair(iv.index, iv.value as Return)}
|
||||||
for(returnIdx in returns) {
|
for(returnIdx in returns) {
|
||||||
assert(returnIdx.second.values.isEmpty())
|
|
||||||
val jump = Jump(null, IdentifierReference(listOf(endlabel.name), returnIdx.second.position), null, returnIdx.second.position)
|
val jump = Jump(null, IdentifierReference(listOf(endlabel.name), returnIdx.second.position), null, returnIdx.second.position)
|
||||||
inlined.statements[returnIdx.first] = jump
|
inlined.statements[returnIdx.first] = jump
|
||||||
endLabelUsed = true
|
endLabelUsed = true
|
||||||
@ -299,8 +298,8 @@ internal class StatementOptimizer(private val program: Program, private val opti
|
|||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
return FunctionCall(first.identifier, functionCall.arglist, functionCall.position)
|
return FunctionCall(first.identifier, functionCall.arglist, functionCall.position)
|
||||||
}
|
}
|
||||||
if(first is Return && first.values.size==1) {
|
if(first is Return && first.value!=null) {
|
||||||
val constval = first.values[0].constValue(program)
|
val constval = first.value?.constValue(program)
|
||||||
if(constval!=null)
|
if(constval!=null)
|
||||||
return constval
|
return constval
|
||||||
}
|
}
|
||||||
|
@ -261,11 +261,11 @@ class AstVm(val program: Program) {
|
|||||||
|
|
||||||
class LoopControlBreak : Exception()
|
class LoopControlBreak : Exception()
|
||||||
class LoopControlContinue : Exception()
|
class LoopControlContinue : Exception()
|
||||||
class LoopControlReturn(val returnvalues: List<RuntimeValue>) : Exception()
|
class LoopControlReturn(val returnvalue: RuntimeValue?) : Exception()
|
||||||
class LoopControlJump(val identifier: IdentifierReference?, val address: Int?, val generatedLabel: String?) : Exception()
|
class LoopControlJump(val identifier: IdentifierReference?, val address: Int?, val generatedLabel: String?) : Exception()
|
||||||
|
|
||||||
|
|
||||||
internal fun executeSubroutine(sub: Subroutine, arguments: List<RuntimeValue>, startlabel: Label?=null): List<RuntimeValue> {
|
internal fun executeSubroutine(sub: Subroutine, arguments: List<RuntimeValue>, startlabel: Label?=null): RuntimeValue? {
|
||||||
if(sub.isAsmSubroutine) {
|
if(sub.isAsmSubroutine) {
|
||||||
return performSyscall(sub, arguments)
|
return performSyscall(sub, arguments)
|
||||||
}
|
}
|
||||||
@ -300,7 +300,7 @@ class AstVm(val program: Program) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (r: LoopControlReturn) {
|
} catch (r: LoopControlReturn) {
|
||||||
return r.returnvalues
|
return r.returnvalue
|
||||||
}
|
}
|
||||||
throw VmTerminationException("instruction pointer overflow, is a return missing? $sub")
|
throw VmTerminationException("instruction pointer overflow, is a return missing? $sub")
|
||||||
}
|
}
|
||||||
@ -355,7 +355,14 @@ class AstVm(val program: Program) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Return -> throw LoopControlReturn(stmt.values.map { evaluate(it, evalCtx) })
|
is Return -> {
|
||||||
|
val value =
|
||||||
|
if(stmt.value==null)
|
||||||
|
null
|
||||||
|
else
|
||||||
|
evaluate(stmt.value!!, evalCtx)
|
||||||
|
throw LoopControlReturn(value)
|
||||||
|
}
|
||||||
is Continue -> throw LoopControlContinue()
|
is Continue -> throw LoopControlContinue()
|
||||||
is Break -> throw LoopControlBreak()
|
is Break -> throw LoopControlBreak()
|
||||||
is Assignment -> {
|
is Assignment -> {
|
||||||
@ -430,7 +437,7 @@ class AstVm(val program: Program) {
|
|||||||
if (sub is Subroutine) {
|
if (sub is Subroutine) {
|
||||||
val args = sub.parameters.map { runtimeVariables.get(sub, it.name) }
|
val args = sub.parameters.map { runtimeVariables.get(sub, it.name) }
|
||||||
performSyscall(sub, args)
|
performSyscall(sub, args)
|
||||||
throw LoopControlReturn(emptyList())
|
throw LoopControlReturn(null)
|
||||||
}
|
}
|
||||||
throw VmExecutionException("can't execute inline assembly in $sub")
|
throw VmExecutionException("can't execute inline assembly in $sub")
|
||||||
}
|
}
|
||||||
@ -635,8 +642,8 @@ class AstVm(val program: Program) {
|
|||||||
|
|
||||||
private fun evaluate(args: List<IExpression>) = args.map { evaluate(it, evalCtx) }
|
private fun evaluate(args: List<IExpression>) = args.map { evaluate(it, evalCtx) }
|
||||||
|
|
||||||
private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>): List<RuntimeValue> {
|
private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>): RuntimeValue? {
|
||||||
val result = mutableListOf<RuntimeValue>()
|
var result: RuntimeValue? = null
|
||||||
when (sub.scopedname) {
|
when (sub.scopedname) {
|
||||||
"c64scr.print" -> {
|
"c64scr.print" -> {
|
||||||
// if the argument is an UWORD, consider it to be the "address" of the string (=heapId)
|
// if the argument is an UWORD, consider it to be the "address" of the string (=heapId)
|
||||||
@ -720,7 +727,7 @@ class AstVm(val program: Program) {
|
|||||||
val origStr = program.heap.get(heapId).str!!
|
val origStr = program.heap.get(heapId).str!!
|
||||||
val paddedStr=inputStr.padEnd(origStr.length+1, '\u0000').substring(0, origStr.length)
|
val paddedStr=inputStr.padEnd(origStr.length+1, '\u0000').substring(0, origStr.length)
|
||||||
program.heap.update(heapId, paddedStr)
|
program.heap.update(heapId, paddedStr)
|
||||||
result.add(RuntimeValue(DataType.UBYTE, paddedStr.indexOf('\u0000')))
|
result = RuntimeValue(DataType.UBYTE, paddedStr.indexOf('\u0000'))
|
||||||
}
|
}
|
||||||
"c64flt.print_f" -> {
|
"c64flt.print_f" -> {
|
||||||
dialog.canvas.printText(args[0].floatval.toString(), true)
|
dialog.canvas.printText(args[0].floatval.toString(), true)
|
||||||
@ -736,13 +743,13 @@ class AstVm(val program: Program) {
|
|||||||
Thread.sleep(10)
|
Thread.sleep(10)
|
||||||
}
|
}
|
||||||
val char=dialog.keyboardBuffer.pop()
|
val char=dialog.keyboardBuffer.pop()
|
||||||
result.add(RuntimeValue(DataType.UBYTE, char.toShort()))
|
result = RuntimeValue(DataType.UBYTE, char.toShort())
|
||||||
}
|
}
|
||||||
"c64utils.str2uword" -> {
|
"c64utils.str2uword" -> {
|
||||||
val heapId = args[0].wordval!!
|
val heapId = args[0].wordval!!
|
||||||
val argString = program.heap.get(heapId).str!!
|
val argString = program.heap.get(heapId).str!!
|
||||||
val numericpart = argString.takeWhile { it.isDigit() }
|
val numericpart = argString.takeWhile { it.isDigit() }
|
||||||
result.add(RuntimeValue(DataType.UWORD, numericpart.toInt() and 65535))
|
result = RuntimeValue(DataType.UWORD, numericpart.toInt() and 65535)
|
||||||
}
|
}
|
||||||
else -> TODO("syscall ${sub.scopedname} $sub")
|
else -> TODO("syscall ${sub.scopedname} $sub")
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import kotlin.math.abs
|
|||||||
class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags,
|
class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags,
|
||||||
val runtimeVars: RuntimeVariables,
|
val runtimeVars: RuntimeVariables,
|
||||||
val performBuiltinFunction: (String, List<RuntimeValue>, StatusFlags) -> RuntimeValue?,
|
val performBuiltinFunction: (String, List<RuntimeValue>, StatusFlags) -> RuntimeValue?,
|
||||||
val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>, startlabel: Label?) -> List<RuntimeValue>)
|
val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>, startlabel: Label?) -> RuntimeValue?)
|
||||||
|
|
||||||
fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
|
fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
|
||||||
val constval = expr.constValue(ctx.program)
|
val constval = expr.constValue(ctx.program)
|
||||||
@ -117,10 +117,9 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
|
|||||||
val args = expr.arglist.map { evaluate(it, ctx) }
|
val args = expr.arglist.map { evaluate(it, ctx) }
|
||||||
return when(sub) {
|
return when(sub) {
|
||||||
is Subroutine -> {
|
is Subroutine -> {
|
||||||
val results = ctx.executeSubroutine(sub, args, null)
|
val result = ctx.executeSubroutine(sub, args, null)
|
||||||
if(results.size!=1)
|
?: throw VmExecutionException("expected a result from functioncall $expr")
|
||||||
throw VmExecutionException("expected 1 result from functioncall $expr")
|
result
|
||||||
results[0]
|
|
||||||
}
|
}
|
||||||
is BuiltinFunctionStatementPlaceholder -> {
|
is BuiltinFunctionStatementPlaceholder -> {
|
||||||
val result = ctx.performBuiltinFunction(sub.name, args, ctx.statusflags)
|
val result = ctx.performBuiltinFunction(sub.name, args, ctx.statusflags)
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
ubyte guess = lsb(c64utils.str2uword(input))
|
ubyte guess = lsb(c64utils.str2uword(input))
|
||||||
|
|
||||||
if guess==secretnumber {
|
if guess==secretnumber {
|
||||||
return ending(true)
|
ending(true)
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
c64scr.print("\n\nThat is too ")
|
c64scr.print("\n\nThat is too ")
|
||||||
if guess<secretnumber
|
if guess<secretnumber
|
||||||
@ -42,7 +43,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ending(false) ; @todo error
|
ending(false)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
sub ending(ubyte success) {
|
sub ending(ubyte success) {
|
||||||
|
@ -4,16 +4,18 @@
|
|||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
str naam = " "
|
|
||||||
|
|
||||||
while true {
|
foo(42)
|
||||||
c64scr.print("naam: ")
|
return
|
||||||
ubyte length = c64scr.input_chars(naam)
|
}
|
||||||
c64scr.print_ub(length)
|
|
||||||
c64.CHROUT(':')
|
sub foo(ubyte arg) -> ubyte {
|
||||||
c64scr.print(naam)
|
bar(arg)
|
||||||
c64.CHROUT('\n')
|
return 33
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub bar(ubyte a2) {
|
||||||
|
;nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ expression_list :
|
|||||||
expression (',' EOL? expression)* // you can split the expression list over several lines
|
expression (',' EOL? expression)* // you can split the expression list over several lines
|
||||||
;
|
;
|
||||||
|
|
||||||
returnstmt : 'return' expression_list? ;
|
returnstmt : 'return' expression? ;
|
||||||
|
|
||||||
breakstmt : 'break';
|
breakstmt : 'break';
|
||||||
|
|
||||||
|
@ -2265,8 +2265,8 @@ public class prog8Parser extends Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class ReturnstmtContext extends ParserRuleContext {
|
public static class ReturnstmtContext extends ParserRuleContext {
|
||||||
public Expression_listContext expression_list() {
|
public ExpressionContext expression() {
|
||||||
return getRuleContext(Expression_listContext.class,0);
|
return getRuleContext(ExpressionContext.class,0);
|
||||||
}
|
}
|
||||||
public ReturnstmtContext(ParserRuleContext parent, int invokingState) {
|
public ReturnstmtContext(ParserRuleContext parent, int invokingState) {
|
||||||
super(parent, invokingState);
|
super(parent, invokingState);
|
||||||
@ -2288,7 +2288,7 @@ public class prog8Parser extends Parser {
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
setState(426);
|
setState(426);
|
||||||
expression_list();
|
expression(0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5147,7 +5147,7 @@ public class prog8Parser extends Parser {
|
|||||||
"\3\2\2\2\u01a3\u01a4\3\2\2\2\u01a4\u01a5\3\2\2\2\u01a5\u01a7\5&\24\2\u01a6"+
|
"\3\2\2\2\u01a3\u01a4\3\2\2\2\u01a4\u01a5\3\2\2\2\u01a5\u01a7\5&\24\2\u01a6"+
|
||||||
"\u01a1\3\2\2\2\u01a7\u01aa\3\2\2\2\u01a8\u01a6\3\2\2\2\u01a8\u01a9\3\2"+
|
"\u01a1\3\2\2\2\u01a7\u01aa\3\2\2\2\u01a8\u01a6\3\2\2\2\u01a8\u01a9\3\2"+
|
||||||
"\2\2\u01a9\65\3\2\2\2\u01aa\u01a8\3\2\2\2\u01ab\u01ad\7C\2\2\u01ac\u01ae"+
|
"\2\2\u01a9\65\3\2\2\2\u01aa\u01a8\3\2\2\2\u01ab\u01ad\7C\2\2\u01ac\u01ae"+
|
||||||
"\5\64\33\2\u01ad\u01ac\3\2\2\2\u01ad\u01ae\3\2\2\2\u01ae\67\3\2\2\2\u01af"+
|
"\5&\24\2\u01ad\u01ac\3\2\2\2\u01ad\u01ae\3\2\2\2\u01ae\67\3\2\2\2\u01af"+
|
||||||
"\u01b0\7D\2\2\u01b09\3\2\2\2\u01b1\u01b2\7E\2\2\u01b2;\3\2\2\2\u01b3\u01b4"+
|
"\u01b0\7D\2\2\u01b09\3\2\2\2\u01b1\u01b2\7E\2\2\u01b2;\3\2\2\2\u01b3\u01b4"+
|
||||||
"\7t\2\2\u01b4=\3\2\2\2\u01b5\u01ba\7t\2\2\u01b6\u01b7\7F\2\2\u01b7\u01b9"+
|
"\7t\2\2\u01b4=\3\2\2\2\u01b5\u01ba\7t\2\2\u01b6\u01b7\7F\2\2\u01b7\u01b9"+
|
||||||
"\7t\2\2\u01b8\u01b6\3\2\2\2\u01b9\u01bc\3\2\2\2\u01ba\u01b8\3\2\2\2\u01ba"+
|
"\7t\2\2\u01b8\u01b6\3\2\2\2\u01b9\u01bc\3\2\2\2\u01ba\u01b8\3\2\2\2\u01ba"+
|
||||||
|
Loading…
x
Reference in New Issue
Block a user