mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
taking the address of strings and arrays
This commit is contained in:
parent
069f6ea372
commit
6c8354aef0
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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(
|
||||||
|
@ -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}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user