mirror of
https://github.com/irmen/prog8.git
synced 2024-08-15 03:29:16 +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
|
||||
uword[2] wordarray
|
||||
byte b1
|
||||
memory byte mb1 = $c991
|
||||
|
||||
|
||||
str stringvar = "??????????\n\n\nnext line\r\r\rnext line after carriagereturn"
|
||||
@ -34,29 +35,38 @@ sub start() {
|
||||
secretnumber = '@'
|
||||
secretnumber = '\r'
|
||||
|
||||
testword = stringvar ; @todo fix str address assignment
|
||||
testword = "stringstring" ; @todo fix str address assignment
|
||||
freadstr_arg = stringvar ; @todo fix str address assignment
|
||||
freadstr_arg = "stringstring" ; @todo fix str address assignment
|
||||
secretnumber = "stringstring2222" ; @todo fix str address assignment
|
||||
testword = stringvar
|
||||
testword = wordarray
|
||||
freadstr_arg = stringvar
|
||||
freadstr_arg = wordarray
|
||||
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, address) ; ok!
|
||||
address =c64.MEMBOT(1, memaddr) ; ok!
|
||||
|
||||
A, Y =c64.GETADR() ; ok!
|
||||
Y, A =c64.GETADR() ; ok!
|
||||
address = c64flt.GETADRAY() ; ok!
|
||||
memaddr = c64flt.GETADRAY() ; ok!
|
||||
wordarray[1] = c64flt.GETADRAY() ; ok!
|
||||
v1, v2 =c64.GETADR() ; ok!
|
||||
address =c64.IOBASE() ; ok!
|
||||
A = c64.CHRIN() ; ok !
|
||||
X = c64.CHRIN() ; ok !
|
||||
Y = c64.CHRIN() ; ok!
|
||||
v1 = c64.CHRIN() ; ok !
|
||||
; address =c64.MEMBOT(1, 40000.w) ; ok!
|
||||
; address =c64.MEMBOT(1, address) ; ok!
|
||||
; address =c64.MEMBOT(1, memaddr) ; ok!
|
||||
;
|
||||
; A, Y =c64.GETADR() ; ok!
|
||||
; Y, A =c64.GETADR() ; ok!
|
||||
; address = c64flt.GETADRAY() ; ok!
|
||||
; memaddr = c64flt.GETADRAY() ; ok!
|
||||
; wordarray[1] = c64flt.GETADRAY() ; ok!
|
||||
; v1, v2 =c64.GETADR() ; ok!
|
||||
; address =c64.IOBASE() ; ok!
|
||||
; A = c64.CHRIN() ; ok !
|
||||
; X = c64.CHRIN() ; ok !
|
||||
; Y = c64.CHRIN() ; ok!
|
||||
; v1 = c64.CHRIN() ; ok !
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -338,26 +338,36 @@ class AstChecker(private val namespace: INameScope,
|
||||
if(target.identifier!=null) {
|
||||
val targetName = target.identifier.nameInSource
|
||||
val targetSymbol = namespace.lookup(targetName, assignment)
|
||||
when {
|
||||
targetSymbol == null -> {
|
||||
when (targetSymbol) {
|
||||
null -> {
|
||||
checkResult.add(ExpressionError("undefined symbol: ${targetName.joinToString(".")}", assignment.position))
|
||||
return assignment
|
||||
}
|
||||
targetSymbol !is VarDecl -> {
|
||||
!is VarDecl -> {
|
||||
checkResult.add(SyntaxError("assignment LHS must be register or variable", assignment.position))
|
||||
return assignment
|
||||
}
|
||||
targetSymbol.type == VarDeclType.CONST -> {
|
||||
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
|
||||
return assignment
|
||||
else -> {
|
||||
if(targetSymbol.type == VarDeclType.CONST) {
|
||||
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
|
||||
return assignment
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
// it is not possible to assign a new arrayspec to something.
|
||||
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))
|
||||
// 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) {
|
||||
// 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) {
|
||||
// check augmented assignment:
|
||||
@ -844,10 +854,12 @@ class AstChecker(private val namespace: INameScope,
|
||||
return err("value '$number' out of range for byte")
|
||||
}
|
||||
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)
|
||||
err("unsigned word value expected instead of float; possible loss of precision")
|
||||
else
|
||||
err("unsigned word value expected")
|
||||
err("unsigned word value or address expected")
|
||||
if (number < 0 || number > 65535)
|
||||
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.UBYTE -> sourceDatatype==DataType.UBYTE
|
||||
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.STR -> sourceDatatype==DataType.STR
|
||||
DataType.STR_S -> sourceDatatype==DataType.STR_S
|
||||
|
@ -1180,13 +1180,44 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
when(targetDt) {
|
||||
DataType.UBYTE, DataType.BYTE ->
|
||||
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
DataType.WORD -> {
|
||||
when (valueDt) {
|
||||
DataType.UBYTE -> prog.instr(Opcode.UB2UWORD)
|
||||
DataType.BYTE -> prog.instr(Opcode.B2WORD)
|
||||
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 -> {
|
||||
when (valueDt) {
|
||||
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}"))
|
||||
}
|
||||
|
||||
fun removeLastInstruction() {
|
||||
currentBlock.instructions.removeAt(currentBlock.instructions.lastIndex)
|
||||
}
|
||||
|
||||
fun symbolDef(name: String, value: Int) {
|
||||
currentBlock.integerConstants[name] = value
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ enum class Opcode {
|
||||
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_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
|
||||
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.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.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.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
|
||||
"""
|
||||
},
|
||||
// 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
|
||||
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"
|
||||
@ -1393,6 +1402,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
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])}"
|
||||
},
|
||||
// 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
|
||||
AsmPattern(
|
||||
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
|
||||
"""
|
||||
},
|
||||
// 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
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.UB2UWORD, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
|
||||
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
|
||||
" 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
|
||||
AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
|
||||
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"
|
||||
},
|
||||
// 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
|
||||
AsmPattern(listOf(Opcode.PUSH_MEM_UB, Opcode.UB2UWORD, Opcode.PUSH_VAR_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
|
||||
val loadIndexY = when(segment[2].callLabel) {
|
||||
@ -2505,15 +2547,15 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
},
|
||||
// AX register pair = word var
|
||||
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
|
||||
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
|
||||
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
|
||||
AsmPattern(
|
||||
|
@ -1323,6 +1323,19 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
P_irqd = evalstack.pop().asBooleanValue
|
||||
}
|
||||
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}")
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
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.
|
||||
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.)
|
||||
@ -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,
|
||||
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.
|
||||
If you do modify them in-place, you should take care yourself that they work as
|
||||
expected when the program is restarted.
|
||||
|
Loading…
Reference in New Issue
Block a user