direct memory access and sprite fixes

This commit is contained in:
Irmen de Jong 2018-12-31 04:48:26 +01:00
parent c07bd8a4a8
commit a319e6f9ec
13 changed files with 767 additions and 713 deletions

View File

@ -126,9 +126,8 @@ assign_target:
postincrdecr : assign_target operator = ('++' | '--') ;
expression :
'(' expression ')'
| functioncall
| prefix = ('+'|'-'|'~') expression
functioncall
| <assoc=right> prefix = ('+'|'-'|'~') expression
| left = expression bop = '**' right = expression
| left = expression bop = ('*' | '/' | '//' | '%' ) right = expression
| left = expression bop = ('+' | '-' ) right = expression
@ -149,6 +148,7 @@ expression :
| arrayindexed
| directmemory
| expression typecast
| '(' expression ')'
;
@ -159,7 +159,7 @@ arrayindexed :
(identifier | scoped_identifier ) arrayspec
;
directmemory : '@' expression ;
directmemory : '@' '(' expression ')';
functioncall :

View File

@ -3,27 +3,30 @@
~ main {
ubyte[63] balloonsprite = [ %00000000, %01111111, %00000000,
%00000001, %11111111, %11000000,
%00000011, %11111111, %11100000,
%00000011, %11100011, %11100000,
%00000111, %11011100, %11110000,
%00000111, %11011101, %11110000,
%00000111, %11011100, %11110000,
%00000011, %11100011, %11100000,
%00000011, %11111111, %11100000,
%00000011, %11111111, %11100000,
%00000010, %11111111, %10100000,
%00000001, %01111111, %01000000,
%00000001, %00111110, %01000000,
%00000000, %10011100, %10000000,
%00000000, %10011100, %10000000,
%00000000, %01001001, %00000000,
%00000000, %01001001, %00000000,
%00000000, %00111110, %00000000,
%00000000, %00111110, %00000000,
%00000000, %00111110, %00000000,
%00000000, %00011100, %00000000 ]
const uword SP0X = $d000
const uword SP0Y = $d001
ubyte[63] balloonsprite = [ %00000000,%01111111,%00000000,
%00000001,%11111111,%11000000,
%00000011,%11111111,%11100000,
%00000011,%11100011,%11100000,
%00000111,%11011100,%11110000,
%00000111,%11011101,%11110000,
%00000111,%11011100,%11110000,
%00000011,%11100011,%11100000,
%00000011,%11111111,%11100000,
%00000011,%11111111,%11100000,
%00000010,%11111111,%10100000,
%00000001,%01111111,%01000000,
%00000001,%00111110,%01000000,
%00000000,%10011100,%10000000,
%00000000,%10011100,%10000000,
%00000000,%01001001,%00000000,
%00000000,%01001001,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00011100,%00000000 ]
const uword sprite_data_address = 13*64 ; // safe area inside the tape buffer
@ -34,7 +37,7 @@
; copy the ballon sprite data to the correct address and setup the sprite pointers
; @todo make a memcopy function for this, that calls c64utils.memcopy
for ubyte i in 0 to 62 {
for ubyte i in 0 to 63 {
;@(sprite_data_address+i) = @(balloonsprite+i) ; @todo nice error message
@(sprite_data_address+i) = balloonsprite[i]
}
@ -48,23 +51,10 @@
c64.SPRPTR6 = sprite_data_address//64
c64.SPRPTR7 = sprite_data_address//64
c64.SP0X = 30+30*0
c64.SP1X = 30+30*1
c64.SP2X = 30+30*2
c64.SP3X = 30+30*3
c64.SP4X = 30+30*4
c64.SP5X = 30+30*5
c64.SP6X = 30+30*6
c64.SP7X = 30+30*7
c64.SP0Y = 100+10*0
c64.SP1Y = 100+10*1
c64.SP2Y = 100+10*2
c64.SP3Y = 100+10*3
c64.SP4Y = 100+10*4
c64.SP5Y = 100+10*5
c64.SP6Y = 100+10*6
c64.SP7Y = 100+10*7
for ubyte i in 0 to 7 {
@(SP0X+i*2) = 50+25*i
@(SP0Y+i*2) = rnd()
}
c64.SPENA = 255 ; enable all sprites
}
@ -72,30 +62,25 @@
~ irq {
; @todo no longer auto-set this as irq handler. instead, add builtins functions activate_irqvec() / restore_irqvec()
sub irq() {
c64.SP0Y--
c64.SP1Y--
c64.SP2Y--
c64.SP3Y--
c64.SP4Y--
c64.SP5Y--
c64.SP6Y--
c64.SP7Y--
;return ; @todo return statements in the irqhandler should not do rts, but instead jmp c64.IRQDFRT
; @todo also when including this return, the jmp c64.IRQDFRT at the end gets omitted.....:(
c64.EXTCOL++
for ubyte i in 0 to 7 {
@(main.SP0Y+i+i)-- ; float up
; const uword SP0X = $d000
; for ubyte i in 0 to 7 {
; @(SP0X+i*2) = @(SP0X+i*2) + 1 ; @todo this doesn't read (or write?) the correct values..
; ubyte r = rnd()
; if r>228
; ; @(SP0X+i*2)++ ; @todo allow this
; @(SP0X+i*2) = @(SP0X+i*2)+1
; else {
; if r<28
; @(SP0X+i*2) = @(SP0X+i*2)-1
; }
; }
; horizontal wobble effect
ubyte r = rnd()
if r>208
@(main.SP0X+i+i)++
else {
; @todo if-else if -else syntax without curly braces
if r<48
@(main.SP0X+i+i)--
}
}
c64.EXTCOL--
}
}

View File

@ -3,23 +3,15 @@
~ main {
sub start() {
A+=5
; @todo if-else if should compile ?:
; if A>100
; Y=2
; else if A>20
; Y=3
; @($d020) = 5
@($d020)++
@($d021)--
; @($d020)=(@$d020)+5
@($d020)+=5
; @($d021)=(@$d021)-5
@($d021)-=5
ubyte i=0
A= @($d020)
A= @($d020+i)
@($d020) = 0
@($d020+i) = 0
@($d020+i) = 1
@($d020+i) = 2
@($d020) = @($d020+i) + 1
@($d020+i) = @($d020+i) + 1
c64scr.print_ub(X)
}
}

View File

@ -261,7 +261,7 @@ interface IAstProcessor {
fun process(assignTarget: AssignTarget): AssignTarget {
assignTarget.arrayindexed?.process(this)
assignTarget.identifier?.process(this)
assignTarget.memAddressExpression = assignTarget.memAddressExpression?.process(this)
assignTarget.memoryAddress?.process(this)
return assignTarget
}
@ -275,9 +275,14 @@ interface IAstProcessor {
return typecastExpression
}
fun process(directmemoryExpression: DirectMemoryExpression): IExpression {
directmemoryExpression.addressExpression = directmemoryExpression.addressExpression.process(this)
return directmemoryExpression
fun process(memread: DirectMemoryRead): IExpression {
memread.addressExpression = memread.addressExpression.process(this)
return memread
}
fun process(memwrite: DirectMemoryWrite): IExpression {
memwrite.addressExpression = memwrite.addressExpression.process(this)
return memwrite
}
}
@ -731,7 +736,7 @@ class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, va
data class AssignTarget(val register: Register?,
val identifier: IdentifierReference?,
val arrayindexed: ArrayIndexedExpression?,
var memAddressExpression: IExpression?,
var memoryAddress: DirectMemoryWrite?,
override val position: Position) : Node {
override lateinit var parent: Node
@ -739,7 +744,7 @@ data class AssignTarget(val register: Register?,
this.parent = parent
identifier?.linkParents(this)
arrayindexed?.linkParents(this)
memAddressExpression?.linkParents(this)
memoryAddress?.linkParents(this)
}
fun process(processor: IAstProcessor) = processor.process(this)
@ -750,7 +755,8 @@ data class AssignTarget(val register: Register?,
is RegisterExpr -> AssignTarget(expr.register, null, null, null, expr.position)
is IdentifierReference -> AssignTarget(null, expr, null, null, expr.position)
is ArrayIndexedExpression -> AssignTarget(null, null, expr, null, expr.position)
is DirectMemoryExpression -> AssignTarget(null, null, null, expr, expr.position)
is DirectMemoryRead -> AssignTarget(null, null, null, DirectMemoryWrite(expr.addressExpression, expr.position), expr.position)
is DirectMemoryWrite -> AssignTarget(null, null, null, expr, expr.position)
else -> throw FatalAstException("invalid expression object $expr")
}
}
@ -771,7 +777,7 @@ data class AssignTarget(val register: Register?,
return dt
}
if(memAddressExpression!=null)
if(memoryAddress!=null)
return DataType.UBYTE
return null
@ -784,8 +790,9 @@ data class AssignTarget(val register: Register?,
return identifier.nameInSource.last()
if(arrayindexed!=null)
return arrayindexed.identifier!!.nameInSource.last()
if(memAddressExpression is LiteralValue)
return (memAddressExpression as LiteralValue).asIntegerValue.toString()
val address = memoryAddress?.addressExpression
if(address is LiteralValue)
return address.asIntegerValue.toString()
return "???"
}
}
@ -1027,7 +1034,7 @@ class TypecastExpression(var expression: IExpression, var type: DataType, overri
}
class DirectMemoryExpression(var addressExpression: IExpression, override val position: Position) : IExpression {
class DirectMemoryRead(var addressExpression: IExpression, override val position: Position) : IExpression {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
@ -1042,7 +1049,27 @@ class DirectMemoryExpression(var addressExpression: IExpression, override val po
override fun constValue(namespace: INameScope, heap: HeapValues) = null
override fun toString(): String {
return "DirectMemory($addressExpression)"
return "DirectMemoryRead($addressExpression)"
}
}
class DirectMemoryWrite(var addressExpression: IExpression, override val position: Position) : IExpression {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
this.addressExpression.linkParents(this)
}
override fun process(processor: IAstProcessor) = processor.process(this)
override fun referencesIdentifier(name: String) = false
override fun resultingDatatype(namespace: INameScope, heap: HeapValues): DataType? = DataType.UBYTE
override fun isIterable(namespace: INameScope, heap: HeapValues) = false
override fun constValue(namespace: INameScope, heap: HeapValues) = null
override fun toString(): String {
return "DirectMemoryWrite($addressExpression)"
}
}
@ -1978,7 +2005,7 @@ private fun prog8Parser.Assign_targetContext.toAst() : AssignTarget {
register!=null -> AssignTarget(register, null, null, null, toPosition())
identifier!=null -> AssignTarget(null, identifier.toAst(), null, null, toPosition())
arrayindexed()!=null -> AssignTarget(null, null, arrayindexed().toAst(), null, toPosition())
directmemory()!=null -> AssignTarget(null, null, null, directmemory().expression().toAst(), toPosition())
directmemory()!=null -> AssignTarget(null, null, null, DirectMemoryWrite(directmemory().expression().toAst(), toPosition()), toPosition())
else -> AssignTarget(null, scoped_identifier()?.toAst(), null, null, toPosition())
}
}
@ -2108,7 +2135,7 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
return TypecastExpression(expression(0).toAst(), typecast().datatype().toAst(), toPosition())
if(directmemory()!=null)
return DirectMemoryExpression(directmemory().expression().toAst(), toPosition())
return DirectMemoryRead(directmemory().expression().toAst(), toPosition())
throw FatalAstException(text)
}

View File

@ -387,7 +387,7 @@ class AstChecker(private val namespace: INameScope,
}
private fun processAssignmentTarget(assignment: Assignment, target: AssignTarget): Assignment {
val memAddr = target.memAddressExpression?.constValue(namespace, heap)?.asIntegerValue
val memAddr = target.memoryAddress?.addressExpression?.constValue(namespace, heap)?.asIntegerValue
if(memAddr!=null) {
if(memAddr<0 || memAddr>=65536)
checkResult.add(ExpressionError("address out of range", target.position))
@ -435,16 +435,16 @@ class AstChecker(private val namespace: INameScope,
target.register != null -> RegisterExpr(target.register, target.position)
target.identifier != null -> target.identifier
target.arrayindexed != null -> target.arrayindexed
target.memAddressExpression != null -> {
// @addr += 4 --> @addr = @addr +4
// TODO: make it so that it follows the others
val memRead = DirectMemoryExpression(target.memAddressExpression!!, target.position)
val expression = BinaryExpression(memRead, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
expression.linkParents(assignment.parent)
val assignment2 = Assignment(listOf(target), null, expression, assignment.position)
assignment2.linkParents(assignment.parent)
return assignment2
}
target.memoryAddress != null -> target.memoryAddress!!
// // @addr += 4 --> @addr = @addr +4
// // TODO: make it so that it follows the others
// val memRead = DirectMemoryRead(target.memoryAddress!!, target.position)
// val expression = BinaryExpression(memRead, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
// expression.linkParents(assignment.parent)
// val assignment2 = Assignment(listOf(target), null, expression, assignment.position)
// assignment2.linkParents(assignment.parent)
// return assignment2
// }
else -> throw FatalAstException("strange assignment")
}
@ -827,7 +827,7 @@ class AstChecker(private val namespace: INameScope,
if(dt !in NumericDatatypes && dt !in ArrayDatatypes)
checkResult.add(SyntaxError("can only increment or decrement a byte/float/word", postIncrDecr.position))
}
} else if(postIncrDecr.target.memAddressExpression != null) {
} else if(postIncrDecr.target.memoryAddress != null) {
// a memory location can always be ++/--
}
return super.process(postIncrDecr)

View File

@ -580,7 +580,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
is ArrayIndexedExpression -> translate(expr, false)
is RangeExpr -> throw CompilerException("it's not possible to just have a range expression that has to be translated")
is TypecastExpression -> translate(expr)
is DirectMemoryExpression -> translate(expr)
is DirectMemoryRead -> translate(expr)
is DirectMemoryWrite -> translate(expr)
else -> {
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
when(lv.type) {
@ -1273,15 +1274,19 @@ private class StatementTranslator(private val prog: IntermediateProgram,
"--" -> prog.instr(opcodeDecArrayindexedVar(variable.datatype), callLabel = variable.scopedname)
}
}
stmt.target.memAddressExpression != null -> {
val address = stmt.target.memAddressExpression!!.constValue(namespace, heap)?.asIntegerValue
stmt.target.memoryAddress != null -> {
val address = stmt.target.memoryAddress?.addressExpression?.constValue(namespace, heap)?.asIntegerValue
if(address!=null) {
when(stmt.operator) {
"++" -> prog.instr(Opcode.INC_MEMORY, Value(DataType.UWORD, address))
"--" -> prog.instr(Opcode.DEC_MEMORY, Value(DataType.UWORD, address))
}
} else {
TODO("memory ++/-- ${stmt.target.memAddressExpression}")
translate(stmt.target.memoryAddress!!.addressExpression)
when(stmt.operator) {
"++" -> prog.instr(Opcode.POP_INC_MEMORY)
"--" -> prog.instr(Opcode.POP_DEC_MEMORY)
}
}
}
else -> throw CompilerException("very strange postincrdecr ${stmt.target}")
@ -1368,7 +1373,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
assignTarget.register != null -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = assignTarget.register.toString())
assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, false)
assignTarget.memAddressExpression != null -> {
assignTarget.memoryAddress != null -> {
TODO("translate aug assign on memory address $stmt")
}
}
@ -1496,14 +1501,13 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
assignTarget.register != null -> prog.instr(Opcode.POP_VAR_BYTE, callLabel = assignTarget.register.toString())
assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, true) // write value to it
assignTarget.memAddressExpression != null -> {
val address = assignTarget.memAddressExpression?.constValue(namespace, heap)?.asIntegerValue
assignTarget.memoryAddress != null -> {
val address = assignTarget.memoryAddress?.addressExpression?.constValue(namespace, heap)?.asIntegerValue
if(address!=null) {
// const integer address given
prog.instr(Opcode.POP_MEM_BYTE, arg=Value(DataType.UWORD, address))
} else {
translate(assignTarget.memAddressExpression!!)
prog.instr(Opcode.POP_MEMWRITE)
translate(assignTarget.memoryAddress!!)
}
}
else -> throw CompilerException("corrupt assigntarget $assignTarget")
@ -2097,15 +2101,26 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
}
private fun translate(expr: DirectMemoryExpression) {
private fun translate(memread: DirectMemoryRead) {
// for now, only a single memory location (ubyte) is read at a time.
val address = expr.addressExpression.constValue(namespace, heap)?.asIntegerValue
val address = memread.addressExpression.constValue(namespace, heap)?.asIntegerValue
if(address!=null) {
prog.instr(Opcode.PUSH_MEM_UB, arg = Value(DataType.UWORD, address))
} else {
translate(expr.addressExpression)
translate(memread.addressExpression)
prog.instr(Opcode.PUSH_MEMREAD)
}
}
private fun translate(memwrite: DirectMemoryWrite) {
// for now, only a single memory location (ubyte) is written at a time.
val address = memwrite.addressExpression.constValue(namespace, heap)?.asIntegerValue
if(address!=null) {
prog.instr(Opcode.POP_MEM_BYTE, arg = Value(DataType.UWORD, address))
} else {
translate(memwrite.addressExpression)
prog.instr(Opcode.POP_MEMWRITE)
}
}
}

View File

@ -164,8 +164,10 @@ enum class Opcode {
DEC_VAR_W,
DEC_VAR_UW,
DEC_VAR_F,
INC_MEMORY,
DEC_MEMORY,
INC_MEMORY, // increment direct address
DEC_MEMORY, // decrement direct address
POP_INC_MEMORY, // increment address from stack
POP_DEC_MEMORY, // decrement address from address
// comparisons
// @todo the comparisons push the result back on the stack. Optimize this to work with just processor flags? This does mean you can no longer use a logical boolean result as a byte 0/1 value ?

View File

@ -496,11 +496,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.PUSH_MEMREAD -> {
"""
lda ${(ESTACK_LO+1).toHex()},x
sta ${C64Zeropage.SCRATCH_W1}
sta (+) +1
lda ${(ESTACK_HI+1).toHex()},x
sta ${C64Zeropage.SCRATCH_W1+1}
ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y
sta (+) +2
+ lda 65535 ; modified
sta ${(ESTACK_LO+1).toHex()},x
"""
}
@ -594,13 +593,12 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
"""
inx
lda ${ESTACK_LO.toHex()},x
sta ${C64Zeropage.SCRATCH_W1}
sta (+) +1
lda ${ESTACK_HI.toHex()},x
sta ${C64Zeropage.SCRATCH_W1+1}
sta (+) +2
inx
lda ${ESTACK_LO.toHex()},x
ldy #0
sta (${C64Zeropage.SCRATCH_W1}),y
+ sta 65535 ; modified
"""
}
@ -637,6 +635,26 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
jsr prog8_lib.inc_var_f
"""
}
Opcode.POP_INC_MEMORY -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
sta (+) +1
lda ${ESTACK_HI.toHex()},x
sta (+) +2
+ inc 65535 ; modified
"""
}
Opcode.POP_DEC_MEMORY -> {
"""
inx
lda ${ESTACK_LO.toHex()},x
sta (+) +1
lda ${ESTACK_HI.toHex()},x
sta (+) +2
+ dec 65535 ; modified
"""
}
Opcode.DEC_VAR_UB, Opcode.DEC_VAR_B -> {
when (ins.callLabel) {
"A" -> " sec | sbc #1"

View File

@ -72,11 +72,11 @@ public class prog8Lexer extends Lexer {
"'%asmbinary'", "'%option'", "','", "'='", "'const'", "'memory'", "'ubyte'",
"'byte'", "'uword'", "'word'", "'float'", "'str'", "'str_p'", "'str_s'",
"'str_ps'", "'['", "']'", "'+='", "'-='", "'/='", "'//='", "'*='", "'**='",
"'&='", "'|='", "'^='", "'%='", "'++'", "'--'", "'('", "')'", "'+'",
"'-'", "'**'", "'*'", "'/'", "'//'", "'%'", "'<'", "'>'", "'<='", "'>='",
"'=='", "'!='", "'&'", "'^'", "'|'", "'to'", "'step'", "'and'", "'or'",
"'xor'", "'not'", "'as'", "'@'", "'return'", "'break'", "'continue'",
"'.'", "'A'", "'X'", "'Y'", "'AX'", "'AY'", "'XY'", "'Pc'", "'Pz'", "'Pn'",
"'&='", "'|='", "'^='", "'%='", "'++'", "'--'", "'+'", "'-'", "'**'",
"'*'", "'/'", "'//'", "'%'", "'<'", "'>'", "'<='", "'>='", "'=='", "'!='",
"'&'", "'^'", "'|'", "'to'", "'step'", "'and'", "'or'", "'xor'", "'not'",
"'('", "')'", "'as'", "'@'", "'return'", "'break'", "'continue'", "'.'",
"'A'", "'X'", "'Y'", "'AX'", "'AY'", "'XY'", "'Pc'", "'Pz'", "'Pn'",
"'Pv'", "'.w'", "'true'", "'false'", "'%asm'", "'sub'", "'->'", "'{'",
"'}'", "'asmsub'", "'clobbers'", "'if'", "'else'", "'if_cs'", "'if_cc'",
"'if_eq'", "'if_z'", "'if_ne'", "'if_nz'", "'if_pl'", "'if_pos'", "'if_mi'",
@ -235,19 +235,19 @@ public class prog8Lexer extends Lexer {
"\3\32\3\32\3\32\3\32\3\32\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\34\3\34"+
"\3\35\3\35\3\36\3\36\3\36\3\37\3\37\3\37\3 \3 \3 \3!\3!\3!\3!\3\"\3\""+
"\3\"\3#\3#\3#\3#\3$\3$\3$\3%\3%\3%\3&\3&\3&\3\'\3\'\3\'\3(\3(\3(\3)\3"+
")\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\61\3"+
"\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67\3\67\3"+
"\67\38\38\38\39\39\3:\3:\3;\3;\3<\3<\3<\3=\3=\3=\3=\3=\3>\3>\3>\3>\3?"+
"\3?\3?\3@\3@\3@\3@\3A\3A\3A\3A\3B\3B\3B\3C\3C\3D\3D\3D\3D\3D\3D\3D\3E"+
"\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3F\3F\3F\3G\3G\3H\3H\3I\3I\3J\3J\3K"+
"\3K\3K\3L\3L\3L\3M\3M\3M\3N\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3R\3R\3R"+
"\3S\3S\3S\3S\3S\3T\3T\3T\3T\3T\3T\3U\3U\3U\3U\3U\3V\3V\3V\3V\3W\3W\3W"+
"\3X\3X\3Y\3Y\3Z\3Z\3Z\3Z\3Z\3Z\3Z\3[\3[\3[\3[\3[\3[\3[\3[\3[\3\\\3\\\3"+
"\\\3]\3]\3]\3]\3]\3^\3^\3^\3^\3^\3^\3_\3_\3_\3_\3_\3_\3`\3`\3`\3`\3`\3"+
"`\3a\3a\3a\3a\3a\3b\3b\3b\3b\3b\3b\3c\3c\3c\3c\3c\3c\3d\3d\3d\3d\3d\3"+
"d\3e\3e\3e\3e\3e\3e\3e\3f\3f\3f\3f\3f\3f\3g\3g\3g\3g\3g\3g\3g\3h\3h\3"+
"h\3h\3h\3h\3i\3i\3i\3i\3i\3i\3j\3j\3j\3j\3k\3k\3k\3l\3l\3l\3l\3l\3l\3"+
"m\3m\3m\3m\3m\3m\3m\3n\3n\3n\3n\3n\3n\3o\3o\7o\u02e9\no\fo\16o\u02ec\13"+
")\3)\3*\3*\3+\3+\3,\3,\3,\3-\3-\3.\3.\3/\3/\3/\3\60\3\60\3\61\3\61\3\62"+
"\3\62\3\63\3\63\3\63\3\64\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67"+
"\3\67\38\38\39\39\3:\3:\3:\3;\3;\3;\3;\3;\3<\3<\3<\3<\3=\3=\3=\3>\3>\3"+
">\3>\3?\3?\3?\3?\3@\3@\3A\3A\3B\3B\3B\3C\3C\3D\3D\3D\3D\3D\3D\3D\3E\3"+
"E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3F\3F\3F\3G\3G\3H\3H\3I\3I\3J\3J\3K\3"+
"K\3K\3L\3L\3L\3M\3M\3M\3N\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3R\3R\3R\3"+
"S\3S\3S\3S\3S\3T\3T\3T\3T\3T\3T\3U\3U\3U\3U\3U\3V\3V\3V\3V\3W\3W\3W\3"+
"X\3X\3Y\3Y\3Z\3Z\3Z\3Z\3Z\3Z\3Z\3[\3[\3[\3[\3[\3[\3[\3[\3[\3\\\3\\\3\\"+
"\3]\3]\3]\3]\3]\3^\3^\3^\3^\3^\3^\3_\3_\3_\3_\3_\3_\3`\3`\3`\3`\3`\3`"+
"\3a\3a\3a\3a\3a\3b\3b\3b\3b\3b\3b\3c\3c\3c\3c\3c\3c\3d\3d\3d\3d\3d\3d"+
"\3e\3e\3e\3e\3e\3e\3e\3f\3f\3f\3f\3f\3f\3g\3g\3g\3g\3g\3g\3g\3h\3h\3h"+
"\3h\3h\3h\3i\3i\3i\3i\3i\3i\3j\3j\3j\3j\3k\3k\3k\3l\3l\3l\3l\3l\3l\3m"+
"\3m\3m\3m\3m\3m\3m\3n\3n\3n\3n\3n\3n\3o\3o\7o\u02e9\no\fo\16o\u02ec\13"+
"o\3o\3o\3o\3o\3p\3p\7p\u02f4\np\fp\16p\u02f7\13p\3p\3p\3q\3q\3q\3q\3r"+
"\6r\u0300\nr\rr\16r\u0301\3s\3s\7s\u0306\ns\fs\16s\u0309\13s\3t\3t\3t"+
"\6t\u030e\nt\rt\16t\u030f\5t\u0312\nt\3u\3u\6u\u0316\nu\ru\16u\u0317\3"+
@ -299,11 +299,11 @@ public class prog8Lexer extends Lexer {
"\3\2\2\2=\u01b1\3\2\2\2?\u01b4\3\2\2\2A\u01b7\3\2\2\2C\u01bb\3\2\2\2E"+
"\u01be\3\2\2\2G\u01c2\3\2\2\2I\u01c5\3\2\2\2K\u01c8\3\2\2\2M\u01cb\3\2"+
"\2\2O\u01ce\3\2\2\2Q\u01d1\3\2\2\2S\u01d4\3\2\2\2U\u01d6\3\2\2\2W\u01d8"+
"\3\2\2\2Y\u01da\3\2\2\2[\u01dc\3\2\2\2]\u01df\3\2\2\2_\u01e1\3\2\2\2a"+
"\u01e3\3\2\2\2c\u01e6\3\2\2\2e\u01e8\3\2\2\2g\u01ea\3\2\2\2i\u01ec\3\2"+
"\2\2k\u01ef\3\2\2\2m\u01f2\3\2\2\2o\u01f5\3\2\2\2q\u01f8\3\2\2\2s\u01fa"+
"\3\2\2\2u\u01fc\3\2\2\2w\u01fe\3\2\2\2y\u0201\3\2\2\2{\u0206\3\2\2\2}"+
"\u020a\3\2\2\2\177\u020d\3\2\2\2\u0081\u0211\3\2\2\2\u0083\u0215\3\2\2"+
"\3\2\2\2Y\u01db\3\2\2\2[\u01dd\3\2\2\2]\u01df\3\2\2\2_\u01e2\3\2\2\2a"+
"\u01e4\3\2\2\2c\u01e6\3\2\2\2e\u01e8\3\2\2\2g\u01eb\3\2\2\2i\u01ee\3\2"+
"\2\2k\u01f1\3\2\2\2m\u01f4\3\2\2\2o\u01f6\3\2\2\2q\u01f8\3\2\2\2s\u01fa"+
"\3\2\2\2u\u01fd\3\2\2\2w\u0202\3\2\2\2y\u0206\3\2\2\2{\u0209\3\2\2\2}"+
"\u020d\3\2\2\2\177\u0211\3\2\2\2\u0081\u0213\3\2\2\2\u0083\u0215\3\2\2"+
"\2\u0085\u0218\3\2\2\2\u0087\u021a\3\2\2\2\u0089\u0221\3\2\2\2\u008b\u0227"+
"\3\2\2\2\u008d\u0230\3\2\2\2\u008f\u0232\3\2\2\2\u0091\u0234\3\2\2\2\u0093"+
"\u0236\3\2\2\2\u0095\u0238\3\2\2\2\u0097\u023b\3\2\2\2\u0099\u023e\3\2"+
@ -377,82 +377,82 @@ public class prog8Lexer extends Lexer {
"\7~\2\2\u01c6\u01c7\7?\2\2\u01c7J\3\2\2\2\u01c8\u01c9\7`\2\2\u01c9\u01ca"+
"\7?\2\2\u01caL\3\2\2\2\u01cb\u01cc\7\'\2\2\u01cc\u01cd\7?\2\2\u01cdN\3"+
"\2\2\2\u01ce\u01cf\7-\2\2\u01cf\u01d0\7-\2\2\u01d0P\3\2\2\2\u01d1\u01d2"+
"\7/\2\2\u01d2\u01d3\7/\2\2\u01d3R\3\2\2\2\u01d4\u01d5\7*\2\2\u01d5T\3"+
"\2\2\2\u01d6\u01d7\7+\2\2\u01d7V\3\2\2\2\u01d8\u01d9\7-\2\2\u01d9X\3\2"+
"\2\2\u01da\u01db\7/\2\2\u01dbZ\3\2\2\2\u01dc\u01dd\7,\2\2\u01dd\u01de"+
"\7,\2\2\u01de\\\3\2\2\2\u01df\u01e0\7,\2\2\u01e0^\3\2\2\2\u01e1\u01e2"+
"\7\61\2\2\u01e2`\3\2\2\2\u01e3\u01e4\7\61\2\2\u01e4\u01e5\7\61\2\2\u01e5"+
"b\3\2\2\2\u01e6\u01e7\7\'\2\2\u01e7d\3\2\2\2\u01e8\u01e9\7>\2\2\u01e9"+
"f\3\2\2\2\u01ea\u01eb\7@\2\2\u01ebh\3\2\2\2\u01ec\u01ed\7>\2\2\u01ed\u01ee"+
"\7?\2\2\u01eej\3\2\2\2\u01ef\u01f0\7@\2\2\u01f0\u01f1\7?\2\2\u01f1l\3"+
"\2\2\2\u01f2\u01f3\7?\2\2\u01f3\u01f4\7?\2\2\u01f4n\3\2\2\2\u01f5\u01f6"+
"\7#\2\2\u01f6\u01f7\7?\2\2\u01f7p\3\2\2\2\u01f8\u01f9\7(\2\2\u01f9r\3"+
"\2\2\2\u01fa\u01fb\7`\2\2\u01fbt\3\2\2\2\u01fc\u01fd\7~\2\2\u01fdv\3\2"+
"\2\2\u01fe\u01ff\7v\2\2\u01ff\u0200\7q\2\2\u0200x\3\2\2\2\u0201\u0202"+
"\7u\2\2\u0202\u0203\7v\2\2\u0203\u0204\7g\2\2\u0204\u0205\7r\2\2\u0205"+
"z\3\2\2\2\u0206\u0207\7c\2\2\u0207\u0208\7p\2\2\u0208\u0209\7f\2\2\u0209"+
"|\3\2\2\2\u020a\u020b\7q\2\2\u020b\u020c\7t\2\2\u020c~\3\2\2\2\u020d\u020e"+
"\7z\2\2\u020e\u020f\7q\2\2\u020f\u0210\7t\2\2\u0210\u0080\3\2\2\2\u0211"+
"\u0212\7p\2\2\u0212\u0213\7q\2\2\u0213\u0214\7v\2\2\u0214\u0082\3\2\2"+
"\2\u0215\u0216\7c\2\2\u0216\u0217\7u\2\2\u0217\u0084\3\2\2\2\u0218\u0219"+
"\7B\2\2\u0219\u0086\3\2\2\2\u021a\u021b\7t\2\2\u021b\u021c\7g\2\2\u021c"+
"\u021d\7v\2\2\u021d\u021e\7w\2\2\u021e\u021f\7t\2\2\u021f\u0220\7p\2\2"+
"\u0220\u0088\3\2\2\2\u0221\u0222\7d\2\2\u0222\u0223\7t\2\2\u0223\u0224"+
"\7g\2\2\u0224\u0225\7c\2\2\u0225\u0226\7m\2\2\u0226\u008a\3\2\2\2\u0227"+
"\u0228\7e\2\2\u0228\u0229\7q\2\2\u0229\u022a\7p\2\2\u022a\u022b\7v\2\2"+
"\u022b\u022c\7k\2\2\u022c\u022d\7p\2\2\u022d\u022e\7w\2\2\u022e\u022f"+
"\7g\2\2\u022f\u008c\3\2\2\2\u0230\u0231\7\60\2\2\u0231\u008e\3\2\2\2\u0232"+
"\u0233\7C\2\2\u0233\u0090\3\2\2\2\u0234\u0235\7Z\2\2\u0235\u0092\3\2\2"+
"\2\u0236\u0237\7[\2\2\u0237\u0094\3\2\2\2\u0238\u0239\7C\2\2\u0239\u023a"+
"\7Z\2\2\u023a\u0096\3\2\2\2\u023b\u023c\7C\2\2\u023c\u023d\7[\2\2\u023d"+
"\u0098\3\2\2\2\u023e\u023f\7Z\2\2\u023f\u0240\7[\2\2\u0240\u009a\3\2\2"+
"\2\u0241\u0242\7R\2\2\u0242\u0243\7e\2\2\u0243\u009c\3\2\2\2\u0244\u0245"+
"\7R\2\2\u0245\u0246\7|\2\2\u0246\u009e\3\2\2\2\u0247\u0248\7R\2\2\u0248"+
"\u0249\7p\2\2\u0249\u00a0\3\2\2\2\u024a\u024b\7R\2\2\u024b\u024c\7x\2"+
"\2\u024c\u00a2\3\2\2\2\u024d\u024e\7\60\2\2\u024e\u024f\7y\2\2\u024f\u00a4"+
"\3\2\2\2\u0250\u0251\7v\2\2\u0251\u0252\7t\2\2\u0252\u0253\7w\2\2\u0253"+
"\u0254\7g\2\2\u0254\u00a6\3\2\2\2\u0255\u0256\7h\2\2\u0256\u0257\7c\2"+
"\2\u0257\u0258\7n\2\2\u0258\u0259\7u\2\2\u0259\u025a\7g\2\2\u025a\u00a8"+
"\3\2\2\2\u025b\u025c\7\'\2\2\u025c\u025d\7c\2\2\u025d\u025e\7u\2\2\u025e"+
"\u025f\7o\2\2\u025f\u00aa\3\2\2\2\u0260\u0261\7u\2\2\u0261\u0262\7w\2"+
"\2\u0262\u0263\7d\2\2\u0263\u00ac\3\2\2\2\u0264\u0265\7/\2\2\u0265\u0266"+
"\7@\2\2\u0266\u00ae\3\2\2\2\u0267\u0268\7}\2\2\u0268\u00b0\3\2\2\2\u0269"+
"\u026a\7\177\2\2\u026a\u00b2\3\2\2\2\u026b\u026c\7c\2\2\u026c\u026d\7"+
"u\2\2\u026d\u026e\7o\2\2\u026e\u026f\7u\2\2\u026f\u0270\7w\2\2\u0270\u0271"+
"\7d\2\2\u0271\u00b4\3\2\2\2\u0272\u0273\7e\2\2\u0273\u0274\7n\2\2\u0274"+
"\u0275\7q\2\2\u0275\u0276\7d\2\2\u0276\u0277\7d\2\2\u0277\u0278\7g\2\2"+
"\u0278\u0279\7t\2\2\u0279\u027a\7u\2\2\u027a\u00b6\3\2\2\2\u027b\u027c"+
"\7k\2\2\u027c\u027d\7h\2\2\u027d\u00b8\3\2\2\2\u027e\u027f\7g\2\2\u027f"+
"\u0280\7n\2\2\u0280\u0281\7u\2\2\u0281\u0282\7g\2\2\u0282\u00ba\3\2\2"+
"\2\u0283\u0284\7k\2\2\u0284\u0285\7h\2\2\u0285\u0286\7a\2\2\u0286\u0287"+
"\7e\2\2\u0287\u0288\7u\2\2\u0288\u00bc\3\2\2\2\u0289\u028a\7k\2\2\u028a"+
"\u028b\7h\2\2\u028b\u028c\7a\2\2\u028c\u028d\7e\2\2\u028d\u028e\7e\2\2"+
"\u028e\u00be\3\2\2\2\u028f\u0290\7k\2\2\u0290\u0291\7h\2\2\u0291\u0292"+
"\7a\2\2\u0292\u0293\7g\2\2\u0293\u0294\7s\2\2\u0294\u00c0\3\2\2\2\u0295"+
"\u0296\7k\2\2\u0296\u0297\7h\2\2\u0297\u0298\7a\2\2\u0298\u0299\7|\2\2"+
"\u0299\u00c2\3\2\2\2\u029a\u029b\7k\2\2\u029b\u029c\7h\2\2\u029c\u029d"+
"\7a\2\2\u029d\u029e\7p\2\2\u029e\u029f\7g\2\2\u029f\u00c4\3\2\2\2\u02a0"+
"\u02a1\7k\2\2\u02a1\u02a2\7h\2\2\u02a2\u02a3\7a\2\2\u02a3\u02a4\7p\2\2"+
"\u02a4\u02a5\7|\2\2\u02a5\u00c6\3\2\2\2\u02a6\u02a7\7k\2\2\u02a7\u02a8"+
"\7h\2\2\u02a8\u02a9\7a\2\2\u02a9\u02aa\7r\2\2\u02aa\u02ab\7n\2\2\u02ab"+
"\u00c8\3\2\2\2\u02ac\u02ad\7k\2\2\u02ad\u02ae\7h\2\2\u02ae\u02af\7a\2"+
"\2\u02af\u02b0\7r\2\2\u02b0\u02b1\7q\2\2\u02b1\u02b2\7u\2\2\u02b2\u00ca"+
"\3\2\2\2\u02b3\u02b4\7k\2\2\u02b4\u02b5\7h\2\2\u02b5\u02b6\7a\2\2\u02b6"+
"\u02b7\7o\2\2\u02b7\u02b8\7k\2\2\u02b8\u00cc\3\2\2\2\u02b9\u02ba\7k\2"+
"\2\u02ba\u02bb\7h\2\2\u02bb\u02bc\7a\2\2\u02bc\u02bd\7p\2\2\u02bd\u02be"+
"\7g\2\2\u02be\u02bf\7i\2\2\u02bf\u00ce\3\2\2\2\u02c0\u02c1\7k\2\2\u02c1"+
"\u02c2\7h\2\2\u02c2\u02c3\7a\2\2\u02c3\u02c4\7x\2\2\u02c4\u02c5\7u\2\2"+
"\u02c5\u00d0\3\2\2\2\u02c6\u02c7\7k\2\2\u02c7\u02c8\7h\2\2\u02c8\u02c9"+
"\7a\2\2\u02c9\u02ca\7x\2\2\u02ca\u02cb\7e\2\2\u02cb\u00d2\3\2\2\2\u02cc"+
"\u02cd\7h\2\2\u02cd\u02ce\7q\2\2\u02ce\u02cf\7t\2\2\u02cf\u00d4\3\2\2"+
"\2\u02d0\u02d1\7k\2\2\u02d1\u02d2\7p\2\2\u02d2\u00d6\3\2\2\2\u02d3\u02d4"+
"\7y\2\2\u02d4\u02d5\7j\2\2\u02d5\u02d6\7k\2\2\u02d6\u02d7\7n\2\2\u02d7"+
"\u02d8\7g\2\2\u02d8\u00d8\3\2\2\2\u02d9\u02da\7t\2\2\u02da\u02db\7g\2"+
"\2\u02db\u02dc\7r\2\2\u02dc\u02dd\7g\2\2\u02dd\u02de\7c\2\2\u02de\u02df"+
"\7v\2\2\u02df\u00da\3\2\2\2\u02e0\u02e1\7w\2\2\u02e1\u02e2\7p\2\2\u02e2"+
"\u02e3\7v\2\2\u02e3\u02e4\7k\2\2\u02e4\u02e5\7n\2\2\u02e5\u00dc\3\2\2"+
"\2\u02e6\u02ea\t\2\2\2\u02e7\u02e9\t\3\2\2\u02e8\u02e7\3\2\2\2\u02e9\u02ec"+
"\3\2\2\2\u02ea\u02e8\3\2\2\2\u02ea\u02eb\3\2\2\2\u02eb\u02ed\3\2\2\2\u02ec"+
"\7/\2\2\u01d2\u01d3\7/\2\2\u01d3R\3\2\2\2\u01d4\u01d5\7-\2\2\u01d5T\3"+
"\2\2\2\u01d6\u01d7\7/\2\2\u01d7V\3\2\2\2\u01d8\u01d9\7,\2\2\u01d9\u01da"+
"\7,\2\2\u01daX\3\2\2\2\u01db\u01dc\7,\2\2\u01dcZ\3\2\2\2\u01dd\u01de\7"+
"\61\2\2\u01de\\\3\2\2\2\u01df\u01e0\7\61\2\2\u01e0\u01e1\7\61\2\2\u01e1"+
"^\3\2\2\2\u01e2\u01e3\7\'\2\2\u01e3`\3\2\2\2\u01e4\u01e5\7>\2\2\u01e5"+
"b\3\2\2\2\u01e6\u01e7\7@\2\2\u01e7d\3\2\2\2\u01e8\u01e9\7>\2\2\u01e9\u01ea"+
"\7?\2\2\u01eaf\3\2\2\2\u01eb\u01ec\7@\2\2\u01ec\u01ed\7?\2\2\u01edh\3"+
"\2\2\2\u01ee\u01ef\7?\2\2\u01ef\u01f0\7?\2\2\u01f0j\3\2\2\2\u01f1\u01f2"+
"\7#\2\2\u01f2\u01f3\7?\2\2\u01f3l\3\2\2\2\u01f4\u01f5\7(\2\2\u01f5n\3"+
"\2\2\2\u01f6\u01f7\7`\2\2\u01f7p\3\2\2\2\u01f8\u01f9\7~\2\2\u01f9r\3\2"+
"\2\2\u01fa\u01fb\7v\2\2\u01fb\u01fc\7q\2\2\u01fct\3\2\2\2\u01fd\u01fe"+
"\7u\2\2\u01fe\u01ff\7v\2\2\u01ff\u0200\7g\2\2\u0200\u0201\7r\2\2\u0201"+
"v\3\2\2\2\u0202\u0203\7c\2\2\u0203\u0204\7p\2\2\u0204\u0205\7f\2\2\u0205"+
"x\3\2\2\2\u0206\u0207\7q\2\2\u0207\u0208\7t\2\2\u0208z\3\2\2\2\u0209\u020a"+
"\7z\2\2\u020a\u020b\7q\2\2\u020b\u020c\7t\2\2\u020c|\3\2\2\2\u020d\u020e"+
"\7p\2\2\u020e\u020f\7q\2\2\u020f\u0210\7v\2\2\u0210~\3\2\2\2\u0211\u0212"+
"\7*\2\2\u0212\u0080\3\2\2\2\u0213\u0214\7+\2\2\u0214\u0082\3\2\2\2\u0215"+
"\u0216\7c\2\2\u0216\u0217\7u\2\2\u0217\u0084\3\2\2\2\u0218\u0219\7B\2"+
"\2\u0219\u0086\3\2\2\2\u021a\u021b\7t\2\2\u021b\u021c\7g\2\2\u021c\u021d"+
"\7v\2\2\u021d\u021e\7w\2\2\u021e\u021f\7t\2\2\u021f\u0220\7p\2\2\u0220"+
"\u0088\3\2\2\2\u0221\u0222\7d\2\2\u0222\u0223\7t\2\2\u0223\u0224\7g\2"+
"\2\u0224\u0225\7c\2\2\u0225\u0226\7m\2\2\u0226\u008a\3\2\2\2\u0227\u0228"+
"\7e\2\2\u0228\u0229\7q\2\2\u0229\u022a\7p\2\2\u022a\u022b\7v\2\2\u022b"+
"\u022c\7k\2\2\u022c\u022d\7p\2\2\u022d\u022e\7w\2\2\u022e\u022f\7g\2\2"+
"\u022f\u008c\3\2\2\2\u0230\u0231\7\60\2\2\u0231\u008e\3\2\2\2\u0232\u0233"+
"\7C\2\2\u0233\u0090\3\2\2\2\u0234\u0235\7Z\2\2\u0235\u0092\3\2\2\2\u0236"+
"\u0237\7[\2\2\u0237\u0094\3\2\2\2\u0238\u0239\7C\2\2\u0239\u023a\7Z\2"+
"\2\u023a\u0096\3\2\2\2\u023b\u023c\7C\2\2\u023c\u023d\7[\2\2\u023d\u0098"+
"\3\2\2\2\u023e\u023f\7Z\2\2\u023f\u0240\7[\2\2\u0240\u009a\3\2\2\2\u0241"+
"\u0242\7R\2\2\u0242\u0243\7e\2\2\u0243\u009c\3\2\2\2\u0244\u0245\7R\2"+
"\2\u0245\u0246\7|\2\2\u0246\u009e\3\2\2\2\u0247\u0248\7R\2\2\u0248\u0249"+
"\7p\2\2\u0249\u00a0\3\2\2\2\u024a\u024b\7R\2\2\u024b\u024c\7x\2\2\u024c"+
"\u00a2\3\2\2\2\u024d\u024e\7\60\2\2\u024e\u024f\7y\2\2\u024f\u00a4\3\2"+
"\2\2\u0250\u0251\7v\2\2\u0251\u0252\7t\2\2\u0252\u0253\7w\2\2\u0253\u0254"+
"\7g\2\2\u0254\u00a6\3\2\2\2\u0255\u0256\7h\2\2\u0256\u0257\7c\2\2\u0257"+
"\u0258\7n\2\2\u0258\u0259\7u\2\2\u0259\u025a\7g\2\2\u025a\u00a8\3\2\2"+
"\2\u025b\u025c\7\'\2\2\u025c\u025d\7c\2\2\u025d\u025e\7u\2\2\u025e\u025f"+
"\7o\2\2\u025f\u00aa\3\2\2\2\u0260\u0261\7u\2\2\u0261\u0262\7w\2\2\u0262"+
"\u0263\7d\2\2\u0263\u00ac\3\2\2\2\u0264\u0265\7/\2\2\u0265\u0266\7@\2"+
"\2\u0266\u00ae\3\2\2\2\u0267\u0268\7}\2\2\u0268\u00b0\3\2\2\2\u0269\u026a"+
"\7\177\2\2\u026a\u00b2\3\2\2\2\u026b\u026c\7c\2\2\u026c\u026d\7u\2\2\u026d"+
"\u026e\7o\2\2\u026e\u026f\7u\2\2\u026f\u0270\7w\2\2\u0270\u0271\7d\2\2"+
"\u0271\u00b4\3\2\2\2\u0272\u0273\7e\2\2\u0273\u0274\7n\2\2\u0274\u0275"+
"\7q\2\2\u0275\u0276\7d\2\2\u0276\u0277\7d\2\2\u0277\u0278\7g\2\2\u0278"+
"\u0279\7t\2\2\u0279\u027a\7u\2\2\u027a\u00b6\3\2\2\2\u027b\u027c\7k\2"+
"\2\u027c\u027d\7h\2\2\u027d\u00b8\3\2\2\2\u027e\u027f\7g\2\2\u027f\u0280"+
"\7n\2\2\u0280\u0281\7u\2\2\u0281\u0282\7g\2\2\u0282\u00ba\3\2\2\2\u0283"+
"\u0284\7k\2\2\u0284\u0285\7h\2\2\u0285\u0286\7a\2\2\u0286\u0287\7e\2\2"+
"\u0287\u0288\7u\2\2\u0288\u00bc\3\2\2\2\u0289\u028a\7k\2\2\u028a\u028b"+
"\7h\2\2\u028b\u028c\7a\2\2\u028c\u028d\7e\2\2\u028d\u028e\7e\2\2\u028e"+
"\u00be\3\2\2\2\u028f\u0290\7k\2\2\u0290\u0291\7h\2\2\u0291\u0292\7a\2"+
"\2\u0292\u0293\7g\2\2\u0293\u0294\7s\2\2\u0294\u00c0\3\2\2\2\u0295\u0296"+
"\7k\2\2\u0296\u0297\7h\2\2\u0297\u0298\7a\2\2\u0298\u0299\7|\2\2\u0299"+
"\u00c2\3\2\2\2\u029a\u029b\7k\2\2\u029b\u029c\7h\2\2\u029c\u029d\7a\2"+
"\2\u029d\u029e\7p\2\2\u029e\u029f\7g\2\2\u029f\u00c4\3\2\2\2\u02a0\u02a1"+
"\7k\2\2\u02a1\u02a2\7h\2\2\u02a2\u02a3\7a\2\2\u02a3\u02a4\7p\2\2\u02a4"+
"\u02a5\7|\2\2\u02a5\u00c6\3\2\2\2\u02a6\u02a7\7k\2\2\u02a7\u02a8\7h\2"+
"\2\u02a8\u02a9\7a\2\2\u02a9\u02aa\7r\2\2\u02aa\u02ab\7n\2\2\u02ab\u00c8"+
"\3\2\2\2\u02ac\u02ad\7k\2\2\u02ad\u02ae\7h\2\2\u02ae\u02af\7a\2\2\u02af"+
"\u02b0\7r\2\2\u02b0\u02b1\7q\2\2\u02b1\u02b2\7u\2\2\u02b2\u00ca\3\2\2"+
"\2\u02b3\u02b4\7k\2\2\u02b4\u02b5\7h\2\2\u02b5\u02b6\7a\2\2\u02b6\u02b7"+
"\7o\2\2\u02b7\u02b8\7k\2\2\u02b8\u00cc\3\2\2\2\u02b9\u02ba\7k\2\2\u02ba"+
"\u02bb\7h\2\2\u02bb\u02bc\7a\2\2\u02bc\u02bd\7p\2\2\u02bd\u02be\7g\2\2"+
"\u02be\u02bf\7i\2\2\u02bf\u00ce\3\2\2\2\u02c0\u02c1\7k\2\2\u02c1\u02c2"+
"\7h\2\2\u02c2\u02c3\7a\2\2\u02c3\u02c4\7x\2\2\u02c4\u02c5\7u\2\2\u02c5"+
"\u00d0\3\2\2\2\u02c6\u02c7\7k\2\2\u02c7\u02c8\7h\2\2\u02c8\u02c9\7a\2"+
"\2\u02c9\u02ca\7x\2\2\u02ca\u02cb\7e\2\2\u02cb\u00d2\3\2\2\2\u02cc\u02cd"+
"\7h\2\2\u02cd\u02ce\7q\2\2\u02ce\u02cf\7t\2\2\u02cf\u00d4\3\2\2\2\u02d0"+
"\u02d1\7k\2\2\u02d1\u02d2\7p\2\2\u02d2\u00d6\3\2\2\2\u02d3\u02d4\7y\2"+
"\2\u02d4\u02d5\7j\2\2\u02d5\u02d6\7k\2\2\u02d6\u02d7\7n\2\2\u02d7\u02d8"+
"\7g\2\2\u02d8\u00d8\3\2\2\2\u02d9\u02da\7t\2\2\u02da\u02db\7g\2\2\u02db"+
"\u02dc\7r\2\2\u02dc\u02dd\7g\2\2\u02dd\u02de\7c\2\2\u02de\u02df\7v\2\2"+
"\u02df\u00da\3\2\2\2\u02e0\u02e1\7w\2\2\u02e1\u02e2\7p\2\2\u02e2\u02e3"+
"\7v\2\2\u02e3\u02e4\7k\2\2\u02e4\u02e5\7n\2\2\u02e5\u00dc\3\2\2\2\u02e6"+
"\u02ea\t\2\2\2\u02e7\u02e9\t\3\2\2\u02e8\u02e7\3\2\2\2\u02e9\u02ec\3\2"+
"\2\2\u02ea\u02e8\3\2\2\2\u02ea\u02eb\3\2\2\2\u02eb\u02ed\3\2\2\2\u02ec"+
"\u02ea\3\2\2\2\u02ed\u02ee\5\u00dfp\2\u02ee\u02ef\3\2\2\2\u02ef\u02f0"+
"\bo\2\2\u02f0\u00de\3\2\2\2\u02f1\u02f5\7=\2\2\u02f2\u02f4\n\2\2\2\u02f3"+
"\u02f2\3\2\2\2\u02f4\u02f7\3\2\2\2\u02f5\u02f3\3\2\2\2\u02f5\u02f6\3\2"+

File diff suppressed because it is too large Load Diff

View File

@ -325,6 +325,16 @@ class StackVm(private var traceOutputFile: String?) {
checkDt(value, DataType.UBYTE)
TODO("pop_memwrite $value to $address")
}
Opcode.POP_INC_MEMORY -> {
val address = evalstack.pop()
checkDt(address, DataType.UWORD)
TODO("pop_inc_memory $address")
}
Opcode.POP_DEC_MEMORY -> {
val address = evalstack.pop()
checkDt(address, DataType.UWORD)
TODO("pop_dec_memory $address")
}
Opcode.ADD_UB -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.UBYTE)

View File

@ -421,11 +421,11 @@ Normally memory locations are accessed by a *memory mapped* name, such as ``c64.
as the memory mapped address $d021.
If you want to access a memory location directly (by using the address itself), without defining
a memory mapped location, you can do so by prefixing the address with ``@``::
a memory mapped location, you can do so by enclosing the address in ``@(...)``::
A = @$d020 ; set the A register to the current c64 screen border color ("peek(53280)")
@$d020 = 0 ; set the c64 screen border to black ("poke 53280,0")
@(vic+$20) = 6 ; you can also use expressions to 'calculate' the address
A = @($d020) ; set the A register to the current c64 screen border color ("peek(53280)")
@($d020) = 0 ; set the c64 screen border to black ("poke 53280,0")
@(vic+$20) = 6 ; you can also use expressions to 'calculate' the address
Expressions

View File

@ -300,11 +300,11 @@ should be the *memory address* where the value is located::
Direct access to memory locations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Instead of defining a memory mapped name for a specific memory location, you can also
directly access the memory. Prefix a numeric expression or literal by ``@`` to do that::
directly access the memory. Enclose a numeric expression or literal with ``@(...)`` to do that::
A = @$d020 ; set the A register to the current c64 screen border color ("peek(53280)")
@$d020 = 0 ; set the c64 screen border to black ("poke 53280,0")
@(vic+$20) = 6 ; a dynamic expression to 'calculate' the address
A = @($d020) ; set the A register to the current c64 screen border color ("peek(53280)")
@($d020) = 0 ; set the c64 screen border to black ("poke 53280,0")
@(vic+$20) = 6 ; a dynamic expression to 'calculate' the address
Constants