mirror of
https://github.com/irmen/prog8.git
synced 2025-11-03 04:17:16 +00:00
make address-of dereference work
This commit is contained in:
@@ -177,7 +177,7 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable {
|
||||
newValue.add(elt)
|
||||
else {
|
||||
val newAddr = PtAddressOf(elt.position)
|
||||
newAddr.children.add(elt.identifier.prefix(newAddr, st))
|
||||
newAddr.children.add(elt.identifier!!.prefix(newAddr, st))
|
||||
if (elt.arrayIndexExpr != null)
|
||||
newAddr.children.add(elt.arrayIndexExpr!!)
|
||||
newAddr.parent = arrayValue
|
||||
@@ -1299,8 +1299,10 @@ $repeatLabel""")
|
||||
if(addrOf!=null && constOffset!=null) {
|
||||
if(addrOf.isFromArrayElement) {
|
||||
TODO("address-of array element $addrOf")
|
||||
} else if(addrOf.dereference!=null) {
|
||||
throw AssemblyError("write &dereference, makes no sense at ${addrOf.position}")
|
||||
} else {
|
||||
out(" sta ${asmSymbolName(addrOf.identifier)}+${constOffset}")
|
||||
out(" sta ${asmSymbolName(addrOf.identifier!!)}+${constOffset}")
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1339,8 +1341,10 @@ $repeatLabel""")
|
||||
if(addrOf!=null && constOffset!=null) {
|
||||
if(addrOf.isFromArrayElement) {
|
||||
TODO("address-of array element $addrOf")
|
||||
} else if(addrOf.dereference!=null) {
|
||||
TODO("read &dereference")
|
||||
} else {
|
||||
out(" lda ${asmSymbolName(addrOf.identifier)}+${constOffset}")
|
||||
out(" lda ${asmSymbolName(addrOf.identifier!!)}+${constOffset}")
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1389,8 +1393,10 @@ $repeatLabel""")
|
||||
if(addrOf!=null && constOffset!=null) {
|
||||
if(addrOf.isFromArrayElement) {
|
||||
TODO("address-of array element $addrOf")
|
||||
} else if(addrOf.dereference!=null) {
|
||||
throw AssemblyError("write &dereference, makes no sense at ${addrOf.position}")
|
||||
} else {
|
||||
out(" sta ${asmSymbolName(addrOf.identifier)}-${constOffset}")
|
||||
out(" sta ${asmSymbolName(addrOf.identifier!!)}-${constOffset}")
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1420,8 +1426,10 @@ $repeatLabel""")
|
||||
if(addrOf!=null && constOffset!=null) {
|
||||
if(addrOf.isFromArrayElement) {
|
||||
TODO("address-of array element $addrOf")
|
||||
} else if(addrOf.dereference!=null) {
|
||||
TODO("read &dereference")
|
||||
} else {
|
||||
out(" lda ${asmSymbolName(addrOf.identifier)}-${constOffset}")
|
||||
out(" lda ${asmSymbolName(addrOf.identifier!!)}-${constOffset}")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,8 +799,8 @@ _jump jmp (${target.asmLabel})
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true)
|
||||
asmgen.out(" cpy #0")
|
||||
} else {
|
||||
var varname = asmgen.asmVariableName(value.identifier)
|
||||
if(value.identifier.type.isSplitWordArray) {
|
||||
var varname = asmgen.asmVariableName(value.identifier!!)
|
||||
if(value.identifier!!.type.isSplitWordArray) {
|
||||
varname += if(value.isMsbForSplitArray) "_msb" else "_lsb"
|
||||
}
|
||||
asmgen.out(" lda #>$varname")
|
||||
@@ -1598,10 +1598,10 @@ _jump jmp (${target.asmLabel})
|
||||
if(left.isFromArrayElement) {
|
||||
fallbackTranslateForSimpleCondition(stmt)
|
||||
} else {
|
||||
val varname = if(left.identifier.type.isSplitWordArray) {
|
||||
if(left.isMsbForSplitArray) left.identifier.name+"_msb" else left.identifier.name+"_lsb"
|
||||
val varname = if(left.identifier!!.type.isSplitWordArray) {
|
||||
if(left.isMsbForSplitArray) left.identifier!!.name+"_msb" else left.identifier!!.name+"_lsb"
|
||||
} else {
|
||||
left.identifier.name
|
||||
left.identifier!!.name
|
||||
}
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
translateAYNotEquals("#<$varname", "#>$varname")
|
||||
@@ -1650,10 +1650,10 @@ _jump jmp (${target.asmLabel})
|
||||
if(left.isFromArrayElement) {
|
||||
fallbackTranslateForSimpleCondition(stmt)
|
||||
} else {
|
||||
val varname = if(left.identifier.type.isSplitWordArray) {
|
||||
if(left.isMsbForSplitArray) left.identifier.name+"_msb" else left.identifier.name+"_lsb"
|
||||
val varname = if(left.identifier!!.type.isSplitWordArray) {
|
||||
if(left.isMsbForSplitArray) left.identifier!!.name+"_msb" else left.identifier!!.name+"_lsb"
|
||||
} else {
|
||||
left.identifier.name
|
||||
left.identifier!!.name
|
||||
}
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
translateAYEquals("#<$varname", "#>$varname")
|
||||
|
||||
@@ -438,15 +438,19 @@ internal class AssignmentAsmGen(
|
||||
private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) {
|
||||
when(val value = assign.source.expression!!) {
|
||||
is PtAddressOf -> {
|
||||
val arrayDt = value.identifier.type
|
||||
if(value.identifier!=null) {
|
||||
val arrayDt = value.identifier!!.type
|
||||
val sourceName =
|
||||
if (value.isMsbForSplitArray)
|
||||
asmgen.asmSymbolName(value.identifier) + "_msb"
|
||||
asmgen.asmSymbolName(value.identifier!!) + "_msb"
|
||||
else if (arrayDt.isSplitWordArray)
|
||||
asmgen.asmSymbolName(value.identifier) + "_lsb" // the _lsb split array comes first in memory
|
||||
asmgen.asmSymbolName(value.identifier!!) + "_lsb" // the _lsb split array comes first in memory
|
||||
else
|
||||
asmgen.asmSymbolName(value.identifier)
|
||||
asmgen.asmSymbolName(value.identifier!!)
|
||||
assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, arrayDt, value.arrayIndexExpr)
|
||||
} else {
|
||||
TODO("read &dereference")
|
||||
}
|
||||
}
|
||||
is PtBool -> throw AssemblyError("source kind should have been literalboolean")
|
||||
is PtNumber -> throw AssemblyError("source kind should have been literalnumber")
|
||||
@@ -1384,9 +1388,11 @@ internal class AssignmentAsmGen(
|
||||
is PtAddressOf -> {
|
||||
if(right.isFromArrayElement) {
|
||||
TODO("address-of array element at ${right.position}")
|
||||
} else if(right.dereference!=null) {
|
||||
TODO("read &dereference")
|
||||
} else {
|
||||
var symbol = asmgen.asmVariableName(right.identifier)
|
||||
if(right.identifier.type.isSplitWordArray) {
|
||||
var symbol = asmgen.asmVariableName(right.identifier!!)
|
||||
if(right.identifier!!.type.isSplitWordArray) {
|
||||
symbol = if(right.isMsbForSplitArray) symbol+"_msb" else symbol+"_lsb"
|
||||
}
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned)
|
||||
@@ -4019,8 +4025,10 @@ $endLabel""")
|
||||
addressOf != null -> {
|
||||
if(addressOf.isFromArrayElement) {
|
||||
TODO("address-of array element $addressOf")
|
||||
} else if(addressOf.dereference!=null) {
|
||||
throw AssemblyError("write &dereference, makes no sense at ${addressOf.position}")
|
||||
} else {
|
||||
asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier)}")
|
||||
asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier!!)}")
|
||||
}
|
||||
}
|
||||
addressExpr is PtIdentifier -> {
|
||||
|
||||
@@ -511,7 +511,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
else if(targetPointerDeref!=null) {
|
||||
val pointerTr = expressionEval.translateExpression(targetPointerDeref.start)
|
||||
result += pointerTr.chunks
|
||||
result += expressionEval.traverseDerefChain(targetPointerDeref, pointerTr.resultReg)
|
||||
result += expressionEval.traverseDerefChainToCalculateFinalAddress(targetPointerDeref, pointerTr.resultReg)
|
||||
|
||||
val instr = when {
|
||||
targetPointerDeref.type.isByteOrBool -> {
|
||||
@@ -977,37 +977,33 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
addInstr(result, if(constAddress!=null)
|
||||
addInstr(result, if (constAddress != null)
|
||||
IRInstruction(Opcode.INCM, vmDt, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
||||
, null)
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null)
|
||||
}
|
||||
else {
|
||||
val tr = expressionEval.translateExpression(operand)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, if(constAddress!=null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, address = constAddress)
|
||||
addInstr(result, if (constAddress != null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol)
|
||||
, null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) , null)
|
||||
}
|
||||
} else {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
addInstr(result, if(constAddress!=null)
|
||||
addInstr(result, if (constAddress != null)
|
||||
IRInstruction(Opcode.INCM, vmDt, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
||||
, null)
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null)
|
||||
}
|
||||
else {
|
||||
val tr = expressionEval.translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if(constAddress!=null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, address = constAddress)
|
||||
addInstr(result, if (constAddress != null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol)
|
||||
, null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) , null)
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -101,7 +101,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = translateExpression(deref.start)
|
||||
result += tr.chunks
|
||||
result += traverseDerefChain(deref, tr.resultReg)
|
||||
result += traverseDerefChainToCalculateFinalAddress(deref, tr.resultReg)
|
||||
when {
|
||||
deref.type.isByteOrBool -> {
|
||||
val resultReg = codeGen.registers.next(IRDataType.BYTE)
|
||||
@@ -199,8 +199,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
fun loadAddressOfArrayLabel(reg: Int) {
|
||||
if (expr.isMsbForSplitArray) {
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier.name + "_msb"), null)
|
||||
} else if (identifier.type.isSplitWordArray) {
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier!!.name + "_msb"), null)
|
||||
} else if (identifier!!.type.isSplitWordArray) {
|
||||
// the _lsb split array comes first in memory
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier.name + "_lsb"), null)
|
||||
} else
|
||||
@@ -213,25 +213,35 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val indexTr = translateExpression(expr.arrayIndexExpr!!)
|
||||
addToResult(result, indexTr, indexTr.resultReg, -1)
|
||||
val indexWordReg = codeGen.registers.next(IRDataType.WORD)
|
||||
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=indexWordReg, reg2=indexTr.resultReg), null)
|
||||
if(identifier.type.isUnsignedWord) {
|
||||
addInstr(
|
||||
result,
|
||||
IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1 = indexWordReg, reg2 = indexTr.resultReg),
|
||||
null
|
||||
)
|
||||
if (identifier!!.type.isUnsignedWord) {
|
||||
require(!expr.isMsbForSplitArray)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = identifier.name)
|
||||
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg)
|
||||
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1 = resultRegister, reg2 = indexWordReg)
|
||||
}
|
||||
} else {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(identifier.type, 1)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
loadAddressOfArrayLabel(resultRegister)
|
||||
if(eltSize>1 && !identifier.type.isSplitWordArray) {
|
||||
it += IRInstruction(Opcode.MUL, IRDataType.WORD, reg1=indexWordReg, immediate = eltSize)
|
||||
if (eltSize > 1 && !identifier.type.isSplitWordArray) {
|
||||
it += IRInstruction(Opcode.MUL, IRDataType.WORD, reg1 = indexWordReg, immediate = eltSize)
|
||||
}
|
||||
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg)
|
||||
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1 = resultRegister, reg2 = indexWordReg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if(expr.identifier!=null ) {
|
||||
loadAddressOfArrayLabel(resultRegister)
|
||||
} else {
|
||||
require(vmDt==IRDataType.WORD)
|
||||
val pointerTr = translateExpression(expr.dereference!!.start)
|
||||
result += pointerTr.chunks
|
||||
result += traverseDerefChainToCalculateFinalAddress(expr.dereference!!, pointerTr.resultReg)
|
||||
addInstr(result, IRInstruction(Opcode.LOADR, IRDataType.WORD, reg1 = resultRegister, reg2 = pointerTr.resultReg), null)
|
||||
}
|
||||
return ExpressionCodeResult(result, vmDt, resultRegister, -1)
|
||||
}
|
||||
@@ -1473,7 +1483,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun traverseDerefChain(targetPointerDeref: PtPointerDeref, pointerReg: Int): IRCodeChunks {
|
||||
internal fun traverseDerefChainToCalculateFinalAddress(targetPointerDeref: PtPointerDeref, pointerReg: Int): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
var struct: StStruct? = null
|
||||
if(targetPointerDeref.start.type.subIdentifier!=null)
|
||||
|
||||
@@ -27,8 +27,8 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
|
||||
// @( &thing ) --> thing (but only if thing is a byte type!)
|
||||
val addrOf = memread.addressExpression as? AddressOf
|
||||
if(addrOf!=null) {
|
||||
if(addrOf.identifier.inferType(program).isBytes)
|
||||
return listOf(IAstModification.ReplaceNode(memread, addrOf.identifier, parent))
|
||||
if(addrOf.identifier?.inferType(program)?.isBytes==true)
|
||||
return listOf(IAstModification.ReplaceNode(memread, addrOf.identifier!!, parent))
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
@@ -29,7 +29,14 @@ class StatementOptimizer(private val program: Program,
|
||||
if(functionCallStatement.target.nameInSource==listOf("txt", "print")) {
|
||||
val arg = functionCallStatement.args.single()
|
||||
val stringVar: IdentifierReference? = if(arg is AddressOf) {
|
||||
if(arg.arrayIndex==null) arg.identifier else null
|
||||
if(arg.arrayIndex==null) {
|
||||
if(arg.identifier!=null)
|
||||
arg.identifier
|
||||
else
|
||||
null // struct can't have string fields so nothing to look at here
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
arg as? IdentifierReference
|
||||
}
|
||||
|
||||
@@ -713,7 +713,7 @@ internal class AstChecker(private val program: Program,
|
||||
|
||||
override fun visit(addressOf: AddressOf) {
|
||||
checkLongType(addressOf)
|
||||
val variable=addressOf.identifier.targetVarDecl()
|
||||
val variable=addressOf.identifier?.targetVarDecl()
|
||||
if (variable!=null) {
|
||||
if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null)
|
||||
errors.err("invalid pointer-of operand type", addressOf.position)
|
||||
@@ -1987,7 +1987,13 @@ internal class AstChecker(private val program: Program,
|
||||
val array = value.value.map {
|
||||
when (it) {
|
||||
is NumericLiteral -> it.number.toInt()
|
||||
is AddressOf -> it.identifier.nameInSource.hashCode() and 0xffff
|
||||
is AddressOf -> {
|
||||
if(it.identifier!=null)
|
||||
it.identifier!!.nameInSource.hashCode() and 0xffff
|
||||
else if(it.dereference!=null)
|
||||
it.dereference!!.identifier.nameInSource.hashCode() and 0xffff
|
||||
else 9999999
|
||||
}
|
||||
is IdentifierReference -> it.nameInSource.hashCode() and 0xffff
|
||||
is TypecastExpression if it.type.isBasic -> {
|
||||
val constVal = it.expression.constValue(program)
|
||||
|
||||
@@ -47,7 +47,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
|
||||
listOf(
|
||||
IAstModification.ReplaceNode(
|
||||
typecast,
|
||||
AddressOf(identifier, null, false, typecast.position),
|
||||
AddressOf(identifier, null, null, false, typecast.position),
|
||||
parent
|
||||
)
|
||||
)
|
||||
|
||||
@@ -282,8 +282,8 @@ _after:
|
||||
val addrOf = memread.addressExpression as? AddressOf
|
||||
if(addrOf?.arrayIndex!=null)
|
||||
return noModifications
|
||||
if(addrOf!=null && addrOf.identifier.inferType(program).isWords) {
|
||||
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier), memread.position)
|
||||
if(addrOf!=null && addrOf.identifier?.inferType(program)?.isWords==true) {
|
||||
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier!!), memread.position)
|
||||
return listOf(IAstModification.ReplaceNode(memread, lsb, parent))
|
||||
}
|
||||
val expr = memread.addressExpression as? BinaryExpression
|
||||
@@ -291,10 +291,10 @@ _after:
|
||||
val addressOf = expr.left as? AddressOf
|
||||
val offset = (expr.right as? NumericLiteral)?.number?.toInt()
|
||||
if(addressOf!=null && offset==1) {
|
||||
val variable = addressOf.identifier.targetVarDecl()
|
||||
val variable = addressOf.identifier?.targetVarDecl()
|
||||
if(variable!=null && variable.datatype.isWord) {
|
||||
val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), memread.position), mutableListOf(
|
||||
addressOf.identifier
|
||||
addressOf.identifier!!
|
||||
), memread.position)
|
||||
return listOf(IAstModification.ReplaceNode(memread, msb, parent))
|
||||
}
|
||||
|
||||
@@ -652,9 +652,12 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
||||
|
||||
private fun transform(src: AddressOf): PtAddressOf {
|
||||
val addr = PtAddressOf(src.position, src.msb)
|
||||
addr.add(transform(src.identifier))
|
||||
if(src.identifier!=null)
|
||||
addr.add(transform(src.identifier!!))
|
||||
if (src.arrayIndex != null)
|
||||
addr.add(transformExpression(src.arrayIndex!!.indexExpr))
|
||||
if (src.dereference!=null)
|
||||
addr.add(transformExpression(src.dereference!!))
|
||||
return addr
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
if(!argDt.isString) {
|
||||
modifications += IAstModification.ReplaceNode(
|
||||
identifier,
|
||||
AddressOf(identifier, null, false, it.second.position),
|
||||
AddressOf(identifier, null, null, false, it.second.position),
|
||||
call as Node
|
||||
)
|
||||
}
|
||||
@@ -285,7 +285,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
// take the address of the identifier
|
||||
modifications += IAstModification.ReplaceNode(
|
||||
identifier,
|
||||
AddressOf(identifier, null, false, it.second.position),
|
||||
AddressOf(identifier, null, null, false, it.second.position),
|
||||
call as Node
|
||||
)
|
||||
}
|
||||
@@ -410,7 +410,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
val eltType = elt.inferType(program)
|
||||
val tgt = elt.targetStatement(program)
|
||||
if(eltType.isIterable || tgt is Subroutine || tgt is Label || tgt is Block) {
|
||||
val addressof = AddressOf(elt, null, false, elt.position)
|
||||
val addressof = AddressOf(elt, null, null, false, elt.position)
|
||||
addressof.linkParents(array)
|
||||
array.value[index] = addressof
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class TestCompilerOnImportsAndIncludes: FunSpec({
|
||||
str0.value shouldBe "main.bar"
|
||||
str0.definingScope.name shouldBe "main"
|
||||
|
||||
val id1 = (args[1] as AddressOf).identifier
|
||||
val id1 = (args[1] as AddressOf).identifier!!
|
||||
val lbl1 = id1.targetStatement(program) as Label
|
||||
lbl1.name shouldBe "foo_bar"
|
||||
lbl1.definingScope.name shouldBe "main"
|
||||
|
||||
@@ -325,7 +325,7 @@ main {
|
||||
val assignAddr = (st[2] as Assignment).value
|
||||
(assignAddr as NumericLiteral).number shouldBe 8194.0
|
||||
val assignAddr2 = ((st[9] as Assignment).value as AddressOf)
|
||||
assignAddr2.identifier.nameInSource shouldBe listOf("buffer")
|
||||
assignAddr2.identifier!!.nameInSource shouldBe listOf("buffer")
|
||||
assignAddr2.arrayIndex!!.indexExpr shouldBe instanceOf<BinaryExpression>()
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class TestIdentifierRef: FunSpec({
|
||||
val mstmts = (module.statements.single() as Block).statements
|
||||
val stmts = mstmts.filterIsInstance<Subroutine>().single().statements
|
||||
val wwref = (stmts[0] as Assignment).target.identifier!!
|
||||
val mainref = ((stmts[1] as Assignment).value as AddressOf).identifier
|
||||
val mainref = ((stmts[1] as Assignment).value as AddressOf).identifier!!
|
||||
wwref.nameInSource shouldBe listOf("ww")
|
||||
wwref.wasStringLiteral() shouldBe false
|
||||
wwref.targetStatement(program) shouldBe instanceOf<VarDecl>()
|
||||
|
||||
@@ -65,13 +65,13 @@ class TestAsmGenSymbols: StringSpec({
|
||||
position = 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), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
|
||||
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
|
||||
val subroutine = Subroutine("start", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY)
|
||||
@@ -118,13 +118,13 @@ class TestAsmGenSymbols: StringSpec({
|
||||
val localvarIdent = sub.children.asSequence().filterIsInstance<PtAssignment>().first { it.value is PtIdentifier }.value as PtIdentifier
|
||||
asmgen.asmSymbolName(localvarIdent) shouldBe "localvar"
|
||||
asmgen.asmVariableName(localvarIdent) shouldBe "localvar"
|
||||
val localvarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier
|
||||
val localvarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier!!
|
||||
asmgen.asmSymbolName(localvarIdentScoped) shouldBe "localvar"
|
||||
asmgen.asmVariableName(localvarIdentScoped) shouldBe "localvar"
|
||||
val scopedVarIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier
|
||||
val scopedVarIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier!!
|
||||
asmgen.asmSymbolName(scopedVarIdent) shouldBe "main.var_outside"
|
||||
asmgen.asmVariableName(scopedVarIdent) shouldBe "main.var_outside"
|
||||
val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier
|
||||
val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier!!
|
||||
asmgen.asmSymbolName(scopedVarIdentScoped) shouldBe "main.var_outside"
|
||||
asmgen.asmVariableName(scopedVarIdentScoped) shouldBe "main.var_outside"
|
||||
}
|
||||
@@ -134,17 +134,17 @@ class TestAsmGenSymbols: StringSpec({
|
||||
val asmgen = createTestAsmGen6502(program)
|
||||
val sub = asmgen.program.entrypoint()!!
|
||||
|
||||
val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier
|
||||
val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier!!
|
||||
asmgen.asmSymbolName(localLabelIdent) shouldBe "locallabel"
|
||||
asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel"
|
||||
val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier
|
||||
val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier!!
|
||||
asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "locallabel"
|
||||
asmgen.asmVariableName(localLabelIdentScoped) shouldBe "locallabel"
|
||||
|
||||
val scopedLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier
|
||||
val scopedLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier!!
|
||||
asmgen.asmSymbolName(scopedLabelIdent) shouldBe "main.label_outside"
|
||||
asmgen.asmVariableName(scopedLabelIdent) shouldBe "main.label_outside"
|
||||
val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier
|
||||
val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier!!
|
||||
asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main.label_outside"
|
||||
asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside"
|
||||
}
|
||||
|
||||
@@ -482,12 +482,13 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
||||
output("&")
|
||||
if(addressOf.msb)
|
||||
output(">")
|
||||
addressOf.identifier.accept(this)
|
||||
addressOf.identifier?.accept(this)
|
||||
if (addressOf.arrayIndex != null) {
|
||||
output("[")
|
||||
addressOf.arrayIndex?.accept(this)
|
||||
output("]")
|
||||
}
|
||||
addressOf.dereference?.accept(this)
|
||||
}
|
||||
|
||||
override fun visit(inlineAssembly: InlineAssembly) {
|
||||
|
||||
@@ -632,10 +632,10 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi
|
||||
val msb = addressOf.ADDRESS_OF_MSB()!=null
|
||||
// note: &< (ADDRESS_OF_LSB) is equivalent to a regular &.
|
||||
return if (identifier != null)
|
||||
AddressOf(addressof().scoped_identifier().toAst(),null, msb, toPosition())
|
||||
AddressOf(addressof().scoped_identifier().toAst(),null, null, msb, toPosition())
|
||||
else {
|
||||
val array = addressOf.arrayindexed()
|
||||
AddressOf(array.scoped_identifier().toAst(), array.arrayindex().toAst(), msb, toPosition())
|
||||
AddressOf(array.scoped_identifier().toAst(), array.arrayindex().toAst(), null, msb, toPosition())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ sealed class Expression: Node {
|
||||
(other is TypecastExpression && other.implicit==implicit && other.type==type && other.expression isSameAs expression)
|
||||
}
|
||||
is AddressOf -> {
|
||||
(other is AddressOf && other.identifier.nameInSource == identifier.nameInSource && other.arrayIndex==arrayIndex)
|
||||
(other is AddressOf && other.identifier?.nameInSource == identifier?.nameInSource && other.arrayIndex==arrayIndex && other.dereference==dereference)
|
||||
}
|
||||
is RangeExpression -> {
|
||||
(other is RangeExpression && other.from==from && other.to==to && other.step==step)
|
||||
@@ -415,13 +415,14 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
|
||||
}
|
||||
}
|
||||
|
||||
data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayIndex?, val msb: Boolean, override val position: Position) : Expression() {
|
||||
data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: ArrayIndex?, var dereference: PtrDereference?, val msb: Boolean, override val position: Position) : Expression() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
identifier.linkParents(this)
|
||||
identifier?.linkParents(this)
|
||||
arrayIndex?.linkParents(this)
|
||||
dereference?.linkParents(this)
|
||||
}
|
||||
|
||||
override val isSimple = true
|
||||
@@ -432,8 +433,11 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
|
||||
if(replacement is IdentifierReference) {
|
||||
identifier = replacement
|
||||
arrayIndex = null
|
||||
dereference = null
|
||||
} else {
|
||||
TODO("replacement with $replacement")
|
||||
dereference = replacement as PtrDereference
|
||||
identifier = null
|
||||
arrayIndex = null
|
||||
}
|
||||
}
|
||||
node===arrayIndex -> {
|
||||
@@ -447,11 +451,11 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
|
||||
replacement.parent = this
|
||||
}
|
||||
|
||||
override fun copy() = AddressOf(identifier.copy(), arrayIndex?.copy(), msb, position)
|
||||
override fun copy() = AddressOf(identifier?.copy(), arrayIndex?.copy(), dereference?.copy(), msb, position)
|
||||
override fun constValue(program: Program): NumericLiteral? {
|
||||
if(msb)
|
||||
return null
|
||||
val target = this.identifier.targetStatement(program)
|
||||
val target = this.identifier?.targetStatement(program)
|
||||
val targetVar = target as? VarDecl
|
||||
if(targetVar!=null) {
|
||||
if (targetVar.type == VarDeclType.MEMORY || targetVar.type == VarDeclType.CONST) {
|
||||
@@ -482,7 +486,7 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
|
||||
}
|
||||
return null
|
||||
}
|
||||
override fun referencesIdentifier(nameInSource: List<String>) = identifier.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true
|
||||
override fun referencesIdentifier(nameInSource: List<String>) = identifier?.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true || dereference?.referencesIdentifier(nameInSource)==true
|
||||
override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.UWORD)
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
||||
|
||||
@@ -269,7 +269,7 @@ class VarDecl(val type: VarDeclType,
|
||||
// parameter variable memory mapped to a R0-R15 virtual register
|
||||
val regname = param.registerOrPair.asScopedNameVirtualReg(param.type)
|
||||
decltype = VarDeclType.MEMORY
|
||||
value = AddressOf(IdentifierReference(regname, param.position), null, false, param.position)
|
||||
value = AddressOf(IdentifierReference(regname, param.position), null, null, false, param.position)
|
||||
}
|
||||
val dt = if(param.type.isArray) DataType.UWORD else param.type
|
||||
return VarDecl(decltype, VarDeclOrigin.SUBROUTINEPARAM, dt, param.zp, SplitWish.DONTCARE, null, param.name, emptyList(), value,
|
||||
@@ -667,9 +667,10 @@ data class AssignTarget(
|
||||
multi != null -> false
|
||||
pointerDereference !=null -> {
|
||||
if(value is PtrDereference) {
|
||||
if(pointerDereference!!.identifier!=value.identifier || pointerDereference!!.field!=value.field)
|
||||
return false
|
||||
TODO("compare ptrderef chains")
|
||||
return if(pointerDereference!!.identifier!=value.identifier || pointerDereference!!.field!=value.field)
|
||||
false
|
||||
else
|
||||
pointerDereference!!.chain == value.chain
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -481,8 +481,9 @@ abstract class AstWalker {
|
||||
|
||||
fun visit(addressOf: AddressOf, parent: Node) {
|
||||
track(before(addressOf, parent), addressOf, parent)
|
||||
addressOf.identifier.accept(this, addressOf)
|
||||
addressOf.identifier?.accept(this, addressOf)
|
||||
addressOf.arrayIndex?.accept(this)
|
||||
addressOf.dereference?.accept(this, addressOf)
|
||||
track(after(addressOf, parent), addressOf, parent)
|
||||
}
|
||||
|
||||
|
||||
@@ -185,8 +185,9 @@ interface IAstVisitor {
|
||||
}
|
||||
|
||||
fun visit(addressOf: AddressOf) {
|
||||
addressOf.identifier.accept(this)
|
||||
addressOf.identifier?.accept(this)
|
||||
addressOf.arrayIndex?.accept(this)
|
||||
addressOf.dereference?.accept(this)
|
||||
}
|
||||
|
||||
fun visit(inlineAssembly: InlineAssembly) {
|
||||
|
||||
@@ -101,7 +101,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
}
|
||||
|
||||
override fun visit(addressOf: AddressOf) {
|
||||
addressOf.identifier.targetSubroutine()?.let { notCalledButReferenced.add(it) }
|
||||
addressOf.identifier?.targetSubroutine()?.let { notCalledButReferenced.add(it) }
|
||||
super.visit(addressOf)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@ STRUCTS and TYPED POINTERS
|
||||
'DONE' means working in the 'virtual' compiler target... (no 6502 codegen has been touched yet)
|
||||
|
||||
- DONE: add ast type check for assignments to struct fields; node_ptr.nextnode = enemy_ptr should error
|
||||
- ubyte_ptr^^ ++ doesn't get changed to an inplace-assign whereas x++ does
|
||||
- add IR LOADPIX/STOREPIX instructions for efficient field access through a pointer var?
|
||||
- change IR instruction LOADI should allow reg1 and reg2 to be the same, so we can remove the extra 'newPointerReg'.
|
||||
- DONE: declare struct as a separate entity so you can then declare multiple variables (pointers) of the same struct type. Like usual.
|
||||
- struct is a 'packed' struct, fields are placed in order of declaration. This guarantees exact size and place of the fields
|
||||
- structs only supported as a reference type (uword pointer). This removes a lot of the problems related to introducing a variable length value type.
|
||||
- need to introduce typed pointer datatype in prog8 to allow this to make any sense. + correct code gen
|
||||
- initially only a pointer-to-struct should actually work, pointer-to-other-type is possible but that can come later.
|
||||
- DONE: struct is a 'packed' struct, fields are placed in order of declaration. This guarantees exact size and place of the fields
|
||||
- DONE: structs only supported as a reference type (uword pointer). This removes a lot of the problems related to introducing a variable length value type.
|
||||
- DONE: need to introduce typed pointer datatype in prog8 to allow this to make any sense. + correct code gen
|
||||
- DONE: initially only a pointer-to-struct should actually work, pointer-to-other-type is possible but that can come later.
|
||||
- DONE: a struct can contain only numeric type fields (byte,word,float) - no nested structs, no reference types (strings, arrays) inside structs.
|
||||
- DONE: struct might also contain typed pointer fields (because a pointer is just an address word)
|
||||
- DONE: max 1 page of memory total size to allow regular register indexing
|
||||
@@ -22,14 +22,16 @@ STRUCTS and TYPED POINTERS
|
||||
- DONE: dereferencing a pointer to struct could look like Pascal's ptr^.field as well, but the ^ is actually redundant here; compiler already knows it's a pointer type.
|
||||
Note that actually dereferencing a pointer to a struct as an explicit operation, conflicts with the third axiom on this list (structs only as reference types) so it can only be done for basic types?
|
||||
So... setting struct fields can simply be ``structvar.field = 42`` and reading them ``a = structvar.field``
|
||||
- you should be able to get the address of an individual field: ``&structpointer.field``
|
||||
- arrays of structs? Just an array of uword pointers to said structs. Can even be @split as the only representation form because that's the default for word arrays.
|
||||
- DONE: you should be able to get the address of an individual field: ``&structpointer.field``
|
||||
- DONE: need to teach sizeof() how to calculate struct sizes (need unit test + doc)
|
||||
- arrays of structs? Just an array of uword pointers to said structs. Can even be @split as the only representation form because that's the default for word arrays.
|
||||
- static initialization of structs may be allowed only at block scope and then behaves like arrays; it won't reset to the original value when program is restarted, so beware. Syntax = TBD
|
||||
- allow memory-mapped structs? Something like &Sprite sprite0 = $9000 basically behaves identically to a typed pointer, but the address is immutable as usual
|
||||
- existing STR and ARRAY remain unchanged (don't become typed pointers) so we can keep doing register-indexed addressing directly on them
|
||||
- rather than str or uword parameter types for routines with a string argument, use ^str (or ^ubyte maybe? these are more or less identical..?)
|
||||
- same for arrays? pointer-to-array syntax = TBD
|
||||
- what about pointers to subroutines? should these be typed as well now?
|
||||
- asm symbol name prefixing should work for dereferences too.
|
||||
- pointer arithmetic is a pain, but need to follow C? ptr=ptr+10 adds 10*sizeof() instead of just 10.
|
||||
|
||||
|
||||
|
||||
@@ -75,19 +75,20 @@ main {
|
||||
node_ptr.nextnode.nextnode.nextnode.nextnode.nextnode.value = 888
|
||||
cx16.r0=node_ptr.nextnode.nextnode.nextnode.nextnode.value
|
||||
|
||||
; BELOW DOESN'T WORK YET:
|
||||
; address of fields
|
||||
txt.print("address of field: ")
|
||||
txt.print_uw(&enemy_ptr.alive)
|
||||
txt.spc()
|
||||
enemy_ptr = 8000
|
||||
txt.print_uw(&enemy_ptr.alive)
|
||||
txt.nl()
|
||||
|
||||
; ubyte_ptr^^ ++
|
||||
|
||||
|
||||
; BELOW DOESN'T WORK YET:
|
||||
; pointer arithmetic
|
||||
; ubyte_ptr^^ ++
|
||||
; enemy_ptr ++ ; add 1*sizeof
|
||||
; enemy_ptr += 10 ; add 10*sizeof
|
||||
|
||||
|
||||
; TODO how to statically allocate/initialize a struct? Difficult.. see TODO in docs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
is PtAddressOf -> {
|
||||
when {
|
||||
it.isFromArrayElement -> TODO("address-of array element $it in initial array value")
|
||||
else -> StArrayElement(null, it.identifier.name, null)
|
||||
else -> StArrayElement(null, it.identifier!!.name, null)
|
||||
}
|
||||
}
|
||||
is PtNumber -> StArrayElement(it.number, null, null)
|
||||
|
||||
@@ -27,7 +27,17 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
||||
return false
|
||||
if (other.type!==type)
|
||||
return false
|
||||
if(!(other.identifier isSameAs identifier))
|
||||
if(other.identifier==null && identifier!=null)
|
||||
return false
|
||||
if(other.identifier!=null && identifier==null)
|
||||
return false
|
||||
if(other.identifier!=null && identifier!=null && !(other.identifier!! isSameAs identifier!!))
|
||||
return false
|
||||
if(other.dereference==null && identifier!=dereference)
|
||||
return false
|
||||
if(other.dereference!=null && identifier==dereference)
|
||||
return false
|
||||
if(other.dereference!=null && dereference!=null && !(other.dereference!! isSameAs dereference!!))
|
||||
return false
|
||||
if(other.children.size!=children.size)
|
||||
return false
|
||||
@@ -141,8 +151,10 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
||||
}
|
||||
|
||||
class PtAddressOf(position: Position, val isMsbForSplitArray: Boolean=false) : PtExpression(DataType.UWORD, position) {
|
||||
val identifier: PtIdentifier
|
||||
get() = children[0] as PtIdentifier
|
||||
val identifier: PtIdentifier?
|
||||
get() = children[0] as? PtIdentifier
|
||||
val dereference: PtPointerDeref?
|
||||
get() = children[0] as? PtPointerDeref
|
||||
val arrayIndexExpr: PtExpression?
|
||||
get() = if(children.size==2) children[1] as PtExpression else null
|
||||
|
||||
|
||||
@@ -32,7 +32,12 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
is PtBool -> it.toString()
|
||||
is PtNumber -> it.number.toString()
|
||||
is PtIdentifier -> it.name
|
||||
is PtAddressOf -> "& ${it.identifier.name}"
|
||||
is PtAddressOf -> {
|
||||
if(it.identifier!=null)
|
||||
"& ${it.identifier!!.name}"
|
||||
else
|
||||
"& ${txt(it.dereference!!)}"
|
||||
}
|
||||
else -> "invalid array element $it"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user