mirror of
https://github.com/irmen/prog8.git
synced 2024-11-27 03:50:27 +00:00
allow taking address of array element
This commit is contained in:
parent
ccf6e32bf9
commit
237c6dc856
@ -126,7 +126,11 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
|||||||
private fun makeInitialArray(value: PtArray): List<StArrayElement> {
|
private fun makeInitialArray(value: PtArray): List<StArrayElement> {
|
||||||
return value.children.map {
|
return value.children.map {
|
||||||
when(it) {
|
when(it) {
|
||||||
is PtAddressOf -> StArrayElement(null, it.identifier.name)
|
is PtAddressOf -> {
|
||||||
|
if(it.isFromArrayElement)
|
||||||
|
TODO("address-of array element $it in initial array value")
|
||||||
|
StArrayElement(null, it.identifier.name)
|
||||||
|
}
|
||||||
is PtIdentifier -> StArrayElement(null, it.name)
|
is PtIdentifier -> StArrayElement(null, it.name)
|
||||||
is PtNumber -> StArrayElement(it.number, null)
|
is PtNumber -> StArrayElement(it.number, null)
|
||||||
else -> throw AssemblyError("invalid array element $it")
|
else -> throw AssemblyError("invalid array element $it")
|
||||||
|
@ -24,7 +24,17 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
|||||||
|
|
||||||
infix fun isSameAs(other: PtExpression): Boolean {
|
infix fun isSameAs(other: PtExpression): Boolean {
|
||||||
return when(this) {
|
return when(this) {
|
||||||
is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier
|
is PtAddressOf -> {
|
||||||
|
if(other !is PtAddressOf)
|
||||||
|
return false
|
||||||
|
if (other.type!==type || !(other.identifier isSameAs identifier))
|
||||||
|
return false
|
||||||
|
if(other.children.size!=children.size)
|
||||||
|
return false
|
||||||
|
if(children.size==1)
|
||||||
|
return true
|
||||||
|
return arrayIndexExpr!! isSameAs other.arrayIndexExpr!!
|
||||||
|
}
|
||||||
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index && other.splitWords==splitWords
|
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index && other.splitWords==splitWords
|
||||||
is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right
|
is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right
|
||||||
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
|
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
|
||||||
@ -105,7 +115,12 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
|||||||
|
|
||||||
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
|
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
|
||||||
val identifier: PtIdentifier
|
val identifier: PtIdentifier
|
||||||
get() = children.single() as PtIdentifier
|
get() = children[0] as PtIdentifier
|
||||||
|
val arrayIndexExpr: PtExpression?
|
||||||
|
get() = if(children.size==2) children[1] as PtExpression else null
|
||||||
|
|
||||||
|
val isFromArrayElement: Boolean
|
||||||
|
get() = children.size==2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2417,8 +2417,7 @@ $repeatLabel""")
|
|||||||
cmp #<$number
|
cmp #<$number
|
||||||
bne $jumpIfFalseLabel
|
bne $jumpIfFalseLabel
|
||||||
cpy #>$number
|
cpy #>$number
|
||||||
bne $jumpIfFalseLabel
|
bne $jumpIfFalseLabel""")
|
||||||
""")
|
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
@ -2426,18 +2425,21 @@ $repeatLabel""")
|
|||||||
cmp ${asmVariableName(right)}
|
cmp ${asmVariableName(right)}
|
||||||
bne $jumpIfFalseLabel
|
bne $jumpIfFalseLabel
|
||||||
cpy ${asmVariableName(right)}+1
|
cpy ${asmVariableName(right)}+1
|
||||||
bne $jumpIfFalseLabel
|
bne $jumpIfFalseLabel""")
|
||||||
""")
|
|
||||||
}
|
}
|
||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
val name = asmSymbolName(right.identifier)
|
val name = asmSymbolName(right.identifier)
|
||||||
out("""
|
if(right.isFromArrayElement) {
|
||||||
cmp #<$name
|
TODO("address-of array element $name at ${right.position}")
|
||||||
bne $jumpIfFalseLabel
|
// assignmentAsmGen.assignAddressOf(target, name, right.arrayIndexExpr)
|
||||||
cpy #>$name
|
} else {
|
||||||
bne $jumpIfFalseLabel
|
out("""
|
||||||
""")
|
cmp #<$name
|
||||||
|
bne $jumpIfFalseLabel
|
||||||
|
cpy #>$name
|
||||||
|
bne $jumpIfFalseLabel""")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
if(left.isSimple()) {
|
if(left.isSimple()) {
|
||||||
@ -2518,12 +2520,16 @@ $repeatLabel""")
|
|||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
val name = asmSymbolName(right.identifier)
|
val name = asmSymbolName(right.identifier)
|
||||||
out("""
|
if(right.isFromArrayElement) {
|
||||||
cmp #<$name
|
TODO("address-of array element $name at ${right.position}")
|
||||||
bne +
|
} else {
|
||||||
cpy #>$name
|
out("""
|
||||||
beq $jumpIfFalseLabel
|
cmp #<$name
|
||||||
+""")
|
bne +
|
||||||
|
cpy #>$name
|
||||||
|
beq $jumpIfFalseLabel
|
||||||
|
+""")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
if(left.isSimple()) {
|
if(left.isSimple()) {
|
||||||
@ -2849,8 +2855,12 @@ $repeatLabel""")
|
|||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
assignExpressionToRegister(right, RegisterOrPair.AY)
|
assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||||
val name = asmSymbolName(left.identifier)
|
val name = asmSymbolName(left.identifier)
|
||||||
code("#>$name", "#<$name")
|
if(left.isFromArrayElement) {
|
||||||
return true
|
TODO("address-of array element $name at ${left.position}")
|
||||||
|
} else {
|
||||||
|
code("#>$name", "#<$name")
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
assignExpressionToRegister(right, RegisterOrPair.AY)
|
assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||||
@ -2898,8 +2908,12 @@ $repeatLabel""")
|
|||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
val name = asmSymbolName(right.identifier)
|
val name = asmSymbolName(right.identifier)
|
||||||
code("#>$name", "#<$name")
|
if(right.isFromArrayElement) {
|
||||||
return true
|
TODO("address-of array element $name at ${right.position}")
|
||||||
|
} else {
|
||||||
|
code("#>$name", "#<$name")
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
|
@ -49,7 +49,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
DataType.WORD -> assignVariableWord(assign.target, variable, assign.source.datatype)
|
DataType.WORD -> assignVariableWord(assign.target, variable, assign.source.datatype)
|
||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
if(assign.source.datatype in PassByReferenceDatatypes)
|
if(assign.source.datatype in PassByReferenceDatatypes)
|
||||||
assignAddressOf(assign.target, variable)
|
assignAddressOf(assign.target, variable, null, null)
|
||||||
else
|
else
|
||||||
assignVariableWord(assign.target, variable, assign.source.datatype)
|
assignVariableWord(assign.target, variable, assign.source.datatype)
|
||||||
}
|
}
|
||||||
@ -181,7 +181,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
when(val value = assign.source.expression!!) {
|
when(val value = assign.source.expression!!) {
|
||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
val sourceName = asmgen.asmSymbolName(value.identifier)
|
val sourceName = asmgen.asmSymbolName(value.identifier)
|
||||||
assignAddressOf(assign.target, sourceName)
|
val arrayDt = value.identifier.type
|
||||||
|
assignAddressOf(assign.target, sourceName, arrayDt, value.arrayIndexExpr)
|
||||||
}
|
}
|
||||||
is PtNumber -> throw AssemblyError("source kind should have been literalnumber")
|
is PtNumber -> throw AssemblyError("source kind should have been literalnumber")
|
||||||
is PtIdentifier -> throw AssemblyError("source kind should have been variable")
|
is PtIdentifier -> throw AssemblyError("source kind should have been variable")
|
||||||
@ -806,28 +807,32 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
|
|
||||||
when (right) {
|
when (right) {
|
||||||
is PtAddressOf -> {
|
is PtAddressOf -> {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
|
|
||||||
val symbol = asmgen.asmVariableName(right.identifier)
|
val symbol = asmgen.asmVariableName(right.identifier)
|
||||||
if(expr.operator=="+")
|
if(right.isFromArrayElement) {
|
||||||
asmgen.out("""
|
TODO("address-of array element $symbol at ${right.position}")
|
||||||
clc
|
} else {
|
||||||
adc #<$symbol
|
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
|
||||||
tax
|
if(expr.operator=="+")
|
||||||
tya
|
asmgen.out("""
|
||||||
adc #>$symbol
|
clc
|
||||||
tay
|
adc #<$symbol
|
||||||
txa""")
|
tax
|
||||||
else
|
tya
|
||||||
asmgen.out("""
|
adc #>$symbol
|
||||||
sec
|
tay
|
||||||
sbc #<$symbol
|
txa""")
|
||||||
tax
|
else
|
||||||
tya
|
asmgen.out("""
|
||||||
sbc #>$symbol
|
sec
|
||||||
tay
|
sbc #<$symbol
|
||||||
txa""")
|
tax
|
||||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
tya
|
||||||
return true
|
sbc #>$symbol
|
||||||
|
tay
|
||||||
|
txa""")
|
||||||
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is PtIdentifier -> {
|
is PtIdentifier -> {
|
||||||
val symname = asmgen.asmVariableName(right)
|
val symname = asmgen.asmVariableName(right)
|
||||||
@ -1619,7 +1624,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
// use subroutine
|
// use subroutine
|
||||||
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
|
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
|
||||||
asmgen.saveRegisterStack(CpuRegister.A, true)
|
asmgen.saveRegisterStack(CpuRegister.A, true)
|
||||||
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position,"P8ZP_SCRATCH_W1"), varname)
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position,"P8ZP_SCRATCH_W1"), varname, null, null)
|
||||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||||
val stringVal = (variable as PtVariable).value as PtString
|
val stringVal = (variable as PtVariable).value as PtString
|
||||||
asmgen.out(" ldy #${stringVal.value.length}")
|
asmgen.out(" ldy #${stringVal.value.length}")
|
||||||
@ -1632,7 +1637,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
||||||
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
|
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
|
||||||
asmgen.saveRegisterStack(CpuRegister.A, true)
|
asmgen.saveRegisterStack(CpuRegister.A, true)
|
||||||
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W1"), varname)
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W1"), varname, null, null)
|
||||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||||
asmgen.out(" ldy #$numElements")
|
asmgen.out(" ldy #$numElements")
|
||||||
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
||||||
@ -1640,7 +1645,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
||||||
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt)
|
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt)
|
||||||
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W2"), varname)
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W2"), varname, null, null)
|
||||||
asmgen.out(" ldy #$numElements")
|
asmgen.out(" ldy #$numElements")
|
||||||
asmgen.out(" jsr prog8_lib.containment_wordarray")
|
asmgen.out(" jsr prog8_lib.containment_wordarray")
|
||||||
return
|
return
|
||||||
@ -2167,12 +2172,24 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assignAddressOf(target: AsmAssignTarget, sourceName: String) {
|
private fun assignAddressOf(target: AsmAssignTarget, sourceName: String, arrayDt: DataType?, arrayIndexExpr: PtExpression?) {
|
||||||
|
val offset = if(arrayIndexExpr!=null) {
|
||||||
|
val constIndex = arrayIndexExpr.asConstInteger()
|
||||||
|
if(constIndex!=null) {
|
||||||
|
if(arrayDt in SplitWordArrayTypes)
|
||||||
|
constIndex
|
||||||
|
else
|
||||||
|
program.memsizer.memorySize(arrayDt!!, constIndex) // add arrayIndexExpr * elementsize to the address of the array variable.
|
||||||
|
} else {
|
||||||
|
TODO("address-of array element $sourceName with non-const index at ${target.position}")
|
||||||
|
}
|
||||||
|
} else 0
|
||||||
|
|
||||||
when(target.kind) {
|
when(target.kind) {
|
||||||
TargetStorageKind.VARIABLE -> {
|
TargetStorageKind.VARIABLE -> {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda #<$sourceName
|
lda #<$sourceName+$offset
|
||||||
ldy #>$sourceName
|
ldy #>$sourceName+$offset
|
||||||
sta ${target.asmVarname}
|
sta ${target.asmVarname}
|
||||||
sty ${target.asmVarname}+1
|
sty ${target.asmVarname}+1
|
||||||
""")
|
""")
|
||||||
@ -2181,20 +2198,20 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
throw AssemblyError("can't store word into memory byte")
|
throw AssemblyError("can't store word into memory byte")
|
||||||
}
|
}
|
||||||
TargetStorageKind.ARRAY -> {
|
TargetStorageKind.ARRAY -> {
|
||||||
asmgen.out(" lda #<$sourceName | ldy #>$sourceName")
|
asmgen.out(" lda #<$sourceName+$offset | ldy #>$sourceName+$offset")
|
||||||
assignRegisterpairWord(target, RegisterOrPair.AY)
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||||
}
|
}
|
||||||
TargetStorageKind.REGISTER -> {
|
TargetStorageKind.REGISTER -> {
|
||||||
when(target.register!!) {
|
when(target.register!!) {
|
||||||
RegisterOrPair.AX -> asmgen.out(" ldx #>$sourceName | lda #<$sourceName")
|
RegisterOrPair.AX -> asmgen.out(" ldx #>$sourceName+$offset | lda #<$sourceName+$offset")
|
||||||
RegisterOrPair.AY -> asmgen.out(" ldy #>$sourceName | lda #<$sourceName")
|
RegisterOrPair.AY -> asmgen.out(" ldy #>$sourceName+$offset | lda #<$sourceName+$offset")
|
||||||
RegisterOrPair.XY -> asmgen.out(" ldy #>$sourceName | ldx #<$sourceName")
|
RegisterOrPair.XY -> asmgen.out(" ldy #>$sourceName+$offset | ldx #<$sourceName+$offset")
|
||||||
in Cx16VirtualRegisters -> {
|
in Cx16VirtualRegisters -> {
|
||||||
asmgen.out(
|
asmgen.out(
|
||||||
"""
|
"""
|
||||||
lda #<$sourceName
|
lda #<$sourceName+$offset
|
||||||
sta cx16.${target.register.toString().lowercase()}
|
sta cx16.${target.register.toString().lowercase()}
|
||||||
lda #>$sourceName
|
lda #>$sourceName+$offset
|
||||||
sta cx16.${target.register.toString().lowercase()}+1
|
sta cx16.${target.register.toString().lowercase()}+1
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
@ -3622,7 +3639,11 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
asmgen.out(" sta ${addressLv.number.toHex()}")
|
asmgen.out(" sta ${addressLv.number.toHex()}")
|
||||||
}
|
}
|
||||||
addressOf != null -> {
|
addressOf != null -> {
|
||||||
asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier)}")
|
if(addressOf.isFromArrayElement) {
|
||||||
|
TODO("address-of array element $addressOf")
|
||||||
|
} else {
|
||||||
|
asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier)}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
addressExpr is PtIdentifier -> {
|
addressExpr is PtIdentifier -> {
|
||||||
asmgen.storeAIntoPointerVar(addressExpr)
|
asmgen.storeAIntoPointerVar(addressExpr)
|
||||||
@ -3632,8 +3653,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
val addrOf = addressExpr.left as? PtAddressOf
|
val addrOf = addressExpr.left as? PtAddressOf
|
||||||
val offset = (addressExpr.right as? PtNumber)?.number?.toInt()
|
val offset = (addressExpr.right as? PtNumber)?.number?.toInt()
|
||||||
if(addrOf!=null && offset!=null) {
|
if(addrOf!=null && offset!=null) {
|
||||||
asmgen.out(" sta ${asmgen.asmSymbolName(addrOf.identifier)}${addressExpr.operator}${offset}")
|
if(addrOf.isFromArrayElement) {
|
||||||
return
|
TODO("address-of array element $addrOf")
|
||||||
|
} else {
|
||||||
|
asmgen.out(" sta ${asmgen.asmSymbolName(addrOf.identifier)}${addressExpr.operator}${offset}")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
|
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
|
||||||
|
@ -3,10 +3,7 @@ package prog8.codegen.intermediate
|
|||||||
import prog8.code.StRomSub
|
import prog8.code.StRomSub
|
||||||
import prog8.code.StSub
|
import prog8.code.StSub
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.AssemblyError
|
import prog8.code.core.*
|
||||||
import prog8.code.core.DataType
|
|
||||||
import prog8.code.core.PassByValueDatatypes
|
|
||||||
import prog8.code.core.SignedDatatypes
|
|
||||||
import prog8.intermediate.*
|
import prog8.intermediate.*
|
||||||
|
|
||||||
internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int) {
|
internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int) {
|
||||||
@ -69,10 +66,28 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
val vmDt = irType(expr.type)
|
val vmDt = irType(expr.type)
|
||||||
val symbol = expr.identifier.name
|
val symbol = expr.identifier.name
|
||||||
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
||||||
val code = IRCodeChunk(null, null)
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
val resultRegister = codeGen.registers.nextFree()
|
val resultRegister = codeGen.registers.nextFree()
|
||||||
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol)
|
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null)
|
||||||
ExpressionCodeResult(code, vmDt, resultRegister, -1)
|
if(expr.isFromArrayElement) {
|
||||||
|
val indexTr = translateExpression(expr.arrayIndexExpr!!)
|
||||||
|
addToResult(result, indexTr, indexTr.resultReg, -1)
|
||||||
|
if(expr.identifier.type in SplitWordArrayTypes) {
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
// multiply indexTr resultreg by the eltSize and add this to the resultRegister.
|
||||||
|
it += IRInstruction(Opcode.ADDR, IRDataType.BYTE, reg1=resultRegister, reg2=indexTr.resultReg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val eltSize = codeGen.program.memsizer.memorySize(expr.identifier.type, 1)
|
||||||
|
result += IRCodeChunk(null, null).also {
|
||||||
|
// multiply indexTr resultreg by the eltSize and add this to the resultRegister.
|
||||||
|
if(eltSize>1)
|
||||||
|
it += IRInstruction(Opcode.MUL, IRDataType.BYTE, reg1=indexTr.resultReg, immediate = eltSize)
|
||||||
|
it += IRInstruction(Opcode.ADDR, IRDataType.BYTE, reg1=resultRegister, reg2=indexTr.resultReg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExpressionCodeResult(result, vmDt, resultRegister, -1)
|
||||||
}
|
}
|
||||||
is PtMemoryByte -> {
|
is PtMemoryByte -> {
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
|
@ -30,7 +30,7 @@ class StatementOptimizer(private val program: Program,
|
|||||||
if(functionCallStatement.target.nameInSource==listOf("txt", "print")) {
|
if(functionCallStatement.target.nameInSource==listOf("txt", "print")) {
|
||||||
val arg = functionCallStatement.args.single()
|
val arg = functionCallStatement.args.single()
|
||||||
val stringVar: IdentifierReference? = if(arg is AddressOf) {
|
val stringVar: IdentifierReference? = if(arg is AddressOf) {
|
||||||
arg.identifier
|
if(arg.arrayIndex==null) arg.identifier else null
|
||||||
} else {
|
} else {
|
||||||
arg as? IdentifierReference
|
arg as? IdentifierReference
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
|
|||||||
listOf(
|
listOf(
|
||||||
IAstModification.ReplaceNode(
|
IAstModification.ReplaceNode(
|
||||||
typecast,
|
typecast,
|
||||||
AddressOf(identifier, typecast.position),
|
AddressOf(identifier, null, typecast.position),
|
||||||
parent
|
parent
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -219,6 +219,8 @@ _after:
|
|||||||
// @(&var+1) --> msb(var)
|
// @(&var+1) --> msb(var)
|
||||||
|
|
||||||
val addrOf = memread.addressExpression as? AddressOf
|
val addrOf = memread.addressExpression as? AddressOf
|
||||||
|
if(addrOf?.arrayIndex!=null)
|
||||||
|
return noModifications
|
||||||
if(addrOf!=null && addrOf.identifier.inferType(program).isWords) {
|
if(addrOf!=null && addrOf.identifier.inferType(program).isWords) {
|
||||||
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier), memread.position)
|
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier), memread.position)
|
||||||
return listOf(IAstModification.ReplaceNode(memread, lsb, parent))
|
return listOf(IAstModification.ReplaceNode(memread, lsb, parent))
|
||||||
|
@ -440,6 +440,8 @@ class IntermediateAstMaker(private val program: Program) {
|
|||||||
addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position)) // NOTE: assumes _lsb is first in memory! (immediately followed by _msb)
|
addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position)) // NOTE: assumes _lsb is first in memory! (immediately followed by _msb)
|
||||||
else
|
else
|
||||||
addr.add(transform(src.identifier))
|
addr.add(transform(src.identifier))
|
||||||
|
if(src.arrayIndex!=null)
|
||||||
|
addr.add(transformExpression(src.arrayIndex!!.indexExpr))
|
||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,8 +304,8 @@ internal class StatementReorderer(
|
|||||||
val eltsize = program.memsizer.memorySize(ArrayToElementTypes.getValue(sourceVar.datatype))
|
val eltsize = program.memsizer.memorySize(ArrayToElementTypes.getValue(sourceVar.datatype))
|
||||||
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assign.position),
|
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assign.position),
|
||||||
mutableListOf(
|
mutableListOf(
|
||||||
AddressOf(sourceIdent, assign.position),
|
AddressOf(sourceIdent, null, assign.position),
|
||||||
AddressOf(identifier, assign.position),
|
AddressOf(identifier, null, assign.position),
|
||||||
NumericLiteral.optimalInteger(numelements*eltsize, assign.position)
|
NumericLiteral.optimalInteger(numelements*eltsize, assign.position)
|
||||||
), false, assign.position
|
), false, assign.position
|
||||||
)
|
)
|
||||||
|
@ -265,7 +265,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
|||||||
if(identifier?.isSubroutineParameter(program)==false) {
|
if(identifier?.isSubroutineParameter(program)==false) {
|
||||||
modifications += IAstModification.ReplaceNode(
|
modifications += IAstModification.ReplaceNode(
|
||||||
identifier,
|
identifier,
|
||||||
AddressOf(identifier, arg.position),
|
AddressOf(identifier, null, arg.position),
|
||||||
call as Node)
|
call as Node)
|
||||||
}
|
}
|
||||||
} else if(arg is NumericLiteral) {
|
} else if(arg is NumericLiteral) {
|
||||||
@ -286,7 +286,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
|||||||
if(arg is IdentifierReference && DataType.UWORD == param.type) {
|
if(arg is IdentifierReference && DataType.UWORD == param.type) {
|
||||||
modifications += IAstModification.ReplaceNode(
|
modifications += IAstModification.ReplaceNode(
|
||||||
arg,
|
arg,
|
||||||
AddressOf(arg, arg.position),
|
AddressOf(arg, null, arg.position),
|
||||||
call as Node
|
call as Node
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -312,7 +312,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
|||||||
if(identifier?.isSubroutineParameter(program)==false) {
|
if(identifier?.isSubroutineParameter(program)==false) {
|
||||||
modifications += IAstModification.ReplaceNode(
|
modifications += IAstModification.ReplaceNode(
|
||||||
call.args[index],
|
call.args[index],
|
||||||
AddressOf(identifier, pair.second.position),
|
AddressOf(identifier, null, pair.second.position),
|
||||||
call as Node)
|
call as Node)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -325,7 +325,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
|||||||
if(pair.second is IdentifierReference && DataType.UWORD in pair.first.possibleDatatypes) {
|
if(pair.second is IdentifierReference && DataType.UWORD in pair.first.possibleDatatypes) {
|
||||||
modifications += IAstModification.ReplaceNode(
|
modifications += IAstModification.ReplaceNode(
|
||||||
call.args[index],
|
call.args[index],
|
||||||
AddressOf(pair.second as IdentifierReference, pair.second.position),
|
AddressOf(pair.second as IdentifierReference, null, pair.second.position),
|
||||||
call as Node
|
call as Node
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -52,13 +52,13 @@ class TestAsmGenSymbols: StringSpec({
|
|||||||
|
|
||||||
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY)
|
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY)
|
||||||
val assign1 = Assignment(tgt, IdentifierReference(listOf("localvar"), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assign1 = Assignment(tgt, IdentifierReference(listOf("localvar"), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
|
|
||||||
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
|
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
|
||||||
val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY)
|
val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY)
|
||||||
|
@ -429,6 +429,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
|||||||
override fun visit(addressOf: AddressOf) {
|
override fun visit(addressOf: AddressOf) {
|
||||||
output("&")
|
output("&")
|
||||||
addressOf.identifier.accept(this)
|
addressOf.identifier.accept(this)
|
||||||
|
addressOf.arrayIndex?.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(inlineAssembly: InlineAssembly) {
|
override fun visit(inlineAssembly: InlineAssembly) {
|
||||||
|
@ -469,8 +469,15 @@ private fun Prog8ANTLRParser.ExpressionContext.toAst() : Expression {
|
|||||||
if(directmemory()!=null)
|
if(directmemory()!=null)
|
||||||
return DirectMemoryRead(directmemory().expression().toAst(), toPosition())
|
return DirectMemoryRead(directmemory().expression().toAst(), toPosition())
|
||||||
|
|
||||||
if(addressof()!=null)
|
if(addressof()!=null) {
|
||||||
return AddressOf(addressof().scoped_identifier().toAst(), toPosition())
|
val addressOf = addressof()
|
||||||
|
val identifier = addressOf.scoped_identifier()
|
||||||
|
val array = addressOf.arrayindexed()
|
||||||
|
return if(identifier!=null)
|
||||||
|
AddressOf(addressof().scoped_identifier().toAst(), null, toPosition())
|
||||||
|
else
|
||||||
|
AddressOf(array.scoped_identifier().toAst(), array.arrayindex().toAst(), toPosition())
|
||||||
|
}
|
||||||
|
|
||||||
throw FatalAstException(text)
|
throw FatalAstException(text)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ sealed class Expression: Node {
|
|||||||
(other is TypecastExpression && other.implicit==implicit && other.type==type && other.expression isSameAs expression)
|
(other is TypecastExpression && other.implicit==implicit && other.type==type && other.expression isSameAs expression)
|
||||||
}
|
}
|
||||||
is AddressOf -> {
|
is AddressOf -> {
|
||||||
(other is AddressOf && other.identifier.nameInSource == identifier.nameInSource)
|
(other is AddressOf && other.identifier.nameInSource == identifier.nameInSource && other.arrayIndex==arrayIndex)
|
||||||
}
|
}
|
||||||
is RangeExpression -> {
|
is RangeExpression -> {
|
||||||
(other is RangeExpression && other.from==from && other.to==to && other.step==step)
|
(other is RangeExpression && other.from==from && other.to==to && other.step==step)
|
||||||
@ -369,25 +369,34 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class AddressOf(var identifier: IdentifierReference, override val position: Position) : Expression() {
|
data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayIndex?, override val position: Position) : Expression() {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
override fun linkParents(parent: Node) {
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
identifier.parent=this
|
identifier.linkParents(this)
|
||||||
|
arrayIndex?.linkParents(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isSimple = true
|
override val isSimple = true
|
||||||
|
|
||||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||||
require(replacement is IdentifierReference && node===identifier)
|
if(node===identifier) {
|
||||||
identifier = replacement
|
require(replacement is IdentifierReference)
|
||||||
replacement.parent = this
|
identifier = replacement
|
||||||
|
replacement.parent = this
|
||||||
|
} else if(node===arrayIndex) {
|
||||||
|
require(replacement is ArrayIndex)
|
||||||
|
arrayIndex = replacement
|
||||||
|
replacement.parent = this
|
||||||
|
} else {
|
||||||
|
throw FatalAstException("invalid replace, no child node $node")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun copy() = AddressOf(identifier.copy(), position)
|
override fun copy() = AddressOf(identifier.copy(), arrayIndex?.copy(), position)
|
||||||
override fun constValue(program: Program): NumericLiteral? = null
|
override fun constValue(program: Program): NumericLiteral? = null
|
||||||
override fun referencesIdentifier(nameInSource: List<String>) = identifier.nameInSource==nameInSource
|
override fun referencesIdentifier(nameInSource: List<String>) = identifier.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true
|
||||||
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UWORD)
|
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UWORD)
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||||
|
@ -458,6 +458,7 @@ abstract class AstWalker {
|
|||||||
fun visit(addressOf: AddressOf, parent: Node) {
|
fun visit(addressOf: AddressOf, parent: Node) {
|
||||||
track(before(addressOf, parent), addressOf, parent)
|
track(before(addressOf, parent), addressOf, parent)
|
||||||
addressOf.identifier.accept(this, addressOf)
|
addressOf.identifier.accept(this, addressOf)
|
||||||
|
addressOf.arrayIndex?.accept(this)
|
||||||
track(after(addressOf, parent), addressOf, parent)
|
track(after(addressOf, parent), addressOf, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,6 +173,7 @@ interface IAstVisitor {
|
|||||||
|
|
||||||
fun visit(addressOf: AddressOf) {
|
fun visit(addressOf: AddressOf) {
|
||||||
addressOf.identifier.accept(this)
|
addressOf.identifier.accept(this)
|
||||||
|
addressOf.arrayIndex?.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(inlineAssembly: InlineAssembly) {
|
fun visit(inlineAssembly: InlineAssembly) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
- allow taking address of array variable (now gives parser error)
|
- implement codegen TODO's "address-of array element" (part of: allow taking address of array element (now gives parser error): &array[10] )
|
||||||
- ir: the @split arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line.
|
- ir: the @split arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line.
|
||||||
|
|
||||||
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
|
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
|
||||||
|
@ -1,37 +1,53 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
%import floats
|
||||||
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
uword zz = $ea45
|
ubyte[] barray = [11,22,33]
|
||||||
txt.print_uwhex(zz, true)
|
uword[] warray = [$1234,$5678,$abcd]
|
||||||
|
uword[] @split split_warray = [$1234,$5678,$abcd]
|
||||||
|
float[] float_array = [11.11,22.22,33.33]
|
||||||
|
|
||||||
|
txt.print("incr of 1: ")
|
||||||
|
txt.print_uw(&barray)
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(&barray[0])
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(&barray[1])
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(&barray[2])
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
;@(&zz) = $11
|
txt.print("incr of 2: ")
|
||||||
setlsb(zz, 0)
|
txt.print_uw(&warray)
|
||||||
txt.print_uwhex(zz, true)
|
txt.spc()
|
||||||
txt.nl()
|
txt.print_uw(&warray[0])
|
||||||
;@(&zz+1) = $22
|
txt.spc()
|
||||||
setmsb(zz, 0)
|
txt.print_uw(&warray[1])
|
||||||
txt.print_uwhex(zz, true)
|
txt.spc()
|
||||||
txt.nl()
|
txt.print_uw(&warray[2])
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
uword[] @split array = [$1234,$5678,$abcd] ; TODO also with @split
|
txt.print("incr of 1: ")
|
||||||
|
txt.print_uw(&split_warray)
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(&split_warray[0])
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(&split_warray[1])
|
||||||
|
txt.spc()
|
||||||
|
txt.print_uw(&split_warray[2])
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
ubyte one = 1
|
txt.print("incr of 4 or 5: ")
|
||||||
ubyte two = 2
|
txt.print_uw(&float_array)
|
||||||
txt.print_uwhex(array[1], true)
|
txt.spc()
|
||||||
txt.nl()
|
txt.print_uw(&float_array[0])
|
||||||
txt.print_uwhex(array[2], true)
|
txt.spc()
|
||||||
txt.nl()
|
txt.print_uw(&float_array[1])
|
||||||
;@(&array+one*2) = $ff
|
txt.spc()
|
||||||
;@(&array+two*2+1) = $ff
|
txt.print_uw(&float_array[2])
|
||||||
setlsb(array[one],0)
|
|
||||||
setmsb(array[two],0)
|
|
||||||
txt.print_uwhex(array[1], true)
|
|
||||||
txt.nl()
|
|
||||||
txt.print_uwhex(array[2], true)
|
|
||||||
txt.nl()
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ typecast : 'as' datatype;
|
|||||||
|
|
||||||
directmemory : '@' '(' expression ')';
|
directmemory : '@' '(' expression ')';
|
||||||
|
|
||||||
addressof : <assoc=right> ADDRESS_OF scoped_identifier ;
|
addressof : <assoc=right> ADDRESS_OF (scoped_identifier | arrayindexed) ;
|
||||||
|
|
||||||
|
|
||||||
functioncall : scoped_identifier '(' expression_list? ')' ;
|
functioncall : scoped_identifier '(' expression_list? ')' ;
|
||||||
|
Loading…
Reference in New Issue
Block a user