From 997bc21feb1168af5195ae8063b53c871afb8c95 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 23 Jan 2021 23:11:57 +0100 Subject: [PATCH] added offsetof() to get the byte offset of struct members. --- .../src/prog8/functions/BuiltinFunctions.kt | 23 ++++++++++ docs/source/programming.rst | 5 +++ docs/source/todo.rst | 1 - examples/test.p8 | 44 +++++++++++++++---- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 116aad288..e6d521a51 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -102,6 +102,7 @@ private val functionSignatures: List = listOf( FSignature("abs" , true, listOf(FParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length FSignature("sizeof" , true, listOf(FParam("object", DataType.values().toSet())), DataType.UBYTE, ::builtinSizeof), + FSignature("offsetof" , true, listOf(FParam("object", DataType.values().toSet())), DataType.UBYTE, ::builtinOffsetof), // normal functions follow: FSignature("sgn" , true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ), FSignature("sin" , true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sin) }, @@ -278,6 +279,28 @@ private fun builtinAbs(args: List, position: Position, program: Prog } } +private fun builtinOffsetof(args: List, position: Position, program: Program): NumericLiteralValue { + // 1 arg, type = anything, result type = ubyte + if(args.size!=1) + throw SyntaxError("offsetof requires one argument", position) + val idref = args[0] as? IdentifierReference + ?: throw SyntaxError("offsetof argument should be an identifier", position) + + val vardecl = idref.targetVarDecl(program.namespace)!! + val struct = vardecl.struct + if (struct == null || vardecl.datatype == DataType.STRUCT) + throw SyntaxError("offsetof can only be used on struct members", position) + + val membername = idref.nameInSource.last() + var offset = 0 + for(member in struct.statements) { + if((member as VarDecl).name == membername) + return NumericLiteralValue(DataType.UBYTE, offset, position) + offset += member.datatype.memorySize() + } + throw SyntaxError("undefined struct member", position) +} + private fun builtinSizeof(args: List, position: Position, program: Program): NumericLiteralValue { // 1 arg, type = anything, result type = ubyte if(args.size!=1) diff --git a/docs/source/programming.rst b/docs/source/programming.rst index be9105ad8..9ce1bfc5d 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -843,6 +843,11 @@ sizeof(name) For an 10 element array of floats, it is 50 (on the C-64, where a float is 5 bytes). Note: usually you will be interested in the number of elements in an array, use len() for that. +offsetof(membername) + Number of bytes from the start of a struct variable that this member variable is located. + For now, this only works on members of a declared struct variable and not yet on members + referenced from the struct type itself. This might be improved in a future version of the language. + swap(x, y) Swap the values of numerical variables (or memory locations) x and y in a fast way. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index e2db74815..c7d3c2fc2 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,7 +2,6 @@ TODO ==== -- add offsetof() to get the byte offset of struct members. - add any2(), all2(), max2(), min2(), reverse2(), sum2(), sort2() that take (array, startindex, length) arguments - optimize for loop iterations better to allow proper inx, cpx #value, bne loop instructions (like repeat loop) - why is there a beq _prog8_label_2_repeatend at the end of repeat loops? seems unused diff --git a/examples/test.p8 b/examples/test.p8 index 149056073..20b2118a7 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,6 +1,7 @@ %import textio %import diskio %import string +%import floats %zeropage basicsafe %option no_sysinit @@ -9,14 +10,41 @@ main { sub start() { - diskio.directory(8) - diskio.save(8, "blabla", $2000, 1024) - diskio.directory(8) - diskio.rename(8, "blabla", "newname") - diskio.directory(8) - diskio.delete(8, "newname") - diskio.directory(8) + struct SaveData { + ubyte galaxy + ubyte planet + uword cash + float flt + ubyte fuel + } + + SaveData data + + txt.print("size of struct: ") + txt.print_ub(sizeof(SaveData)) + txt.chrout(';') + txt.print_ub(sizeof(data)) + txt.chrout('\n') + + txt.print("offset of galaxy: ") + txt.print_ub(offsetof(data.galaxy)) + txt.chrout('\n') + + txt.print("offset of planet: ") + txt.print_ub(offsetof(data.planet)) + txt.chrout('\n') + + txt.print("offset of cash: ") + txt.print_ub(offsetof(data.cash)) + txt.chrout('\n') + + txt.print("offset of flt: ") + txt.print_ub(offsetof(data.flt)) + txt.chrout('\n') + + txt.print("offset of fuel: ") + txt.print_ub(offsetof(data.fuel)) + txt.chrout('\n') - txt.print("---------------------------------\n") } }