introduced repeat loop. repeat-until changed to do-util.

forever loop is gone (use repeat without iteration count).
struct literal is now same as array literal [...] to avoid parsing ambiguity with scope blocks.
This commit is contained in:
Irmen de Jong 2020-07-25 16:25:02 +02:00
parent b0e8738ab8
commit c38508c262
35 changed files with 274 additions and 226 deletions

View File

@ -324,16 +324,18 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
whileLoop.body.accept(this) whileLoop.body.accept(this)
} }
override fun visit(foreverLoop: ForeverLoop) {
output("forever ")
foreverLoop.body.accept(this)
}
override fun visit(repeatLoop: RepeatLoop) { override fun visit(repeatLoop: RepeatLoop) {
output("repeat ") output("repeat ")
repeatLoop.iterations?.accept(this)
output(" ")
repeatLoop.body.accept(this) repeatLoop.body.accept(this)
}
override fun visit(untilLoop: UntilLoop) {
output("do ")
untilLoop.body.accept(this)
output(" until ") output(" until ")
repeatLoop.untilCondition.accept(this) untilLoop.untilCondition.accept(this)
} }
override fun visit(returnStmt: Return) { override fun visit(returnStmt: Return) {
@ -425,10 +427,6 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
outputln("") outputln("")
} }
override fun visit(structLv: StructLiteralValue) {
outputListMembers(structLv.values.asSequence(), '{', '}')
}
override fun visit(nopStatement: NopStatement) { override fun visit(nopStatement: NopStatement) {
output("; NOP @ ${nopStatement.position} $nopStatement") output("; NOP @ ${nopStatement.position} $nopStatement")
} }

View File

