mirror of
https://github.com/irmen/prog8.git
synced 2025-11-03 04:17:16 +00:00
revert & to untyped pointer, added && for typed pointer address-of
This commit is contained in:
@@ -39,14 +39,14 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
|
||||
listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
|
||||
} else {
|
||||
listOf(IAstModification.ReplaceNode(typecast,
|
||||
AddressOf(identifier, null, null, false, typecast.position), parent))
|
||||
AddressOf(identifier, null, null, false, false,typecast.position), parent))
|
||||
}
|
||||
} else if (typecast.expression is IFunctionCall) {
|
||||
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
|
||||
}
|
||||
} else if(sourceDt.isString && typecast.type.isPointer && typecast.type.sub==BaseDataType.UBYTE) {
|
||||
// casting a string to a ^^ubyte is just taking the address of the string.
|
||||
val addr = AddressOf(typecast.expression as IdentifierReference, null, null, false, typecast.position)
|
||||
val addr = AddressOf(typecast.expression as IdentifierReference, null, null, false, true, typecast.position)
|
||||
return listOf(IAstModification.ReplaceNode(typecast, addr, parent))
|
||||
} else {
|
||||
errors.err("cannot cast pass-by-reference value to type ${typecast.type} (only to UWORD)", typecast.position)
|
||||
|
||||
@@ -317,7 +317,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
if(!argDt.isString || it.second is IdentifierReference) {
|
||||
modifications += IAstModification.ReplaceNode(
|
||||
identifier,
|
||||
AddressOf(identifier, null, null, false, it.second.position),
|
||||
AddressOf(identifier, null, null, false, true, it.second.position),
|
||||
call as Node
|
||||
)
|
||||
}
|
||||
@@ -337,7 +337,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
// take the address of the identifier
|
||||
modifications += IAstModification.ReplaceNode(
|
||||
identifier,
|
||||
AddressOf(identifier, null, null, false, it.second.position),
|
||||
AddressOf(identifier, null, null, false, false,it.second.position),
|
||||
call as Node
|
||||
)
|
||||
} else if(dt.isUnknown) {
|
||||
@@ -346,7 +346,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
// take the address of the subroutine or label
|
||||
modifications += IAstModification.ReplaceNode(
|
||||
identifier,
|
||||
AddressOf(identifier, null, null, false, it.second.position),
|
||||
AddressOf(identifier, null, null, false, false, it.second.position),
|
||||
call as Node
|
||||
)
|
||||
}
|
||||
@@ -481,7 +481,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
val eltType = elt.inferType(program)
|
||||
val tgt = elt.targetStatement()
|
||||
if(eltType.isIterable || tgt is Subroutine || tgt is Label || tgt is Block) {
|
||||
val addressof = AddressOf(elt, null, null, false, elt.position)
|
||||
val addressof = AddressOf(elt, null, null, false, false, elt.position)
|
||||
addressof.linkParents(array)
|
||||
array.value[index] = addressof
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ import prog8.ast.expressions.ArrayIndexedExpression
|
||||
import prog8.ast.expressions.DirectMemoryRead
|
||||
import prog8.ast.expressions.PtrDereference
|
||||
import prog8.ast.statements.*
|
||||
import prog8.code.ast.PtAssignment
|
||||
import prog8.code.ast.PtReturn
|
||||
import prog8.code.ast.PtSubSignature
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.IMemSizer
|
||||
@@ -585,7 +583,7 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
test("type of & operator (address-of)") {
|
||||
test("internal type for address-of") {
|
||||
DataType.BYTE.typeForAddressOf(false) shouldBe DataType.pointer(BaseDataType.BYTE)
|
||||
DataType.WORD.typeForAddressOf(false) shouldBe DataType.pointer(BaseDataType.WORD)
|
||||
DataType.FLOAT.typeForAddressOf(false) shouldBe DataType.pointer(BaseDataType.FLOAT)
|
||||
@@ -605,6 +603,31 @@ main {
|
||||
DataType.pointer(BaseDataType.BOOL).typeForAddressOf(false) shouldBe DataType.UWORD
|
||||
}
|
||||
|
||||
test("untyped and typed address-of operators") {
|
||||
val src="""
|
||||
%option enable_floats
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
float f
|
||||
cx16.r0 = &f+1
|
||||
cx16.r1 = &&f+1
|
||||
}
|
||||
}"""
|
||||
|
||||
val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = true)!!
|
||||
val st = result.codegenAst!!.entrypoint()!!.children
|
||||
st.size shouldBe 6
|
||||
val r0v = (st[3] as PtAssignment).value as PtBinaryExpression
|
||||
val r1v = (st[4] as PtAssignment).value as PtBinaryExpression
|
||||
r0v.left shouldBe instanceOf<PtAddressOf>()
|
||||
r0v.right shouldBe instanceOf<PtNumber>()
|
||||
(r0v.right as PtNumber).number shouldBe 1.0
|
||||
r1v.left shouldBe instanceOf<PtAddressOf>()
|
||||
r1v.right shouldBe instanceOf<PtNumber>()
|
||||
(r1v.right as PtNumber).number shouldBe VMTarget.FLOAT_MEM_SIZE
|
||||
}
|
||||
|
||||
test("address-of struct fields") {
|
||||
val src="""
|
||||
%option enable_floats
|
||||
@@ -1375,7 +1398,7 @@ main {
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(VMTarget(), false, src, outputDir, errors = errors) shouldBe null
|
||||
errors.errors.size shouldBe 999
|
||||
// TODO
|
||||
// TODO implement this test
|
||||
}
|
||||
|
||||
xtest("array of pointers as subroutine param") {
|
||||
|
||||
@@ -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, 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 assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), null, null, false, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, null, false, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, null, false, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, null, false, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, null, false, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, null, false, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, null, false, 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)
|
||||
|
||||
@@ -280,10 +280,17 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
|
||||
val msb = ctx.ADDRESS_OF_MSB()!=null
|
||||
// note: &< (ADDRESS_OF_LSB) is equivalent to a regular &.
|
||||
val index = ctx.arrayindex()?.accept(this) as? ArrayIndex
|
||||
return if(index!=null) {
|
||||
AddressOf(identifier, index, null, msb, ctx.toPosition())
|
||||
var typed = false
|
||||
if(ctx.TYPED_ADDRESS_OF()!=null) {
|
||||
// new typed AddressOf
|
||||
if(msb)
|
||||
throw SyntaxError("typed address of not allowed with msb", ctx.toPosition())
|
||||
typed = true
|
||||
}
|
||||
return if (index != null) {
|
||||
AddressOf(identifier, index, null, msb, typed, ctx.toPosition())
|
||||
} else {
|
||||
AddressOf(identifier,null, null, msb, ctx.toPosition())
|
||||
AddressOf(identifier, null, null, msb, typed, ctx.toPosition())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -502,7 +502,8 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
|
||||
}
|
||||
}
|
||||
|
||||
data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: ArrayIndex?, var dereference: PtrDereference?, val msb: Boolean, override val position: Position) : Expression() {
|
||||
data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: ArrayIndex?, var dereference: PtrDereference?,
|
||||
val msb: Boolean, val typed: Boolean, override val position: Position) : Expression() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
@@ -538,7 +539,7 @@ data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: Array
|
||||
replacement.parent = this
|
||||
}
|
||||
|
||||
override fun copy() = AddressOf(identifier?.copy(), arrayIndex?.copy(), dereference?.copy(), msb, position)
|
||||
override fun copy() = AddressOf(identifier?.copy(), arrayIndex?.copy(), dereference?.copy(), msb, typed, position)
|
||||
override fun constValue(program: Program): NumericLiteral? {
|
||||
if(msb)
|
||||
return null
|
||||
@@ -574,8 +575,9 @@ data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: Array
|
||||
return null
|
||||
}
|
||||
override fun referencesIdentifier(nameInSource: List<String>) = identifier?.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true || dereference?.referencesIdentifier(nameInSource)==true
|
||||
// override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(BaseDataType.UWORD) // TODO orignal behavior
|
||||
override fun inferType(program: Program): InferredTypes.InferredType {
|
||||
if(!typed)
|
||||
return InferredTypes.knownFor(BaseDataType.UWORD) // orignal pre-v12 untyped AddressOf
|
||||
if(identifier!=null) {
|
||||
val type = identifier!!.inferType(program).getOrUndef()
|
||||
val addrofDt = type.typeForAddressOf(msb)
|
||||
|
||||
@@ -270,7 +270,7 @@ class VarDecl(
|
||||
// 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, null, false, param.position)
|
||||
value = AddressOf(IdentifierReference(regname, param.position), null, null, false, 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,
|
||||
|
||||
@@ -999,7 +999,7 @@ containment check: ``in``
|
||||
}
|
||||
|
||||
|
||||
address of: ``&``, ``&<``, ``&>``
|
||||
address of: ``&``, ``&<``, ``&>``, ``&&``
|
||||
This is a prefix operator that can be applied to a string or array variable or literal value.
|
||||
It results in the memory address (UWORD) of that string or array in memory: ``uword a = &stringvar``
|
||||
Sometimes the compiler silently inserts this operator to make it easier for instance
|
||||
@@ -1012,6 +1012,11 @@ address of: ``&``, ``&<``, ``&>``
|
||||
and MSB byte array separately, respectively. Note that ``&<`` is just the same as ``&`` in this case.
|
||||
For more details on split word arrays, see :ref:`arrayvars`.
|
||||
|
||||
**Typed pointer version:** the single ``&`` operator still returns an untyped uword address for
|
||||
backward compatibility reasons, so existing programs keep working. The *double ampersand* ``&&`` operator
|
||||
however returns a *typed* pointer to the value. The semantics are slightly different because adding or subtracting
|
||||
a number from a typed pointer uses *pointer arithmetic* that takes the size of the value that it points to into account.
|
||||
|
||||
|
||||
ternary:
|
||||
Prog8 doesn't have a ternary operator to choose one of two values (``x? y : z`` in many other languages)
|
||||
|
||||
@@ -81,3 +81,11 @@ Typed pointer to Struct type
|
||||
----------------------------
|
||||
|
||||
Work in progress.
|
||||
|
||||
|
||||
Address-Of: untyped vs typed
|
||||
----------------------------
|
||||
|
||||
``&`` still returns untyped (uword) pointer, as it did in older Prog8 versions. This is for backward compatibility reasons so existing programs don't break.
|
||||
The *double ampersand* operator ``&&`` returns a *typed* pointer to the value. The semantics are slightly different from the old untyped address-of operator, because adding or subtracting
|
||||
a number from a typed pointer uses *pointer arithmetic* that takes the size of the value that it points to into account.
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
What to do with the changed adress-of behavior? &x now returns a typed pointer to &x + 10 will now be calculated differently (C pointer arithmetic semantics rather than simply byte addition)
|
||||
compiler flag to select old behavior? new operator that has the new behavior? Don't want to break existing code that used &....
|
||||
Old behavior can be put back by always returning UWORD as the inferred type for AddressOf nodes
|
||||
|
||||
|
||||
STRUCTS and TYPED POINTERS
|
||||
--------------------------
|
||||
@@ -58,6 +54,7 @@ STRUCTS and TYPED POINTERS
|
||||
- DONE: fix _msb/_lsb storage of the split-words pointer-arrays
|
||||
- DONE: what about static initialization of an array of struct pointers? -> impossible right now because the pointer values are not constants.
|
||||
- DONE: make typeForAddressOf() be even more specific about the typed pointers it returns for the address-of operator.
|
||||
- DONE: existing '&' address-of still returns untyped uword (for backward compatibility). New '&&' operator returns typed pointer.
|
||||
- DONE: allow list1^^ = list2^^ (value wise assignment of List structures) by replacing it with a sys.memcopy(list2, list1, sizeof(List)) call.
|
||||
- DONE: allow a.b.ptr[i].value (equiv to a.b.ptr[i]^^.value) expressions (assignment target doesn't parse yet, see below)
|
||||
- DONE: check passing arrays to typed ptr sub-parameters. NOTE: word array can only be a @nosplit array if the parameter type is ^^word, because the words need to be sequential in memory there
|
||||
|
||||
@@ -5,48 +5,23 @@
|
||||
|
||||
main {
|
||||
|
||||
ubyte @shared thingIndex = 10
|
||||
uword[20] @shared dummy
|
||||
uword[10] @split curframesplit
|
||||
uword[10] @nosplit curframe
|
||||
uword p1, p2
|
||||
float f
|
||||
|
||||
sub start() {
|
||||
classic()
|
||||
; new()
|
||||
}
|
||||
|
||||
sub classic() {
|
||||
txt.print("float pointer+1: ")
|
||||
txt.print("classic float pointer+1: ")
|
||||
txt.print_uwhex(&f, true)
|
||||
txt.spc()
|
||||
txt.print_uwhex(&f + 1, true)
|
||||
txt.spc()
|
||||
txt.print_uw(&f + 1 - &f)
|
||||
txt.nl()
|
||||
|
||||
p1 = &curframesplit[thingIndex]
|
||||
p2 = &curframe[thingIndex]
|
||||
|
||||
txt.print("&array (split): ")
|
||||
txt.print_uwhex(&curframesplit, true)
|
||||
txt.print("typed float pointer+1: ")
|
||||
txt.print_uwhex(&&f, true)
|
||||
txt.spc()
|
||||
txt.print_uwhex(p1, true)
|
||||
txt.print_uwhex(&&f + 1, true)
|
||||
txt.spc()
|
||||
txt.print_uw(p1 - &curframesplit)
|
||||
txt.spc()
|
||||
txt.print_uwhex(p1 + &curframesplit, true)
|
||||
txt.nl()
|
||||
|
||||
txt.print("&array (normal): ")
|
||||
txt.print_uwhex(&curframe, true)
|
||||
txt.spc()
|
||||
txt.print_uwhex(p2, true)
|
||||
txt.spc()
|
||||
txt.print_uw(p2 - &curframe)
|
||||
txt.spc()
|
||||
txt.print_uwhex(p2 + &curframe, true)
|
||||
txt.print_uw(&&f + 1 - &&f)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
; 6502 data size: $0251
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ DEC_INTEGER : DEC_DIGIT (DEC_DIGIT | '_')* ;
|
||||
HEX_INTEGER : '$' HEX_DIGIT (HEX_DIGIT | '_')* ;
|
||||
BIN_INTEGER : '%' BIN_DIGIT (BIN_DIGIT | '_')* ;
|
||||
ADDRESS_OF: '&' ;
|
||||
TYPED_ADDRESS_OF: '&&' ;
|
||||
ADDRESS_OF_MSB: '&>' ;
|
||||
ADDRESS_OF_LSB: '&<' ;
|
||||
INVALID_AND_COMPOSITE: '&&' ;
|
||||
POINTER: '^^';
|
||||
|
||||
fragment HEX_DIGIT: ('a'..'f') | ('A'..'F') | ('0'..'9') ;
|
||||
@@ -241,7 +241,7 @@ typecast : 'as' datatype;
|
||||
|
||||
directmemory : '@' '(' expression ')';
|
||||
|
||||
addressof : <assoc=right> (ADDRESS_OF | ADDRESS_OF_LSB | ADDRESS_OF_MSB) scoped_identifier arrayindex? ;
|
||||
addressof : <assoc=right> (ADDRESS_OF | TYPED_ADDRESS_OF | | ADDRESS_OF_LSB | ADDRESS_OF_MSB) scoped_identifier arrayindex? ;
|
||||
|
||||
functioncall : scoped_identifier '(' expression_list? ')' ;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user