mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 08:29:25 +00:00
implemented array indexing
This commit is contained in:
parent
8f26fdef61
commit
0cdae48ce7
@ -123,7 +123,6 @@ postincrdecr : assign_target operator = ('++' | '--') ;
|
|||||||
|
|
||||||
expression :
|
expression :
|
||||||
'(' expression ')'
|
'(' expression ')'
|
||||||
| expression arrayspec
|
|
||||||
| functioncall
|
| functioncall
|
||||||
| prefix = ('+'|'-'|'~') expression
|
| prefix = ('+'|'-'|'~') expression
|
||||||
| left = expression bop = '**' right = expression
|
| left = expression bop = '**' right = expression
|
||||||
@ -143,9 +142,15 @@ expression :
|
|||||||
| register
|
| register
|
||||||
| identifier
|
| identifier
|
||||||
| scoped_identifier
|
| scoped_identifier
|
||||||
|
| arrayindexed
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
arrayindexed :
|
||||||
|
(identifier | scoped_identifier | register) arrayspec
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
functioncall :
|
functioncall :
|
||||||
(identifier | scoped_identifier) '(' expression_list? ')'
|
(identifier | scoped_identifier) '(' expression_list? ')'
|
||||||
;
|
;
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
; sub VECTOR (dir: Pc, userptr: XY) -> (X, A?, Y?) = $FF8D ; read/set I/O vector table
|
|
||||||
|
|
||||||
|
|
||||||
asmsub VECTOR (dir: byte @ A, userptr: word @ XY) -> clobbers(A,X,Y) -> (byte @ X) = $ff8d
|
|
||||||
; asmsub VECTOR (dir: byte @ Pc, userptr: word @ XY) -> byte @ X, clobbers @ A, clobbers @ Y = $ff8d
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
|
byte[100] array
|
||||||
|
byte[4,5] mvar
|
||||||
|
|
||||||
|
A=AX[2]
|
||||||
|
A=AY[2]
|
||||||
|
A=XY[2]
|
||||||
|
|
||||||
|
A=array[98]
|
||||||
|
A=array[99]
|
||||||
|
A=mvar[13]
|
||||||
|
A=mvar[2,3]
|
||||||
|
A=mvar[Y,X]
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -216,6 +216,12 @@ interface IAstProcessor {
|
|||||||
fun process(asmSubroutine: AsmSubroutine): IStatement {
|
fun process(asmSubroutine: AsmSubroutine): IStatement {
|
||||||
return asmSubroutine
|
return asmSubroutine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun process(arrayIndexedExpression: ArrayIndexedExpression): IExpression {
|
||||||
|
arrayIndexedExpression.identifier?.process(this)
|
||||||
|
arrayIndexedExpression.array.process(this)
|
||||||
|
return arrayIndexedExpression
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -805,6 +811,39 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ArrayIndexedExpression(val identifier: IdentifierReference?,
|
||||||
|
val register: Register?,
|
||||||
|
var array: ArraySpec,
|
||||||
|
override val position: Position) : IExpression {
|
||||||
|
override lateinit var parent: Node
|
||||||
|
override fun linkParents(parent: Node) {
|
||||||
|
this.parent = parent
|
||||||
|
identifier?.linkParents(this)
|
||||||
|
array.linkParents(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isIterable(namespace: INameScope, heap: HeapValues) = false
|
||||||
|
override fun constValue(namespace: INameScope, heap: HeapValues): LiteralValue? = null
|
||||||
|
override fun process(processor: IAstProcessor): IExpression = processor.process(this)
|
||||||
|
override fun referencesIdentifier(name: String) = identifier?.referencesIdentifier(name) ?: false
|
||||||
|
|
||||||
|
override fun resultingDatatype(namespace: INameScope, heap: HeapValues): DataType? {
|
||||||
|
if (register != null)
|
||||||
|
return DataType.BYTE
|
||||||
|
val target = identifier?.targetStatement(namespace)
|
||||||
|
if (target is VarDecl) {
|
||||||
|
return when (target.datatype) {
|
||||||
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||||
|
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||||
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw FatalAstException("cannot get indexed element on $target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private data class NumericLiteral(val number: Number, val datatype: DataType)
|
private data class NumericLiteral(val number: Number, val datatype: DataType)
|
||||||
|
|
||||||
|
|
||||||
@ -1755,9 +1794,19 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
|
|||||||
if(childCount==3 && children[0].text=="(" && children[2].text==")")
|
if(childCount==3 && children[0].text=="(" && children[2].text==")")
|
||||||
return expression(0).toAst() // expression within ( )
|
return expression(0).toAst() // expression within ( )
|
||||||
|
|
||||||
|
if(arrayindexed()!=null)
|
||||||
|
return arrayindexed().toAst()
|
||||||
|
|
||||||
throw FatalAstException(text)
|
throw FatalAstException(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun prog8Parser.ArrayindexedContext.toAst(): IExpression {
|
||||||
|
return ArrayIndexedExpression(identifier()?.toAst() ?: scoped_identifier()?.toAst(),
|
||||||
|
register()?.toAst(),
|
||||||
|
arrayspec().toAst(),
|
||||||
|
toPosition())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun prog8Parser.Expression_listContext.toAst() = expression().map{ it.toAst() }
|
private fun prog8Parser.Expression_listContext.toAst() = expression().map{ it.toAst() }
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
if(assignment.value is FunctionCall)
|
if(assignment.value is FunctionCall)
|
||||||
checkResult.add(ExpressionError("function call doesn't return a value to use in assignment", assignment.value.position))
|
checkResult.add(ExpressionError("function call doesn't return a value to use in assignment", assignment.value.position))
|
||||||
else
|
else
|
||||||
checkResult.add(ExpressionError("assignment source ${assignment.value} is no value or has no proper datatype", assignment.value.position))
|
checkResult.add(ExpressionError("assignment value is invalid or has no proper datatype", assignment.value.position))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.position)
|
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.position)
|
||||||
@ -561,6 +561,34 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
return super.process(postIncrDecr)
|
return super.process(postIncrDecr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun process(arrayIndexedExpression: ArrayIndexedExpression): IExpression {
|
||||||
|
val reg=arrayIndexedExpression.register
|
||||||
|
if(reg==null) {
|
||||||
|
val target = arrayIndexedExpression.identifier!!.targetStatement(namespace)
|
||||||
|
if(target is VarDecl) {
|
||||||
|
if(target.datatype==DataType.BYTE || target.datatype==DataType.WORD || target.datatype==DataType.FLOAT)
|
||||||
|
checkResult.add(SyntaxError("array indexing requires an iterable variable", arrayIndexedExpression.position))
|
||||||
|
val arraysize = target.arrayspec?.size()
|
||||||
|
if(arraysize!=null) {
|
||||||
|
// check out of bounds
|
||||||
|
if((arrayIndexedExpression.array.y as? LiteralValue)?.asIntegerValue != null) {
|
||||||
|
throw FatalAstException("constant y dimension of index should have been const-folded with x into one value")
|
||||||
|
}
|
||||||
|
val index = (arrayIndexedExpression.array.x as? LiteralValue)?.asIntegerValue
|
||||||
|
if(index!=null && (index<0 || index>=arraysize))
|
||||||
|
checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.array.position))
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
checkResult.add(SyntaxError("array indexing requires a variable to act upon", arrayIndexedExpression.position))
|
||||||
|
} else if(reg==Register.A || reg==Register.X || reg==Register.Y) {
|
||||||
|
checkResult.add(SyntaxError("array indexing on registers requires register pair variable", arrayIndexedExpression.position))
|
||||||
|
} else if(arrayIndexedExpression.array.y!=null) {
|
||||||
|
checkResult.add(SyntaxError("array indexing on registers can only use one index dimension", arrayIndexedExpression.position))
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.process(arrayIndexedExpression)
|
||||||
|
}
|
||||||
|
|
||||||
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: IStatement): IStatement? {
|
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: IStatement): IStatement? {
|
||||||
val targetStatement = target.targetStatement(namespace)
|
val targetStatement = target.targetStatement(namespace)
|
||||||
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)
|
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)
|
||||||
|
@ -417,9 +417,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
|
|
||||||
private fun translate(expr: IExpression) {
|
private fun translate(expr: IExpression) {
|
||||||
when(expr) {
|
when(expr) {
|
||||||
is RegisterExpr -> {
|
is RegisterExpr -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = expr.register.toString())
|
||||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = expr.register.toString())
|
|
||||||
}
|
|
||||||
is PrefixExpression -> {
|
is PrefixExpression -> {
|
||||||
translate(expr.expression)
|
translate(expr.expression)
|
||||||
translatePrefixOperator(expr.operator)
|
translatePrefixOperator(expr.operator)
|
||||||
@ -444,29 +442,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is IdentifierReference -> {
|
is IdentifierReference -> translate(expr)
|
||||||
val target = expr.targetStatement(namespace)
|
is ArrayIndexedExpression -> translate(expr)
|
||||||
when(target) {
|
|
||||||
is VarDecl -> {
|
|
||||||
when(target.type) {
|
|
||||||
VarDeclType.VAR ->
|
|
||||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = target.scopedname)
|
|
||||||
VarDeclType.CONST ->
|
|
||||||
throw CompilerException("const ref should have been const-folded away")
|
|
||||||
VarDeclType.MEMORY -> {
|
|
||||||
when(target.datatype){
|
|
||||||
DataType.BYTE -> stackvmProg.instr(Opcode.PUSH_MEM, Value(DataType.WORD, (target.value as LiteralValue).asNumericValue!!))
|
|
||||||
DataType.WORD -> stackvmProg.instr(Opcode.PUSH_MEM_W, Value(DataType.WORD, (target.value as LiteralValue).asNumericValue!!))
|
|
||||||
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH_MEM_F, Value(DataType.WORD, (target.value as LiteralValue).asNumericValue!!))
|
|
||||||
else -> TODO("invalid datatype for memory variable expression: $target")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else -> throw CompilerException("expression identifierref should be a vardef, not $target")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is RangeExpr -> {
|
is RangeExpr -> {
|
||||||
TODO("TRANSLATE range $expr")
|
TODO("TRANSLATE range $expr")
|
||||||
}
|
}
|
||||||
@ -491,6 +468,30 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun translate(identifierRef: IdentifierReference) {
|
||||||
|
val target = identifierRef.targetStatement(namespace)
|
||||||
|
when (target) {
|
||||||
|
is VarDecl -> {
|
||||||
|
when (target.type) {
|
||||||
|
VarDeclType.VAR ->
|
||||||
|
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = target.scopedname)
|
||||||
|
VarDeclType.CONST ->
|
||||||
|
throw CompilerException("const ref should have been const-folded away")
|
||||||
|
VarDeclType.MEMORY -> {
|
||||||
|
when (target.datatype) {
|
||||||
|
DataType.BYTE -> stackvmProg.instr(Opcode.PUSH_MEM, Value(DataType.WORD, (target.value as LiteralValue).asNumericValue!!))
|
||||||
|
DataType.WORD -> stackvmProg.instr(Opcode.PUSH_MEM_W, Value(DataType.WORD, (target.value as LiteralValue).asNumericValue!!))
|
||||||
|
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH_MEM_F, Value(DataType.WORD, (target.value as LiteralValue).asNumericValue!!))
|
||||||
|
else -> TODO("invalid datatype for memory variable expression: $target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else -> throw CompilerException("expression identifierref should be a vardef, not $target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun translate(stmt: FunctionCallStatement) {
|
private fun translate(stmt: FunctionCallStatement) {
|
||||||
stackvmProg.line(stmt.position)
|
stackvmProg.line(stmt.position)
|
||||||
val targetStmt = stmt.target.targetStatement(namespace)!!
|
val targetStmt = stmt.target.targetStatement(namespace)!!
|
||||||
@ -590,6 +591,33 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
stackvmProg.instr(opcode)
|
stackvmProg.instr(opcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun translate(arrayindexed: ArrayIndexedExpression) {
|
||||||
|
val variable = arrayindexed.identifier?.targetStatement(namespace) as? VarDecl
|
||||||
|
val variableName =
|
||||||
|
if(arrayindexed.register!=null) {
|
||||||
|
val reg=arrayindexed.register
|
||||||
|
if(reg==Register.A || reg==Register.X || reg==Register.Y)
|
||||||
|
throw CompilerException("requires register pair")
|
||||||
|
if(arrayindexed.array.y!=null)
|
||||||
|
throw CompilerException("when using an address, can only use one index dimension")
|
||||||
|
reg.toString()
|
||||||
|
} else {
|
||||||
|
variable!!.scopedname
|
||||||
|
}
|
||||||
|
translate(arrayindexed.array.x)
|
||||||
|
val y = arrayindexed.array.y
|
||||||
|
if(y!=null) {
|
||||||
|
// calc matrix index i=y*columns+x
|
||||||
|
// (the const-folding will have removed this for us when both x and y are constants)
|
||||||
|
translate(y)
|
||||||
|
stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, (variable!!.arrayspec!!.x as LiteralValue).asIntegerValue!!))
|
||||||
|
stackvmProg.instr(Opcode.MUL)
|
||||||
|
stackvmProg.instr(Opcode.ADD)
|
||||||
|
}
|
||||||
|
stackvmProg.instr(Opcode.PUSH_INDEXED_VAR, callLabel = variableName)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun createSyscall(funcname: String) {
|
private fun createSyscall(funcname: String) {
|
||||||
val function = (
|
val function = (
|
||||||
if (funcname.startsWith("_vm_"))
|
if (funcname.startsWith("_vm_"))
|
||||||
|
@ -340,6 +340,23 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
}
|
}
|
||||||
return super.process(literalValue)
|
return super.process(literalValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun process(arrayIndexedExpression: ArrayIndexedExpression): IExpression {
|
||||||
|
if(arrayIndexedExpression.array.y!=null) {
|
||||||
|
if(arrayIndexedExpression.array.size()!=null) {
|
||||||
|
// both x and y are known
|
||||||
|
// calculate the 2-dimension index i = y*columns + x
|
||||||
|
if(arrayIndexedExpression.identifier!=null) {
|
||||||
|
val x = (arrayIndexedExpression.array.x as LiteralValue).asIntegerValue!!
|
||||||
|
val y = (arrayIndexedExpression.array.y as LiteralValue).asIntegerValue!!
|
||||||
|
val variable = arrayIndexedExpression.identifier.targetStatement(namespace) as VarDecl
|
||||||
|
val index = x + y*(variable.arrayspec!!.x as LiteralValue).asIntegerValue!!
|
||||||
|
arrayIndexedExpression.array = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.array.position), null, arrayIndexedExpression.array.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.process(arrayIndexedExpression)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -101,7 +101,8 @@ class Program (val name: String,
|
|||||||
}
|
}
|
||||||
Opcode.INC_VAR, Opcode.DEC_VAR,
|
Opcode.INC_VAR, Opcode.DEC_VAR,
|
||||||
Opcode.SHR_VAR, Opcode.SHL_VAR, Opcode.ROL_VAR, Opcode.ROR_VAR,
|
Opcode.SHR_VAR, Opcode.SHL_VAR, Opcode.ROL_VAR, Opcode.ROR_VAR,
|
||||||
Opcode.ROL2_VAR, Opcode.ROR2_VAR, Opcode.POP_VAR, Opcode.PUSH_VAR -> {
|
Opcode.ROL2_VAR, Opcode.ROR2_VAR, Opcode.POP_VAR, Opcode.PUSH_VAR,
|
||||||
|
Opcode.PUSH_INDEXED_VAR -> {
|
||||||
val withoutQuotes =
|
val withoutQuotes =
|
||||||
if(args!!.startsWith('"') && args.endsWith('"'))
|
if(args!!.startsWith('"') && args.endsWith('"'))
|
||||||
args.substring(1, args.length-1) else args
|
args.substring(1, args.length-1) else args
|
||||||
|
@ -93,6 +93,9 @@ enum class Opcode {
|
|||||||
EQUAL,
|
EQUAL,
|
||||||
NOTEQUAL,
|
NOTEQUAL,
|
||||||
|
|
||||||
|
// array access
|
||||||
|
PUSH_INDEXED_VAR,
|
||||||
|
|
||||||
// branching
|
// branching
|
||||||
JUMP,
|
JUMP,
|
||||||
BCS,
|
BCS,
|
||||||
@ -905,6 +908,23 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
Opcode.LINE -> {
|
Opcode.LINE -> {
|
||||||
sourceLine = ins.callLabel!!
|
sourceLine = ins.callLabel!!
|
||||||
}
|
}
|
||||||
|
Opcode.PUSH_INDEXED_VAR -> {
|
||||||
|
val index = evalstack.pop().integerValue()
|
||||||
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
|
if(variable.type==DataType.WORD) {
|
||||||
|
// assume the variable is a pointer (address) and get the byte value from that memory location
|
||||||
|
evalstack.push(Value(DataType.BYTE, mem.getByte(variable.integerValue())))
|
||||||
|
} else {
|
||||||
|
// get indexed element from the array
|
||||||
|
val array = heap.get(variable.heapId)
|
||||||
|
val result = array.array!![index]
|
||||||
|
when(array.type) {
|
||||||
|
DataType.ARRAY, DataType.MATRIX -> evalstack.push(Value(DataType.BYTE, result))
|
||||||
|
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, result))
|
||||||
|
else -> throw VmExecutionException("not a proper array/matrix var")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}")
|
else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,11 +182,15 @@ Values will usually be part of an expression or assignment statement::
|
|||||||
|
|
||||||
Array and Matrix (2-dimensional array) types are also supported like this::
|
Array and Matrix (2-dimensional array) types are also supported like this::
|
||||||
|
|
||||||
byte[4] array = [1, 2, 3, 4] ; initialize the array
|
byte[4] array = [1, 2, 3, 4] ; initialize the array
|
||||||
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
|
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
|
||||||
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
|
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
|
||||||
byte[2,3] matrix = 1 ; a matrix of 2*3=6 bytes all with value 1
|
byte[2,3] matrix = 1 ; a matrix of 2*3=6 bytes all with value 1
|
||||||
byte[2,3] matrix = [1,2,3,4,5,6] ; a 2*3 matrix with value |(1,2) (3,4) (5,6)|
|
byte[2,3] matrix = [1,2,3,4,5,6] ; a 2*3 matrix with value |(1,2) (3,4) (5,6)|
|
||||||
|
|
||||||
|
value = array[3] ; the fourth value in the array (index is 0-based)
|
||||||
|
value = matrix[4,2] ; the byte at the 5th column and 3rd row in the matrix
|
||||||
|
char = string[4] ; the fifth character (=byte) in the string
|
||||||
|
|
||||||
|
|
||||||
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.)
|
||||||
|
@ -315,8 +315,17 @@ If used in the place of a literal value, it expands into the actual array of val
|
|||||||
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
|
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
|
||||||
|
|
||||||
|
|
||||||
.. todo::
|
Array indexing
|
||||||
this may be used later in the for-loop as well. Add 'step' to range expression?
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Strings, arrays and matrixes form a sequence of values. You can access the individual values by
|
||||||
|
indexing into the array.
|
||||||
|
Syntax is familiar with brackets: ``arrayvar[x]`` or ``matrixvar[x, y]`` ::
|
||||||
|
|
||||||
|
array[2] ; the third byte in the array (index is 0-based)
|
||||||
|
matrix[4,2] ; the byte at the 5th column and 3rd row in the matrix
|
||||||
|
string[4] ; the fifth character (=byte) in the string
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Operators
|
Operators
|
||||||
@ -374,14 +383,6 @@ range creation: ``to``
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.. todo::
|
|
||||||
array indexing: ``[`` *index* ``]``
|
|
||||||
When put after a sequence type (array, string or matrix) it means to point to the given element in that sequence::
|
|
||||||
|
|
||||||
array[2] ; the third byte in the array (index is 0-based)
|
|
||||||
matrix[4,2] ; the byte at the 5th column and 3rd row in the matrix
|
|
||||||
|
|
||||||
|
|
||||||
precedence grouping in expressions, or subroutine parameter list: ``(`` *expression* ``)``
|
precedence grouping in expressions, or subroutine parameter list: ``(`` *expression* ``)``
|
||||||
Parentheses are used to group parts of an expression to change the order of evaluation.
|
Parentheses are used to group parts of an expression to change the order of evaluation.
|
||||||
(the subexpression inside the parentheses will be evaluated first):
|
(the subexpression inside the parentheses will be evaluated first):
|
||||||
@ -427,14 +428,8 @@ The open curly brace must immediately follow the subroutine result specification
|
|||||||
and can have nothing following it. The close curly brace must be on its own line as well.
|
and can have nothing following it. The close curly brace must be on its own line as well.
|
||||||
|
|
||||||
.. todo::
|
.. todo::
|
||||||
Pre-defined subroutines that are available on specific memory addresses
|
asmsub with assigning memory address to refer to predefined ROM subroutines
|
||||||
(in system ROM for instance) can be defined by assigning the routine's memory address to the sub,
|
asmsub with a regular body to precisely control what registers are used to call the subroutine
|
||||||
and not specifying a code block::
|
|
||||||
|
|
||||||
sub <identifier> ([proc_parameters]) -> [proc_results] = <address>
|
|
||||||
|
|
||||||
; example:
|
|
||||||
sub CLOSE (logical: A) -> (A?, X?, Y?) = $FFC3
|
|
||||||
|
|
||||||
|
|
||||||
.. data:: parameters
|
.. data:: parameters
|
||||||
|
Loading…
Reference in New Issue
Block a user