taking the address of strings and arrays

This commit is contained in:
Irmen de Jong 2018-11-23 00:31:21 +01:00
parent 069f6ea372
commit 6c8354aef0
8 changed files with 152 additions and 40 deletions

View File

@ -14,6 +14,7 @@ sub start() {
memory uword memaddr = $c000 memory uword memaddr = $c000
uword[2] wordarray uword[2] wordarray
byte b1 byte b1
memory byte mb1 = $c991
str stringvar = "??????????\n\n\nnext line\r\r\rnext line after carriagereturn" str stringvar = "??????????\n\n\nnext line\r\r\rnext line after carriagereturn"
@ -34,29 +35,38 @@ sub start() {
secretnumber = '@' secretnumber = '@'
secretnumber = '\r' secretnumber = '\r'
testword = stringvar ; @todo fix str address assignment testword = stringvar
testword = "stringstring" ; @todo fix str address assignment testword = wordarray
freadstr_arg = stringvar ; @todo fix str address assignment freadstr_arg = stringvar
freadstr_arg = "stringstring" ; @todo fix str address assignment freadstr_arg = wordarray
secretnumber = "stringstring2222" ; @todo fix str address assignment wordarray[1] = stringvar
wordarray[1] = wordarray
wordarray[b1] = stringvar
wordarray[b1] = wordarray
wordarray[mb1] = stringvar
wordarray[mb1] = wordarray
; testword = "stringstring" ; @todo asmgen for this
; freadstr_arg = "stringstring" ; @todo asmgen for this
; freadstr_arg = "stringstring2222" ; @todo asmgen for this
; wordarray[1] = "stringstring" ; @todo asmgen for this
address =c64.MEMBOT(1, 40000.w) ; ok! ; address =c64.MEMBOT(1, 40000.w) ; ok!
address =c64.MEMBOT(1, address) ; ok! ; address =c64.MEMBOT(1, address) ; ok!
address =c64.MEMBOT(1, memaddr) ; ok! ; address =c64.MEMBOT(1, memaddr) ; ok!
;
A, Y =c64.GETADR() ; ok! ; A, Y =c64.GETADR() ; ok!
Y, A =c64.GETADR() ; ok! ; Y, A =c64.GETADR() ; ok!
address = c64flt.GETADRAY() ; ok! ; address = c64flt.GETADRAY() ; ok!
memaddr = c64flt.GETADRAY() ; ok! ; memaddr = c64flt.GETADRAY() ; ok!
wordarray[1] = c64flt.GETADRAY() ; ok! ; wordarray[1] = c64flt.GETADRAY() ; ok!
v1, v2 =c64.GETADR() ; ok! ; v1, v2 =c64.GETADR() ; ok!
address =c64.IOBASE() ; ok! ; address =c64.IOBASE() ; ok!
A = c64.CHRIN() ; ok ! ; A = c64.CHRIN() ; ok !
X = c64.CHRIN() ; ok ! ; X = c64.CHRIN() ; ok !
Y = c64.CHRIN() ; ok! ; Y = c64.CHRIN() ; ok!
v1 = c64.CHRIN() ; ok ! ; v1 = c64.CHRIN() ; ok !
return return
} }

View File