@ -57,7 +57,7 @@ interface INameScope {
when(stmt) { when(stmt) {
// NOTE: if other nodes are introduced that are a scope, or contain subscopes, they must be added here! // NOTE: if other nodes are introduced that are a scope, or contain subscopes, they must be added here!
is ForLoop -> if(stmt.body.name==name) return stmt.body is ForLoop -> if(stmt.body.name==name) return stmt.body
is RepeatLoop -> if(stmt.body.name==name) return stmt.body is UntilLoop -> if(stmt.body.name==name) return stmt.body
is WhileLoop -> if(stmt.body.name==name) return stmt.body is WhileLoop -> if(stmt.body.name==name) return stmt.body
is BranchStatement -> { is BranchStatement -> {
if(stmt.truepart.name==name) return stmt.truepart if(stmt.truepart.name==name) return stmt.truepart
@ -175,8 +175,8 @@ interface INameScope {
find(it.truepart) find(it.truepart)
find(it.elsepart) find(it.elsepart)
} }
is UntilLoop -> find(it.body)
is RepeatLoop -> find(it.body) is RepeatLoop -> find(it.body)
is ForeverLoop -> find(it.body)
is WhileLoop -> find(it.body) is WhileLoop -> find(it.body)
is WhenStatement -> it.choices.forEach { choice->find(choice.statements) } is WhenStatement -> it.choices.forEach { choice->find(choice.statements) }
else -> { /* do nothing */ } else -> { /* do nothing */ }

View File

@ -205,14 +205,14 @@ private fun prog8Parser.StatementContext.toAst() : Statement {
val forloop = forloop()?.toAst() val forloop = forloop()?.toAst()
if(forloop!=null) return forloop if(forloop!=null) return forloop
val repeatloop = repeatloop()?.toAst() val untilloop = untilloop()?.toAst()
if(repeatloop!=null) return repeatloop if(untilloop!=null) return untilloop
val whileloop = whileloop()?.toAst() val whileloop = whileloop()?.toAst()
if(whileloop!=null) return whileloop if(whileloop!=null) return whileloop
val foreverloop = foreverloop()?.toAst() val repeatloop = repeatloop()?.toAst()
if(foreverloop!=null) return foreverloop if(repeatloop!=null) return repeatloop
val breakstmt = breakstmt()?.toAst() val breakstmt = breakstmt()?.toAst()
if(breakstmt!=null) return breakstmt if(breakstmt!=null) return breakstmt
@ -487,10 +487,6 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression {
// the ConstantFold takes care of that and converts the type if needed. // the ConstantFold takes care of that and converts the type if needed.
ArrayLiteralValue(InferredTypes.InferredType.unknown(), array, position = litval.toPosition()) ArrayLiteralValue(InferredTypes.InferredType.unknown(), array, position = litval.toPosition())
} }
litval.structliteral()!=null -> {
val values = litval.structliteral().expression().map { it.toAst() }
StructLiteralValue(values, litval.toPosition())
}
else -> throw FatalAstException("invalid parsed literal") else -> throw FatalAstException("invalid parsed literal")
} }
} }
@ -609,19 +605,20 @@ private fun prog8Parser.WhileloopContext.toAst(): WhileLoop {
return WhileLoop(condition, scope, toPosition()) return WhileLoop(condition, scope, toPosition())
} }
private fun prog8Parser.ForeverloopContext.toAst(): ForeverLoop { private fun prog8Parser.RepeatloopContext.toAst(): RepeatLoop {
val iterations = expression()?.toAst()
val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst()) val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst())
val scope = AnonymousScope(statements, statement_block()?.toPosition() val scope = AnonymousScope(statements, statement_block()?.toPosition()
?: statement().toPosition()) ?: statement().toPosition())
return ForeverLoop(scope, toPosition()) return RepeatLoop(iterations, scope, toPosition())
} }
private fun prog8Parser.RepeatloopContext.toAst(): RepeatLoop { private fun prog8Parser.UntilloopContext.toAst(): UntilLoop {
val untilCondition = expression().toAst() val untilCondition = expression().toAst()
val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst()) val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst())
val scope = AnonymousScope(statements, statement_block()?.toPosition() val scope = AnonymousScope(statements, statement_block()?.toPosition()
?: statement().toPosition()) ?: statement().toPosition())
return RepeatLoop(scope, untilCondition, toPosition()) return UntilLoop(scope, untilCondition, toPosition())
} }
private fun prog8Parser.WhenstmtContext.toAst(): WhenStatement { private fun prog8Parser.WhenstmtContext.toAst(): WhenStatement {

View File

@ -455,31 +455,6 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
} }
} }
class StructLiteralValue(var values: List<Expression>,
override val position: Position): Expression() {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent=parent
values.forEach { it.linkParents(this) }
}
override fun replaceChildNode(node: Node, replacement: Node) {
throw FatalAstException("can't replace here")
}
override fun constValue(program: Program): NumericLiteralValue? = null
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifiers(vararg name: String) = values.any { it.referencesIdentifiers(*name) }
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(DataType.STRUCT)
override fun toString(): String {
return "struct{ ${values.joinToString(", ")} }"
}
}
private var heapIdSequence = 0 // unique ids for strings and arrays "on the heap" private var heapIdSequence = 0 // unique ids for strings and arrays "on the heap"
class StringLiteralValue(val value: String, class StringLiteralValue(val value: String,

View File

@ -316,10 +316,10 @@ internal class AstChecker(private val program: Program,
visitStatements(subroutine.statements) visitStatements(subroutine.statements)
} }
override fun visit(repeatLoop: RepeatLoop) { override fun visit(untilLoop: UntilLoop) {
if(repeatLoop.untilCondition.inferType(program).typeOrElse(DataType.STRUCT) !in IntegerDatatypes) if(untilLoop.untilCondition.inferType(program).typeOrElse(DataType.STRUCT) !in IntegerDatatypes)
errors.err("condition value should be an integer type", repeatLoop.untilCondition.position) errors.err("condition value should be an integer type", untilLoop.untilCondition.position)
super.visit(repeatLoop) super.visit(untilLoop)
} }
override fun visit(whileLoop: WhileLoop) { override fun visit(whileLoop: WhileLoop) {
@ -348,9 +348,9 @@ internal class AstChecker(private val program: Program,
if(targetIdent!=null) { if(targetIdent!=null) {
val targetVar = targetIdent.targetVarDecl(program.namespace) val targetVar = targetIdent.targetVarDecl(program.namespace)
if(targetVar?.struct != null) { if(targetVar?.struct != null) {
val sourceStructLv = assignment.value as? StructLiteralValue val sourceStructLv = assignment.value as? ArrayLiteralValue
if (sourceStructLv != null) { if (sourceStructLv != null) {
if (sourceStructLv.values.size != targetVar.struct?.numberOfElements) if (sourceStructLv.value.size != targetVar.struct?.numberOfElements)
errors.err("number of elements doesn't match struct definition", sourceStructLv.position) errors.err("number of elements doesn't match struct definition", sourceStructLv.position)
} else { } else {
val sourceIdent = assignment.value as? IdentifierReference val sourceIdent = assignment.value as? IdentifierReference
@ -503,21 +503,14 @@ internal class AstChecker(private val program: Program,
checkValueTypeAndRangeString(decl.datatype, decl.value as StringLiteralValue) checkValueTypeAndRangeString(decl.datatype, decl.value as StringLiteralValue)
} }
is ArrayLiteralValue -> { is ArrayLiteralValue -> {
val arraySpec = decl.arraysize ?: ArrayIndex.forArray(decl.value as ArrayLiteralValue)
checkValueTypeAndRangeArray(decl.datatype, decl.struct, arraySpec, decl.value as ArrayLiteralValue)
}
is NumericLiteralValue -> {
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
}
is StructLiteralValue -> {
if(decl.datatype==DataType.STRUCT) { if(decl.datatype==DataType.STRUCT) {
val struct = decl.struct!! val struct = decl.struct!!
val structLv = decl.value as StructLiteralValue val structLv = decl.value as ArrayLiteralValue
if(struct.numberOfElements != structLv.values.size) { if(struct.numberOfElements != structLv.value.size) {
errors.err("struct value has incorrect number of elements", structLv.position) errors.err("struct value has incorrect number of elements", structLv.position)
return return
} }
for(value in structLv.values.zip(struct.statements)) { for(value in structLv.value.zip(struct.statements)) {
val memberdecl = value.second as VarDecl val memberdecl = value.second as VarDecl
val constValue = value.first.constValue(program) val constValue = value.first.constValue(program)
if(constValue==null) { if(constValue==null) {
@ -531,9 +524,13 @@ internal class AstChecker(private val program: Program,
} }
} }
} else { } else {
errors.err("struct literal is wrong type to initialize this variable", decl.value!!.position) val arraySpec = decl.arraysize ?: ArrayIndex.forArray(decl.value as ArrayLiteralValue)
checkValueTypeAndRangeArray(decl.datatype, decl.struct, arraySpec, decl.value as ArrayLiteralValue)
} }
} }
is NumericLiteralValue -> {
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
}
else -> { else -> {
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}") err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}")
super.visit(decl) super.visit(decl)
@ -570,8 +567,18 @@ internal class AstChecker(private val program: Program,
} }
val declValue = decl.value val declValue = decl.value
if(declValue!=null && decl.type==VarDeclType.VAR && !declValue.inferType(program).istype(decl.datatype)) if(declValue!=null && decl.type==VarDeclType.VAR) {
if(decl.datatype==DataType.STRUCT) {
val valueIdt = declValue.inferType(program)
if(valueIdt.isUnknown)
throw AstException("invalid value type")
val valueDt = valueIdt.typeOrElse(DataType.STRUCT)
if(valueDt !in ArrayDatatypes)
err("initialisation of struct should be with array value", declValue.position)
} else if (!declValue.inferType(program).istype(decl.datatype)) {
err("initialisation value has incompatible type (${declValue.inferType(program)}) for the variable (${decl.datatype})", declValue.position) err("initialisation value has incompatible type (${declValue.inferType(program)}) for the variable (${decl.datatype})", declValue.position)
}
}
super.visit(decl) super.visit(decl)
} }
@ -1278,8 +1285,8 @@ internal class AstChecker(private val program: Program,
DataType.STR -> sourceDatatype== DataType.STR DataType.STR -> sourceDatatype== DataType.STR
DataType.STRUCT -> { DataType.STRUCT -> {
if(sourceDatatype==DataType.STRUCT) { if(sourceDatatype==DataType.STRUCT) {
val structLv = sourceValue as StructLiteralValue val structLv = sourceValue as ArrayLiteralValue
val numValues = structLv.values.size val numValues = structLv.value.size
val targetstruct = target.identifier!!.targetVarDecl(program.namespace)!!.struct!! val targetstruct = target.identifier!!.targetVarDecl(program.namespace)!!.struct!!
return targetstruct.numberOfElements == numValues return targetstruct.numberOfElements == numValues
} }

View File

@ -57,8 +57,8 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
return super.visit(decl) return super.visit(decl)
} }
if (decl.value != null && decl.value !is StructLiteralValue) { if (decl.value != null && decl.value !is ArrayLiteralValue) {
errors.err("initializing requires struct literal value", decl.value?.position ?: decl.position) errors.err("initializing a struct requires array literal value", decl.value?.position ?: decl.position)
return super.visit(decl) return super.visit(decl)
} }
} }

View File

@ -94,7 +94,7 @@ abstract class AstWalker {
open fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList() open fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = emptyList() open fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = emptyList() open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(foreverLoop: ForeverLoop, parent: Node): Iterable<IAstModification> = emptyList() open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> = emptyList() open fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = emptyList() open fun before(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = emptyList() open fun before(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = emptyList()
@ -110,12 +110,11 @@ abstract class AstWalker {
open fun before(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = emptyList() open fun before(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(program: Program, parent: Node): Iterable<IAstModification> = emptyList() open fun before(program: Program, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(range: RangeExpr, parent: Node): Iterable<IAstModification> = emptyList() open fun before(range: RangeExpr, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = emptyList() open fun before(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(returnStmt: Return, parent: Node): Iterable<IAstModification> = emptyList() open fun before(returnStmt: Return, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = emptyList() open fun before(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = emptyList() open fun before(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = emptyList() open fun before(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(structLv: StructLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = emptyList() open fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = emptyList() open fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = emptyList()
open fun before(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = emptyList() open fun before(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = emptyList()
@ -137,7 +136,7 @@ abstract class AstWalker {
open fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList() open fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = emptyList() open fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = emptyList() open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(foreverLoop: ForeverLoop, parent: Node): Iterable<IAstModification> = emptyList() open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> = emptyList() open fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = emptyList() open fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = emptyList() open fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = emptyList()
@ -153,12 +152,11 @@ abstract class AstWalker {
open fun after(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = emptyList() open fun after(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(program: Program, parent: Node): Iterable<IAstModification> = emptyList() open fun after(program: Program, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(range: RangeExpr, parent: Node): Iterable<IAstModification> = emptyList() open fun after(range: RangeExpr, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = emptyList() open fun after(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> = emptyList() open fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = emptyList() open fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = emptyList() open fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = emptyList() open fun after(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(structLv: StructLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = emptyList() open fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = emptyList() open fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = emptyList()
open fun after(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = emptyList() open fun after(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = emptyList()
@ -336,19 +334,20 @@ abstract class AstWalker {
track(after(whileLoop, parent), whileLoop, parent) track(after(whileLoop, parent), whileLoop, parent)
} }
fun visit(foreverLoop: ForeverLoop, parent: Node) {
track(before(foreverLoop, parent), foreverLoop, parent)
foreverLoop.body.accept(this, foreverLoop)
track(after(foreverLoop, parent), foreverLoop, parent)
}
fun visit(repeatLoop: RepeatLoop, parent: Node) { fun visit(repeatLoop: RepeatLoop, parent: Node) {
track(before(repeatLoop, parent), repeatLoop, parent) track(before(repeatLoop, parent), repeatLoop, parent)
repeatLoop.untilCondition.accept(this, repeatLoop) repeatLoop.iterations?.accept(this, repeatLoop)
repeatLoop.body.accept(this, repeatLoop) repeatLoop.body.accept(this, repeatLoop)
track(after(repeatLoop, parent), repeatLoop, parent) track(after(repeatLoop, parent), repeatLoop, parent)
} }
fun visit(untilLoop: UntilLoop, parent: Node) {
track(before(untilLoop, parent), untilLoop, parent)
untilLoop.untilCondition.accept(this, untilLoop)
untilLoop.body.accept(this, untilLoop)
track(after(untilLoop, parent), untilLoop, parent)
}
fun visit(returnStmt: Return, parent: Node) { fun visit(returnStmt: Return, parent: Node) {
track(before(returnStmt, parent), returnStmt, parent) track(before(returnStmt, parent), returnStmt, parent)
returnStmt.value?.accept(this, returnStmt) returnStmt.value?.accept(this, returnStmt)
@ -434,11 +433,5 @@ abstract class AstWalker {
structDecl.statements.forEach { it.accept(this, structDecl) } structDecl.statements.forEach { it.accept(this, structDecl) }
track(after(structDecl, parent), structDecl, parent) track(after(structDecl, parent), structDecl, parent)
} }
fun visit(structLv: StructLiteralValue, parent: Node) {
track(before(structLv, parent), structLv, parent)
structLv.values.forEach { it.accept(this, structLv) }
track(after(structLv, parent), structLv, parent)
}
} }

View File

@ -112,13 +112,14 @@ interface IAstVisitor {
whileLoop.body.accept(this) whileLoop.body.accept(this)
} }
fun visit(foreverLoop: ForeverLoop) { fun visit(repeatLoop: RepeatLoop) {
foreverLoop.body.accept(this) repeatLoop.iterations?.accept(this)
repeatLoop.body.accept(this)
} }
fun visit(repeatLoop: RepeatLoop) { fun visit(untilLoop: UntilLoop) {
repeatLoop.untilCondition.accept(this) untilLoop.untilCondition.accept(this)
repeatLoop.body.accept(this) untilLoop.body.accept(this)
} }
fun visit(returnStmt: Return) { fun visit(returnStmt: Return) {
@ -178,8 +179,4 @@ interface IAstVisitor {
fun visit(structDecl: StructDecl) { fun visit(structDecl: StructDecl) {
structDecl.statements.forEach { it.accept(this) } structDecl.statements.forEach { it.accept(this) }
} }
fun visit(structLv: StructLiteralValue) {
structLv.values.forEach { it.accept(this) }
}
} }

View File

@ -106,8 +106,8 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
val valueType = assignment.value.inferType(program) val valueType = assignment.value.inferType(program)
val targetType = assignment.target.inferType(program, assignment) val targetType = assignment.target.inferType(program, assignment)
if(valueType.istype(DataType.STRUCT) && targetType.istype(DataType.STRUCT)) { if(valueType.istype(DataType.STRUCT) && targetType.istype(DataType.STRUCT)) {
val assignments = if (assignment.value is StructLiteralValue) { val assignments = if (assignment.value is ArrayLiteralValue) {
flattenStructAssignmentFromStructLiteral(assignment, program) // 'structvar = { ..... } ' flattenStructAssignmentFromStructLiteral(assignment, program) // 'structvar = [ ..... ] '
} else { } else {
flattenStructAssignmentFromIdentifier(assignment, program) // 'structvar1 = structvar2' flattenStructAssignmentFromIdentifier(assignment, program) // 'structvar1 = structvar2'
} }
@ -128,11 +128,11 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
val targetVar = identifier.targetVarDecl(program.namespace)!! val targetVar = identifier.targetVarDecl(program.namespace)!!
val struct = targetVar.struct!! val struct = targetVar.struct!!
val slv = structAssignment.value as? StructLiteralValue val slv = structAssignment.value as? ArrayLiteralValue
if(slv==null || slv.values.size != struct.numberOfElements) if(slv==null || slv.value.size != struct.numberOfElements)
throw FatalAstException("element count mismatch") throw FatalAstException("element count mismatch")
return struct.statements.zip(slv.values).map { (targetDecl, sourceValue) -> return struct.statements.zip(slv.value).map { (targetDecl, sourceValue) ->
targetDecl as VarDecl targetDecl as VarDecl
val mangled = mangledStructMemberName(identifierName, targetDecl.name) val mangled = mangledStructMemberName(identifierName, targetDecl.name)
val idref = IdentifierReference(listOf(mangled), structAssignment.position) val idref = IdentifierReference(listOf(mangled), structAssignment.position)
@ -174,7 +174,7 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
assign assign
} }
} }
is StructLiteralValue -> { is ArrayLiteralValue -> {
throw IllegalArgumentException("not going to flatten a structLv assignment here") throw IllegalArgumentException("not going to flatten a structLv assignment here")
} }
else -> throw FatalAstException("strange struct value") else -> throw FatalAstException("strange struct value")

View File

@ -179,51 +179,6 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
return noModifications return noModifications
} }
override fun after(structLv: StructLiteralValue, parent: Node): Iterable<IAstModification> {
// assignment of a struct literal value, some member values may need proper typecast
fun addTypecastsIfNeeded(struct: StructDecl): Iterable<IAstModification> {
val newValues = struct.statements.zip(structLv.values).map { (structMemberDecl, memberValue) ->
val memberDt = (structMemberDecl as VarDecl).datatype
val valueDt = memberValue.inferType(program)
if (valueDt.typeOrElse(memberDt) != memberDt)
TypecastExpression(memberValue, memberDt, true, memberValue.position)
else
memberValue
}
class StructLvValueReplacer(val targetStructLv: StructLiteralValue, val typecastValues: List<Expression>) : IAstModification {
override fun perform() {
targetStructLv.values = typecastValues
typecastValues.forEach { it.linkParents(targetStructLv) }
}
}
return if(structLv.values.zip(newValues).any { (v1, v2) -> v1 !== v2})
listOf(StructLvValueReplacer(structLv, newValues))
else
emptyList()
}
val decl = structLv.parent as? VarDecl
if(decl != null) {
val struct = decl.struct
if(struct != null)
return addTypecastsIfNeeded(struct)
} else {
val assign = structLv.parent as? Assignment
if (assign != null) {
val decl2 = assign.target.identifier?.targetVarDecl(program.namespace)
if(decl2 != null) {
val struct = decl2.struct
if(struct != null)
return addTypecastsIfNeeded(struct)
}
}
}
return noModifications
}
override fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> { override fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> {
// add a typecast to the return type if it doesn't match the subroutine's signature // add a typecast to the return type if it doesn't match the subroutine's signature
val returnValue = returnStmt.value val returnValue = returnStmt.value

View File

@ -270,7 +270,7 @@ open class VarDecl(val type: VarDeclType,
fun flattenStructMembers(): MutableList<Statement> { fun flattenStructMembers(): MutableList<Statement> {
val result = struct!!.statements.withIndex().map { val result = struct!!.statements.withIndex().map {
val member = it.value as VarDecl val member = it.value as VarDecl
val initvalue = if(value!=null) (value as StructLiteralValue).values[it.index] else null val initvalue = if(value!=null) (value as ArrayLiteralValue).value[it.index] else null
VarDecl( VarDecl(
VarDeclType.VAR, VarDeclType.VAR,
member.datatype, member.datatype,
@ -780,17 +780,21 @@ class WhileLoop(var condition: Expression,
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
} }
class ForeverLoop(var body: AnonymousScope, override val position: Position) : Statement() { class RepeatLoop(var iterations: Expression?, var body: AnonymousScope, override val position: Position) : Statement() {
override lateinit var parent: Node override lateinit var parent: Node
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {
this.parent = parent this.parent = parent
iterations?.linkParents(this)
body.linkParents(this) body.linkParents(this)
} }
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is AnonymousScope && node===body) when {
body = replacement node===iterations -> iterations = replacement as Expression
node===body -> body = replacement as AnonymousScope
else -> throw FatalAstException("invalid replace")
}
replacement.parent = this replacement.parent = this
} }
@ -798,7 +802,7 @@ class ForeverLoop(var body: AnonymousScope, override val position: Position) : S
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
} }
class RepeatLoop(var body: AnonymousScope, class UntilLoop(var body: AnonymousScope,
var untilCondition: Expression, var untilCondition: Expression,
override val position: Position) : Statement() { override val position: Position) : Statement() {
override lateinit var parent: Node override lateinit var parent: Node

View File

@ -641,8 +641,8 @@ internal class AsmGen(private val program: Program,
is Continue -> out(" jmp ${loopContinueLabels.peek()}") is Continue -> out(" jmp ${loopContinueLabels.peek()}")
is Break -> out(" jmp ${loopEndLabels.peek()}") is Break -> out(" jmp ${loopEndLabels.peek()}")
is WhileLoop -> translate(stmt) is WhileLoop -> translate(stmt)
is ForeverLoop -> translate(stmt)
is RepeatLoop -> translate(stmt) is RepeatLoop -> translate(stmt)
is UntilLoop -> translate(stmt)
is WhenStatement -> translate(stmt) is WhenStatement -> translate(stmt)
is BuiltinFunctionStatementPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore?") is BuiltinFunctionStatementPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore?")
is AnonymousScope -> translate(stmt) is AnonymousScope -> translate(stmt)
@ -673,15 +673,72 @@ internal class AsmGen(private val program: Program,
} }
} }
private fun translate(stmt: ForeverLoop) { private fun translate(stmt: RepeatLoop) {
val foreverLabel = makeLabel("forever") val repeatLabel = makeLabel("repeat")
val endLabel = makeLabel("foreverend") val endLabel = makeLabel("repeatend")
val counterLabel = makeLabel("repeatcounter")
loopEndLabels.push(endLabel) loopEndLabels.push(endLabel)
loopContinueLabels.push(foreverLabel) loopContinueLabels.push(repeatLabel)
out(foreverLabel)
when (stmt.iterations) {
null -> {
// endless loop
out(repeatLabel)
translate(stmt.body) translate(stmt.body)
out(" jmp $foreverLabel") out(" jmp $repeatLabel")
out(endLabel) out(endLabel)
}
is NumericLiteralValue -> {
val iterations = (stmt.iterations as NumericLiteralValue).number.toInt()
if(iterations<0 || iterations > 65536)
throw AssemblyError("invalid number of iterations")
when {
iterations == 0 -> {}
iterations <= 255 -> {
out("""
lda #${iterations}
sta $counterLabel
$repeatLabel lda $counterLabel
beq $endLabel
dec $counterLabel
""")
translate(stmt.body)
out("""
jmp $repeatLabel
$counterLabel .byte 0
$endLabel""")
}
else -> {
out("""
lda #<${iterations}
sta $counterLabel
lda #>${iterations}
sta $counterLabel+1
$repeatLabel lda $counterLabel
bne +
lda $counterLabel+1
beq $endLabel
+ lda $counterLabel
bne +
dec $counterLabel+1
+ dec $counterLabel
""")
translate(stmt.body)
out("""
jmp $repeatLabel
$counterLabel .word 0
$endLabel""")
}
}
}
is IdentifierReference -> {
TODO("iterations ${stmt.iterations}")
}
else -> {
TODO("repeat loop with iterations ${stmt.iterations}")
}
}
loopEndLabels.pop() loopEndLabels.pop()
loopContinueLabels.pop() loopContinueLabels.pop()
} }
@ -714,7 +771,7 @@ internal class AsmGen(private val program: Program,
loopContinueLabels.pop() loopContinueLabels.pop()
} }
private fun translate(stmt: RepeatLoop) { private fun translate(stmt: UntilLoop) {
val repeatLabel = makeLabel("repeat") val repeatLabel = makeLabel("repeat")
val endLabel = makeLabel("repeatend") val endLabel = makeLabel("repeatend")
loopEndLabels.push(endLabel) loopEndLabels.push(endLabel)

View File

@ -832,7 +832,6 @@ internal class AssignmentAsmGen(private val program: Program, private val errors
assignFromEvalResult(assign.target) assignFromEvalResult(assign.target)
} }
is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array assignment $assign") is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array assignment $assign")
is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened ${assign.value.position}")
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values ${assign.value.position}") is RangeExpr -> throw AssemblyError("range expression should have been changed into array values ${assign.value.position}")
} }
} }

View File

@ -28,7 +28,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
is IdentifierReference -> translateExpression(expression) is IdentifierReference -> translateExpression(expression)
is FunctionCall -> translateExpression(expression) is FunctionCall -> translateExpression(expression)
is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable") is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable")
is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened")
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values") is RangeExpr -> throw AssemblyError("range expression should have been changed into array values")
} }
} }

View File

@ -41,7 +41,6 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
when { when {
stmt.args.all {it is AddressOf || stmt.args.all {it is AddressOf ||
it is NumericLiteralValue || it is NumericLiteralValue ||
it is StructLiteralValue ||
it is StringLiteralValue || it is StringLiteralValue ||
it is ArrayLiteralValue || it is ArrayLiteralValue ||
it is IdentifierReference} -> { it is IdentifierReference} -> {

View File

@ -251,18 +251,18 @@ internal class StatementOptimizer(private val program: Program,
return noModifications return noModifications
} }
override fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> { override fun before(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> {
val constvalue = repeatLoop.untilCondition.constValue(program) val constvalue = untilLoop.untilCondition.constValue(program)
if(constvalue!=null) { if(constvalue!=null) {
if(constvalue.asBooleanValue) { if(constvalue.asBooleanValue) {
// always true -> keep only the statement block (if there are no continue and break statements) // always true -> keep only the statement block (if there are no continue and break statements)
errors.warn("condition is always true", repeatLoop.untilCondition.position) errors.warn("condition is always true", untilLoop.untilCondition.position)
if(!hasContinueOrBreak(repeatLoop.body)) if(!hasContinueOrBreak(untilLoop.body))
return listOf(IAstModification.ReplaceNode(repeatLoop, repeatLoop.body, parent)) return listOf(IAstModification.ReplaceNode(untilLoop, untilLoop.body, parent))
} else { } else {
// always false // always false
val forever = ForeverLoop(repeatLoop.body, repeatLoop.position) val forever = RepeatLoop(null, untilLoop.body, untilLoop.position)
return listOf(IAstModification.ReplaceNode(repeatLoop, forever, parent)) return listOf(IAstModification.ReplaceNode(untilLoop, forever, parent))
} }
} }
return noModifications return noModifications
@ -273,7 +273,7 @@ internal class StatementOptimizer(private val program: Program,
if(constvalue!=null) { if(constvalue!=null) {
return if(constvalue.asBooleanValue) { return if(constvalue.asBooleanValue) {
// always true // always true
val forever = ForeverLoop(whileLoop.body, whileLoop.position) val forever = RepeatLoop(null, whileLoop.body, whileLoop.position)
listOf(IAstModification.ReplaceNode(whileLoop, forever, parent)) listOf(IAstModification.ReplaceNode(whileLoop, forever, parent))
} else { } else {
// always false -> remove the while statement altogether // always false -> remove the while statement altogether
@ -284,6 +284,24 @@ internal class StatementOptimizer(private val program: Program,
return noModifications return noModifications
} }
override fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> {
val iter = repeatLoop.iterations
if(iter!=null) {
if(repeatLoop.body.containsNoCodeNorVars()) {
errors.warn("empty loop removed", repeatLoop.position)
return listOf(IAstModification.Remove(repeatLoop, parent))
}
val iterations = iter.constValue(program)?.number?.toInt()
if (iterations == 0) {
errors.warn("iterations is always 0, removed loop", iter.position)
return listOf(IAstModification.Remove(repeatLoop, parent))
}
if (iterations == 1)
errors.warn("iterations is always 1", iter.position)
}
return noModifications
}
override fun after(whenStatement: WhenStatement, parent: Node): Iterable<IAstModification> { override fun after(whenStatement: WhenStatement, parent: Node): Iterable<IAstModification> {
// remove empty choices // remove empty choices
class ChoiceRemover(val choice: WhenChoice) : IAstModification { class ChoiceRemover(val choice: WhenChoice) : IAstModification {

View File

@ -50,7 +50,7 @@ Code
There are different kinds of instructions ('statements' is a better name) such as: There are different kinds of instructions ('statements' is a better name) such as:
- value assignment - value assignment
- looping (for, while, repeat, unconditional jumps) - looping (for, while, do-until, repeat, unconditional jumps)
- conditional execution (if - then - else, when, and conditional jumps) - conditional execution (if - then - else, when, and conditional jumps)
- subroutine calls - subroutine calls
- label definition - label definition
@ -137,7 +137,7 @@ Scopes are created using either of these two statements:
.. important:: .. important::
Unlike most other programming languages, a new scope is *not* created inside Unlike most other programming languages, a new scope is *not* created inside
for, while and repeat statements, the if statement, and the branching conditionals. for, while, repeat, and do-until statements, the if statement, and the branching conditionals.
These all share the same scope from the subroutine they're defined in. These all share the same scope from the subroutine they're defined in.
You can define variables in these blocks, but these will be treated as if they You can define variables in these blocks, but these will be treated as if they
were defined in the subroutine instead. were defined in the subroutine instead.
@ -391,11 +391,9 @@ The loop variable must be declared as byte or word earlier so you can reuse it f
Iterating with a floating point variable is not supported. If you want to loop over a floating-point array, use a loop with an integer index variable instead. Iterating with a floating point variable is not supported. If you want to loop over a floating-point array, use a loop with an integer index variable instead.
The *while*-loop is used to repeat a piece of code while a certain condition is still true. The *while*-loop is used to repeat a piece of code while a certain condition is still true.
The *repeat--until* loop is used to repeat a piece of code until a certain condition is true. The *do--until* loop is used to repeat a piece of code until a certain condition is true.
The *repeat* loop is used as a short notation of a for loop where the loop variable doesn't matter and you're only interested in the number of iterations.
The *forever*-loop is used to simply run a piece of code in a loop, forever. You can still (without iteration count specified it simply loops forever).
break out of this loop if desired. A "while true" or "until false" loop is equivalent to
a forever-loop.
You can also create loops by using the ``goto`` statement, but this should usually be avoided. You can also create loops by using the ``goto`` statement, but this should usually be avoided.

View File

@ -596,31 +596,33 @@ You can use a single statement, or a statement block like in the example below::
} }
repeat-until loop do-until loop
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
Until the given condition is true (1), repeat the given statement(s). Until the given condition is true (1), repeat the given statement(s).
You can use a single statement, or a statement block like in the example below:: You can use a single statement, or a statement block like in the example below::
repeat { do {
; do something... ; do something...
break ; break out of the loop break ; break out of the loop
continue ; immediately enter next iteration continue ; immediately enter next iteration
} until <condition> } until <condition>
forever loop repeat loop
^^^^^^^^^^^^ ^^^^^^^^^^^
Simply run the code in a loop, forever. It's the same as a while true or until false loop, When you're only interested in repeating something a given number of times.
or just a jump back to a previous label. You can still break out of this loop as well, if you want:: It's a short hand for a for loop without an explicit loop variable::
forever { repeat 15 {
; .. do stuff ; do something...
if something break ; you can break out of the loop
break ; you can exit the loop if you want
} }
If you omit the iteration count, it simply loops forever.
You can still ``break`` out of such a loop if you want though.
Conditional Execution and Jumps Conditional Execution and Jumps
------------------------------- -------------------------------

View File

@ -21,7 +21,7 @@ main {
ubyte active_height = 24 ubyte active_height = 24
ubyte upwards = true ubyte upwards = true
forever { repeat {
ubyte mountain = 223 ; slope upwards ubyte mountain = 223 ; slope upwards
if active_height < target_height { if active_height < target_height {
active_height++ active_height++

View File

@ -16,7 +16,7 @@ sub start() {
void c64.CHRIN() void c64.CHRIN()
c64.CLEARSCR() c64.CLEARSCR()
forever { repeat {
uword note uword note
for note in notes { for note in notes {
ubyte note1 = lsb(note) ubyte note1 = lsb(note)

View File

@ -39,7 +39,7 @@ graphics {
if dx >= dy { if dx >= dy {
if positive_ix { if positive_ix {
forever { repeat {
plot(y1) plot(y1)
if plotx==x2 if plotx==x2
return return
@ -51,7 +51,7 @@ graphics {
} }
} }
} else { } else {
forever { repeat {
plot(y1) plot(y1)
if plotx==x2 if plotx==x2
return return
@ -66,7 +66,7 @@ graphics {
} }
else { else {
if positive_ix { if positive_ix {
forever { repeat {
plot(y1) plot(y1)
if y1 == y2 if y1 == y2
return return
@ -78,7 +78,7 @@ graphics {
} }
} }
} else { } else {
forever { repeat {
plot(y1) plot(y1)
if y1 == y2 if y1 == y2
return return

View File

@ -19,7 +19,7 @@ main {
sub start() { sub start() {
float time=0.0 float time=0.0
forever { repeat {
rotate_vertices(time) rotate_vertices(time)
c64scr.clear_screenchars(32) c64scr.clear_screenchars(32)
draw_edges() draw_edges()

View File

@ -82,7 +82,7 @@ main {
uword anglex uword anglex
uword angley uword angley
uword anglez uword anglez
forever { repeat {
c64.TIME_LO=0 c64.TIME_LO=0
rotate_vertices(msb(anglex), msb(angley), msb(anglez)) rotate_vertices(msb(anglex), msb(angley), msb(anglez))
position_sprites() position_sprites()

View File

@ -21,7 +21,7 @@ main {
uword anglex uword anglex
uword angley uword angley
uword anglez uword anglez
forever { repeat {
rotate_vertices(msb(anglex), msb(angley), msb(anglez)) rotate_vertices(msb(anglex), msb(angley), msb(anglez))
c64scr.clear_screenchars(32) c64scr.clear_screenchars(32)
draw_edges() draw_edges()

View File

@ -10,7 +10,7 @@ main {
graphics.enable_bitmap_mode() graphics.enable_bitmap_mode()
draw_lines() draw_lines()
draw_circles() draw_circles()
forever { repeat {
} }
} }

View File

@ -77,7 +77,7 @@ main {
ubyte y = y1 ubyte y = y1
if dx >= dy { if dx >= dy {
forever { repeat {
c64scr.setcc(x, y, 42, 5) c64scr.setcc(x, y, 42, 5)
if x==x2 if x==x2
return return
@ -89,7 +89,7 @@ main {
} }
} }
} else { } else {
forever { repeat {
c64scr.setcc(x, y, 42, 5) c64scr.setcc(x, y, 42, 5)
if y == y2 if y == y2
return return

View File

@ -48,7 +48,7 @@ main {
} }
} }
forever { repeat {
} }
} }
} }

View File

@ -12,7 +12,7 @@ main {
; calculate primes ; calculate primes
c64scr.print("prime numbers up to 255:\n\n") c64scr.print("prime numbers up to 255:\n\n")
ubyte amount=0 ubyte amount=0
forever { repeat {
ubyte prime = find_next_prime() ubyte prime = find_next_prime()
if prime==0 if prime==0
break break

View File

@ -7,7 +7,7 @@ main {
c64.SCROLY &= %11101111 ; blank the screen c64.SCROLY &= %11101111 ; blank the screen
c64utils.set_rasterirq_excl(40) ; register exclusive raster irq handler c64utils.set_rasterirq_excl(40) ; register exclusive raster irq handler
forever { repeat {
; enjoy the moving bars :) ; enjoy the moving bars :)
} }

View File

@ -14,7 +14,7 @@ main {
sub start() { sub start() {
Color purple = {255, 0, 255} Color purple = [255, 0, 255]
Color other Color other

View File

@ -11,7 +11,7 @@ main {
float t float t
ubyte color ubyte color
forever { repeat {
ubyte xx=(sin(t) * width/2.2) + width/2.0 as ubyte ubyte xx=(sin(t) * width/2.2) + width/2.0 as ubyte
ubyte yy=(cos(t*1.1356) * height/2.2) + height/2.0 as ubyte ubyte yy=(cos(t*1.1356) * height/2.2) + height/2.0 as ubyte
c64scr.setcc(xx, yy, 81, color) c64scr.setcc(xx, yy, 81, color)

View File

@ -15,7 +15,7 @@ main {
Ball ball Ball ball
forever { repeat {
ubyte x = msb(sin8u(msb(ball.anglex)) as uword * width) ubyte x = msb(sin8u(msb(ball.anglex)) as uword * width)
ubyte y = msb(cos8u(msb(ball.angley)) as uword * height) ubyte y = msb(cos8u(msb(ball.angley)) as uword * height)
c64scr.setcc(x, y, 81, ball.color) c64scr.setcc(x, y, 81, ball.color)

View File

@ -7,11 +7,64 @@
main { main {
; TODO check removal of empty loops
sub start() { sub start() {
ubyte i ubyte i
for i in 0 to 20 { for i in 1 to 20 {
c64scr.print_ub(i) c64.CHROUT('*')
c64.CHROUT('\n')
} }
c64.CHROUT('\n')
i=0
do {
c64.CHROUT('*')
i++
} until i==20
c64.CHROUT('\n')
repeat {
break
continue
c64.CHROUT('*')
}
c64.CHROUT('\n')
repeat 0 {
c64.CHROUT('@')
break
continue
}
c64.CHROUT('\n')
repeat 1 {
c64.CHROUT('1')
continue
break
}
c64.CHROUT('\n')
repeat 255 {
c64.CHROUT('@')
}
c64.CHROUT('\n')
repeat 256 {
c64.CHROUT('!')
}
c64.CHROUT('\n')
uword teller
repeat 4000 {
teller++
}
c64scr.print_uw(teller)
c64.CHROUT('\n')
repeat {
}
} }
} }

View File

@ -22,7 +22,7 @@ main {
turtle.rt(94) turtle.rt(94)
} }
forever { repeat {
} }
} }
} }

View File

@ -94,8 +94,8 @@ statement :
| returnstmt | returnstmt
| forloop | forloop
| whileloop | whileloop
| untilloop
| repeatloop | repeatloop
| foreverloop
| whenstmt | whenstmt
| breakstmt | breakstmt
| continuestmt | continuestmt
@ -228,8 +228,6 @@ booleanliteral : 'true' | 'false' ;
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ; // you can split the values over several lines arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ; // you can split the values over several lines
structliteral : '{' EOL? expression (',' EOL? expression)* EOL? '}' ; // you can split the values over several lines
stringliteral : ALT_STRING_ENCODING? STRING ; stringliteral : ALT_STRING_ENCODING? STRING ;
charliteral : ALT_STRING_ENCODING? SINGLECHAR ; charliteral : ALT_STRING_ENCODING? SINGLECHAR ;
@ -244,7 +242,6 @@ literalvalue :
| stringliteral | stringliteral
| charliteral | charliteral
| floatliteral | floatliteral
| structliteral
; ;
inlineasm : '%asm' INLINEASMBLOCK; inlineasm : '%asm' INLINEASMBLOCK;
@ -304,9 +301,9 @@ forloop : 'for' identifier 'in' expression EOL? (statement | statement_block) ;
whileloop: 'while' expression EOL? (statement | statement_block) ; whileloop: 'while' expression EOL? (statement | statement_block) ;
repeatloop: 'repeat' (statement | statement_block) EOL? 'until' expression ; untilloop: 'do' (statement | statement_block) EOL? 'until' expression ;
foreverloop: 'forever' EOL? (statement | statement_block) ; repeatloop: 'repeat' expression? EOL? (statement | statement_block) ;
whenstmt: 'when' expression '{' EOL (when_choice | EOL) * '}' EOL? ; whenstmt: 'when' expression '{' EOL (when_choice | EOL) * '}' EOL? ;