@ -338,26 +338,36 @@ class AstChecker(private val namespace: INameScope,
if(target.identifier!=null) { if(target.identifier!=null) {
val targetName = target.identifier.nameInSource val targetName = target.identifier.nameInSource
val targetSymbol = namespace.lookup(targetName, assignment) val targetSymbol = namespace.lookup(targetName, assignment)
when { when (targetSymbol) {
targetSymbol == null -> { null -> {
checkResult.add(ExpressionError("undefined symbol: ${targetName.joinToString(".")}", assignment.position)) checkResult.add(ExpressionError("undefined symbol: ${targetName.joinToString(".")}", assignment.position))
return assignment return assignment
} }
targetSymbol !is VarDecl -> { !is VarDecl -> {
checkResult.add(SyntaxError("assignment LHS must be register or variable", assignment.position)) checkResult.add(SyntaxError("assignment LHS must be register or variable", assignment.position))
return assignment return assignment
} }
targetSymbol.type == VarDeclType.CONST -> { else -> {
if(targetSymbol.type == VarDeclType.CONST) {
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position)) checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
return assignment return assignment
} }
else -> {} if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes) {
if(targetSymbol.datatype==DataType.UWORD)
return assignment // array can be assigned to UWORD (it's address should be taken as the value then)
}
}
} }
} }
// it is not possible to assign a new arrayspec to something. // it is only possible to assign an array to something that is an UWORD or UWORD array (in which case the address of the array value is used as the value)
if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes) if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes) {
checkResult.add(SyntaxError("it's not possible to assign an arrayspec literal value to something, use it as a variable decl initializer instead", assignment.position)) // the UWORD case has been handled above already, check for UWORD array
val arrayVar = target.arrayindexed?.identifier?.targetStatement(namespace)
if(arrayVar is VarDecl && arrayVar.datatype==DataType.ARRAY_UW)
return assignment
checkResult.add(SyntaxError("it's not possible to assign an array to something other than an UWORD, use it as a variable decl initializer instead", assignment.position))
}
if(assignment.aug_op!=null) { if(assignment.aug_op!=null) {
// check augmented assignment: // check augmented assignment:
@ -844,10 +854,12 @@ class AstChecker(private val namespace: INameScope,
return err("value '$number' out of range for byte") return err("value '$number' out of range for byte")
} }
DataType.UWORD -> { DataType.UWORD -> {
if(value.isString || value.isArray) // string or array are assignable to uword; their memory address is used.
return true
val number = value.asIntegerValue ?: return if (value.floatvalue!=null) val number = value.asIntegerValue ?: return if (value.floatvalue!=null)
err("unsigned word value expected instead of float; possible loss of precision") err("unsigned word value expected instead of float; possible loss of precision")
else else
err("unsigned word value expected") err("unsigned word value or address expected")
if (number < 0 || number > 65535) if (number < 0 || number > 65535)
return err("value '$number' out of range for unsigned word") return err("value '$number' out of range for unsigned word")
} }
@ -950,7 +962,7 @@ class AstChecker(private val namespace: INameScope,
DataType.BYTE -> sourceDatatype==DataType.BYTE DataType.BYTE -> sourceDatatype==DataType.BYTE
DataType.UBYTE -> sourceDatatype==DataType.UBYTE DataType.UBYTE -> sourceDatatype==DataType.UBYTE
DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.WORD DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.WORD
DataType.UWORD -> sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.UWORD DataType.UWORD -> sourceDatatype in setOf(DataType.UBYTE, DataType.UWORD, DataType.STR, DataType.STR_S) || sourceDatatype in ArrayDatatypes
DataType.FLOAT -> sourceDatatype in NumericDatatypes DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype==DataType.STR DataType.STR -> sourceDatatype==DataType.STR
DataType.STR_S -> sourceDatatype==DataType.STR_S DataType.STR_S -> sourceDatatype==DataType.STR_S

View File

@ -1180,13 +1180,44 @@ private class StatementTranslator(private val prog: IntermediateProgram,
when(targetDt) { when(targetDt) {
DataType.UBYTE, DataType.BYTE -> DataType.UBYTE, DataType.BYTE ->
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.UWORD, DataType.WORD -> { DataType.WORD -> {
when (valueDt) { when (valueDt) {
DataType.UBYTE -> prog.instr(Opcode.UB2UWORD) DataType.UBYTE -> prog.instr(Opcode.UB2UWORD)
DataType.BYTE -> prog.instr(Opcode.B2WORD) DataType.BYTE -> prog.instr(Opcode.B2WORD)
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
} }
} }
DataType.UWORD -> {
when (valueDt) {
DataType.UBYTE -> prog.instr(Opcode.UB2UWORD)
DataType.BYTE -> prog.instr(Opcode.B2WORD)
DataType.STR, DataType.STR_S -> {
when(stmt.value) {
is LiteralValue -> {
val lv = stmt.value as LiteralValue
prog.removeLastInstruction()
prog.instr(Opcode.PUSH_ADDR_STR, Value(lv.type, lv.heapId!!))
}
is IdentifierReference -> {
val vardecl = (stmt.value as IdentifierReference).targetStatement(namespace) as VarDecl
prog.removeLastInstruction()
prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname)
}
else -> throw CompilerException("can only take address of a literal string value or a string/array variable")
}
}
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.ARRAY_W, DataType.ARRAY_UW, DataType.ARRAY_F -> {
if (stmt.value is IdentifierReference) {
val vardecl = (stmt.value as IdentifierReference).targetStatement(namespace) as VarDecl
prog.removeLastInstruction()
prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname)
}
else
throw CompilerException("can only take address of a literal string value or a string/array variable")
}
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
}
}
DataType.FLOAT -> { DataType.FLOAT -> {
when (valueDt) { when (valueDt) {
DataType.UBYTE -> prog.instr(Opcode.UB2FLOAT) DataType.UBYTE -> prog.instr(Opcode.UB2FLOAT)

View File

@ -295,6 +295,10 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
currentBlock.instructions.add(Instruction(Opcode.LINE, callLabel = "${position.line} ${position.file}")) currentBlock.instructions.add(Instruction(Opcode.LINE, callLabel = "${position.line} ${position.file}"))
} }
fun removeLastInstruction() {
currentBlock.instructions.removeAt(currentBlock.instructions.lastIndex)
}
fun symbolDef(name: String, value: Int) { fun symbolDef(name: String, value: Int) {
currentBlock.integerConstants[name] = value currentBlock.integerConstants[name] = value
} }

View File

@ -17,6 +17,8 @@ enum class Opcode {
PUSH_REGAX_WORD, // push registers A/X as a 16-bit word PUSH_REGAX_WORD, // push registers A/X as a 16-bit word
PUSH_REGAY_WORD, // push registers A/Y as a 16-bit word PUSH_REGAY_WORD, // push registers A/Y as a 16-bit word
PUSH_REGXY_WORD, // push registers X/Y as a 16-bit word PUSH_REGXY_WORD, // push registers X/Y as a 16-bit word
PUSH_ADDR_STR, // push the address of the string value (literal)
PUSH_ADDR_HEAPVAR, // push the address of the variable that's on the heap (string or array)
// popping values off the (evaluation) stack, possibly storing them in another location // popping values off the (evaluation) stack, possibly storing them in another location
DISCARD_BYTE, // discard top byte value DISCARD_BYTE, // discard top byte value
@ -227,7 +229,7 @@ val opcodesWithVarArgument = setOf(
Opcode.ROL_VAR_BYTE, Opcode.ROL_VAR_WORD, Opcode.ROR_VAR_BYTE, Opcode.ROR_VAR_WORD, Opcode.ROL_VAR_BYTE, Opcode.ROL_VAR_WORD, Opcode.ROR_VAR_BYTE, Opcode.ROR_VAR_WORD,
Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD, Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD,
Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT, Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT,
Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_WORD, Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_ADDR_HEAPVAR,
Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT, Opcode.READ_INDEXED_VAR_BYTE, Opcode.READ_INDEXED_VAR_WORD, Opcode.READ_INDEXED_VAR_FLOAT,
Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT Opcode.WRITE_INDEXED_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD, Opcode.WRITE_INDEXED_VAR_FLOAT
) )

View File

@ -1298,6 +1298,15 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
sty ${segment[1].callLabel}+1 sty ${segment[1].callLabel}+1
""" """
}, },
// var = address-of other var
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.POP_VAR_WORD)) { segment ->
"""
lda #<${segment[0].callLabel}
ldy #>${segment[0].callLabel}
sta ${segment[1].callLabel}
sty ${segment[1].callLabel}+1
"""
},
// var = mem ubyte // var = mem ubyte
AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2UWORD, Opcode.POP_VAR_WORD)) { segment ->
" lda ${hexVal(segment[0])} | sta ${segment[2].callLabel} | lda #0 | sta ${segment[2].callLabel}+1" " lda ${hexVal(segment[0])} | sta ${segment[2].callLabel} | lda #0 | sta ${segment[2].callLabel}+1"
@ -1393,6 +1402,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_WORD)) { segment ->
" lda ${segment[0].callLabel} || sta ${hexVal(segment[1])} | lda ${segment[0].callLabel}+1 | sta ${hexValPlusOne(segment[1])}" " lda ${segment[0].callLabel} || sta ${hexVal(segment[1])} | lda ${segment[0].callLabel}+1 | sta ${hexValPlusOne(segment[1])}"
}, },
// mem uword = address-of var
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.POP_MEM_WORD)) { segment ->
" lda #<${segment[0].callLabel} || sta ${hexVal(segment[1])} | lda #>${segment[0].callLabel} | sta ${hexValPlusOne(segment[1])}"
},
// mem (u)word = mem (u)word // mem (u)word = mem (u)word
AsmPattern( AsmPattern(
listOf(Opcode.PUSH_MEM_UW, Opcode.POP_MEM_WORD), listOf(Opcode.PUSH_MEM_UW, Opcode.POP_MEM_WORD),
@ -1607,6 +1620,20 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
sta ${segment[2].callLabel}+1,y sta ${segment[2].callLabel}+1,y
""" """
}, },
// uwordarray[index mem] = address-of var
AsmPattern(
listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.PUSH_MEM_B, Opcode.WRITE_INDEXED_VAR_WORD),
listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.PUSH_MEM_UB, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
"""
lda ${hexVal(segment[1])}
asl a
tay
lda #<${segment[0].callLabel}
sta ${segment[2].callLabel},y
lda #>${segment[0].callLabel}
sta ${segment[2].callLabel}+1,y
"""
},
// uwordarray[index] = ubytevar // uwordarray[index] = ubytevar
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.UB2UWORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.UB2UWORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val index = segment[2].arg!!.integerValue()*2 val index = segment[2].arg!!.integerValue()*2
@ -1898,6 +1925,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
val index = segment[1].arg!!.integerValue()*2 val index = segment[1].arg!!.integerValue()*2
" lda ${segment[0].callLabel} | sta ${segment[2].callLabel}+$index | lda ${segment[0].callLabel}+1 | sta ${segment[2].callLabel}+${index+1}" " lda ${segment[0].callLabel} | sta ${segment[2].callLabel}+$index | lda ${segment[0].callLabel}+1 | sta ${segment[2].callLabel}+${index+1}"
}, },
// uwordarray[index] = address-of var
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val index = segment[1].arg!!.integerValue()*2
" lda #<${segment[0].callLabel} | sta ${segment[2].callLabel}+$index | lda #>${segment[0].callLabel} | sta ${segment[2].callLabel}+${index+1}"
},
// uwordarray[index] = mem uword // uwordarray[index] = mem uword
AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val index = segment[1].arg!!.integerValue()*2 val index = segment[1].arg!!.integerValue()*2
@ -1967,6 +1999,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
} }
" $loadIndexY | lda ${segment[0].callLabel} | sta ${segment[2].callLabel},y | lda ${segment[0].callLabel}+1 | sta ${segment[2].callLabel}+1,y" " $loadIndexY | lda ${segment[0].callLabel} | sta ${segment[2].callLabel},y | lda ${segment[0].callLabel}+1 | sta ${segment[2].callLabel}+1,y"
}, },
// uwordarray[indexvar] = address-of var
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val loadIndexY = when(segment[1].callLabel) {
"A" -> " asl a | tay"
"X" -> " txa | asl a | tay"
"Y" -> " tya | asl a | tay"
else -> " lda ${segment[1].callLabel} | asl a | tay"
}
" $loadIndexY | lda #<${segment[0].callLabel} | sta ${segment[2].callLabel},y | lda #>${segment[0].callLabel} | sta ${segment[2].callLabel}+1,y"
},
// uwordarray[indexvar] = mem ubyte // uwordarray[indexvar] = mem ubyte
AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2UWORD, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2UWORD, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
val loadIndexY = when(segment[2].callLabel) { val loadIndexY = when(segment[2].callLabel) {
@ -2505,15 +2547,15 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}, },
// AX register pair = word var // AX register pair = word var
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGAX_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGAX_WORD)) { segment ->
" lda #<${segment[0].callLabel} | ldx #>${segment[0].callLabel}" " lda ${segment[0].callLabel} | ldx ${segment[0].callLabel}+1"
}, },
// AY register pair = word var // AY register pair = word var
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGAY_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGAY_WORD)) { segment ->
" lda #<${segment[0].callLabel} | ldy #>${segment[0].callLabel}" " lda ${segment[0].callLabel} | ldy ${segment[0].callLabel}+1"
}, },
// XY register pair = word var // XY register pair = word var
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGXY_WORD)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGXY_WORD)) { segment ->
" ldx #<${segment[0].callLabel} | ldy #>${segment[0].callLabel}" " ldx ${segment[0].callLabel} | ldy ${segment[0].callLabel}+1"
}, },
// AX register pair = mem word // AX register pair = mem word
AsmPattern( AsmPattern(

View File

@ -1323,6 +1323,19 @@ class StackVm(private var traceOutputFile: String?) {
P_irqd = evalstack.pop().asBooleanValue P_irqd = evalstack.pop().asBooleanValue
} }
Opcode.INLINE_ASSEMBLY -> throw VmExecutionException("stackVm doesn't support executing inline assembly code") Opcode.INLINE_ASSEMBLY -> throw VmExecutionException("stackVm doesn't support executing inline assembly code")
Opcode.PUSH_ADDR_HEAPVAR -> {
val heapId = variables[ins.callLabel]!!.heapId
if(heapId<=0)
throw VmExecutionException("expected variable on heap")
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable
}
Opcode.PUSH_ADDR_STR -> {
val heapId = ins.arg!!.heapId
if(heapId<=0)
throw VmExecutionException("expected string to be on heap")
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string
}
//else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}") //else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}")
} }

View File

@ -207,8 +207,6 @@ Array types are also supported. They can be made of bytes, words and floats::
Right now, the array should be small enough to be indexable by a single byte index. Right now, the array should be small enough to be indexable by a single byte index.
This means byte arrays should be <= 256 elements, word arrays <= 128 elements, and float This means byte arrays should be <= 256 elements, word arrays <= 128 elements, and float
arrays <= 51 elements. This limit may or may not be lifted in a future version. arrays <= 51 elements. This limit may or may not be lifted in a future version.
Matrixes can be indexed in each dimension only by a byte as well, this also means
their maximum size is 65536 elements (bytes).
Note that the various keywords for the data type and variable type (``byte``, ``word``, ``const``, etc.) Note that the various keywords for the data type and variable type (``byte``, ``word``, ``const``, etc.)
@ -300,7 +298,7 @@ When declaring values with an initial value, this value will be set into the var
the program reaches the declaration again. This can be in loops, multiple subroutine calls, the program reaches the declaration again. This can be in loops, multiple subroutine calls,
or even multiple invocations of the entire program. or even multiple invocations of the entire program.
This only works for simple types, *and not for string variables, arrays and matrices*. This only works for simple types, *and not for string variables and arrays*.
It is assumed these are left unchanged by the program. It is assumed these are left unchanged by the program.
If you do modify them in-place, you should take care yourself that they work as If you do modify them in-place, you should take care yourself that they work as
expected when the program is restarted. expected when the program is restarted.