mirror of
https://github.com/irmen/prog8.git
synced 2026-04-20 11:17:01 +00:00
add offsetof()
This commit is contained in:
@@ -103,6 +103,7 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
|
||||
"abs__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
|
||||
"len" to FSignature(true, BaseDataType.UWORD, FParam("values", *IterableDatatypes)),
|
||||
"sizeof" to FSignature(true, BaseDataType.UBYTE, FParam("object", *(BaseDataType.entries - BaseDataType.STRUCT_INSTANCE).toTypedArray())),
|
||||
"offsetof" to FSignature(true, BaseDataType.UBYTE, FParam("field", BaseDataType.UBYTE)),
|
||||
"sgn" to FSignature(true, BaseDataType.BYTE, FParam("value", *NumericDatatypes)),
|
||||
"sqrt" to FSignature(true, null, FParam("value", *NumericDatatypes)),
|
||||
"sqrt__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE)),
|
||||
|
||||
@@ -54,6 +54,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
"prog8_lib_square_word" -> funcSquare(call, IRDataType.WORD)
|
||||
"prog8_lib_structalloc" -> funcStructAlloc(call)
|
||||
"sizeof" -> throw AssemblyError("sizeof must have been replaced with a constant")
|
||||
"offsetof" -> throw AssemblyError("offsetof must have been replaced with a constant")
|
||||
else -> throw AssemblyError("missing builtinfunc for ${call.name}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import prog8.ast.FatalAstException
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.SyntaxError
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.StructDecl
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.code.core.*
|
||||
import kotlin.math.*
|
||||
@@ -15,6 +16,7 @@ internal val constEvaluatorsForBuiltinFuncs: Map<String, ConstExpressionCaller>
|
||||
"abs" to ::builtinAbs,
|
||||
"len" to ::builtinLen,
|
||||
"sizeof" to ::builtinSizeof,
|
||||
"offsetof" to ::builtinOffsetof,
|
||||
"sgn" to ::builtinSgn,
|
||||
"sqrt__ubyte" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, false) { sqrt(it.toDouble()) } },
|
||||
"sqrt__uword" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, false) { sqrt(it.toDouble()) } },
|
||||
@@ -90,6 +92,25 @@ private fun builtinAbs(args: List<Expression>, position: Position, program: Prog
|
||||
else throw SyntaxError("abs requires one integer argument", position)
|
||||
}
|
||||
|
||||
private fun builtinOffsetof(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||
// 1 arg, "Struct.field"
|
||||
if(args.size!=1)
|
||||
throw SyntaxError("offsetof requires one argument", position)
|
||||
val identifier = (args[0] as? IdentifierReference)?.nameInSource
|
||||
if(identifier==null || identifier.size<2)
|
||||
throw CannotEvaluateException("offsetof","argument should be an identifier of the form Struct.field")
|
||||
|
||||
val structname = identifier.dropLast(1)
|
||||
val fieldname = identifier.last()
|
||||
val struct = args[0].definingScope.lookup(structname) as? StructDecl
|
||||
if(struct==null)
|
||||
throw SyntaxError("cannot find struct '$structname'", args[0].position)
|
||||
val offset = struct.offsetof(fieldname, program.memsizer)
|
||||
if(offset==null)
|
||||
throw SyntaxError("no such field '${identifier.joinToString(".")}'", args[0].position)
|
||||
return NumericLiteral.optimalInteger(offset.toInt(), position)
|
||||
}
|
||||
|
||||
private fun builtinSizeof(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||
// 1 arg, type = anything, result type = ubyte or uword
|
||||
if(args.size!=1)
|
||||
|
||||
@@ -414,6 +414,15 @@ class StructDecl(override val name: String, val fields: Array<Pair<DataType, Str
|
||||
|
||||
override fun getFieldType(name: String): DataType? = fields.firstOrNull { it.second==name }?.first
|
||||
override val scopedNameString by lazy { scopedName.joinToString(".") }
|
||||
|
||||
fun offsetof(fieldname: String, sizer: IMemSizer): UByte? {
|
||||
fields.fold(0) { offset, field ->
|
||||
if (field.second == fieldname)
|
||||
return offset.toUByte()
|
||||
offset + sizer.memorySize(field.first, 1)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class StructFieldRef(val pointer: IdentifierReference, val struct: StructDecl, val type: DataType, override val name: String, override val position: Position): Statement(), INamedStatement {
|
||||
|
||||
@@ -118,6 +118,11 @@ mkword (msb, lsb)
|
||||
Don't get confused by how the system actually stores this 16-bit word value in memory (which is
|
||||
in little-endian format, so lsb first then msb)
|
||||
|
||||
offsetof (Struct.field)
|
||||
The offset in bytes of the given field in the struct. The first field will always have offset 0.
|
||||
Usually you just reference the fields directly but in some cases it might be useful to know how many
|
||||
bytes from the start of the structure a field is located at.
|
||||
|
||||
peek (address)
|
||||
same as @(address) - reads the byte at the given address in memory.
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ and for example the below code omits line 5::
|
||||
STRUCTS and TYPED POINTERS
|
||||
--------------------------
|
||||
|
||||
- add offsetof()
|
||||
- fix code size regressions (if any left)
|
||||
- optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0
|
||||
- update structpointers.rst docs with 6502 specific things?
|
||||
|
||||
+44
-30
@@ -1,36 +1,50 @@
|
||||
%option enable_floats
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
struct Node {
|
||||
ubyte id
|
||||
str name
|
||||
uword array
|
||||
bool flag
|
||||
float perc
|
||||
}
|
||||
struct Foobar {
|
||||
bool thing
|
||||
}
|
||||
|
||||
sub start() {
|
||||
^^Node test = []
|
||||
txt.print("expected: 0 10 30\n")
|
||||
counter = 0
|
||||
txt.print_ub(nodefer(10))
|
||||
txt.spc()
|
||||
txt.print_ub(nodefer(20))
|
||||
txt.spc()
|
||||
txt.print_ub(nodefer(30))
|
||||
txt.nl()
|
||||
|
||||
test.id ++
|
||||
test.array += 1000
|
||||
test.id <<= 2
|
||||
test.id <<= cx16.r0L
|
||||
test.id >>= 3
|
||||
test.id >>= cx16.r0L
|
||||
test.id &= 1
|
||||
; test.id *= 5 ; TODO implement this
|
||||
; test.id /= 5 ; TODO implement this
|
||||
test.array ^= 1000
|
||||
test.array |= 1000
|
||||
test.array &= 1000
|
||||
test.array >>= 3
|
||||
test.array >>= cx16.r0L
|
||||
test.array <<= 2
|
||||
test.array <<= cx16.r0L
|
||||
test.array *= 5
|
||||
counter = 0
|
||||
txt.print_ub(add(10))
|
||||
txt.spc()
|
||||
txt.print_ub(add(20))
|
||||
txt.spc()
|
||||
txt.print_ub(add(30))
|
||||
txt.nl()
|
||||
|
||||
counter = 0
|
||||
txt.print_ub(add2(10))
|
||||
txt.spc()
|
||||
txt.print_ub(add2(20))
|
||||
txt.spc()
|
||||
txt.print_ub(add2(30))
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
ubyte counter = 0
|
||||
|
||||
sub nodefer(ubyte amount) -> ubyte {
|
||||
ubyte result = counter
|
||||
counter += amount
|
||||
return result
|
||||
}
|
||||
|
||||
sub add(ubyte amount) -> ubyte {
|
||||
defer counter += amount ; TODO FIX : BORKED!
|
||||
return counter
|
||||
}
|
||||
|
||||
sub add2(ubyte amount) -> ubyte {
|
||||
cx16.r0L = 0
|
||||
defer counter += amount
|
||||
return counter + cx16.r0L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<keywords keywords="&;&&;&<;&>;->;@;^^;alias;and;as;asmsub;break;clobbers;continue;do;downto;else;extsub;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;on;or;repeat;return;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" />
|
||||
<keywords2 keywords="%address;%align;%asm;%asmbinary;%asminclude;%breakpoint;%encoding;%import;%ir;%jmptable;%launcher;%memtop;%option;%output;%zeropage;%zpallowed;%zpreserved;@align64;@alignpage;@alignword;@bank;@dirty;@nosplit;@nozp;@requirezp;@shared;@split;@zp;atascii:;c64os:;cp437:;default:;iso16:;iso5:;iso:;kata:;petscii:;sc:" />
|
||||
<keywords3 keywords="^^bool;^^byte;^^float;^^long;^^str;^^ubyte;^^uword;^^word;bool;byte;const;float;long;str;struct;ubyte;uword;void;word" />
|
||||
<keywords4 keywords="abs;bmx;call;callfar;callfar2;cbm;clamp;cmp;conv;cx16;defer;diskio;divmod;floats;len;lsb;lsw;math;max;memory;min;mkword;msb;msw;peek;peekbool;peekf;peekw;poke;pokebool;pokef;pokew;psg;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sqrt;strings;sys;txt;verafx" />
|
||||
<keywords4 keywords="abs;bmx;call;callfar;callfar2;cbm;clamp;cmp;conv;cx16;defer;diskio;divmod;floats;len;lsb;lsw;math;max;memory;min;mkword;msb;msw;offsetof;peek;peekbool;peekf;peekw;poke;pokebool;pokef;pokew;psg;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sqrt;strings;sys;txt;verafx" />
|
||||
</highlighting>
|
||||
<extensionMap>
|
||||
<mapping ext="p8" />
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<Keywords name="Keywords1">void const
str
byte ubyte bool
long word uword
float
zp shared split nosplit requirezp nozp struct</Keywords>
|
||||
<Keywords name="Keywords2">%address
%asm
%ir
%asmbinary
%asminclude
%align
%breakpoint
%encoding
%import
%jmptable
%memtop
%launcher
%option
%output
%zeropage
%zpreserved
%zpallowed</Keywords>
|
||||
<Keywords name="Keywords3">inline sub asmsub extsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat unroll
break continue return goto</Keywords>
|
||||
<Keywords name="Keywords4">alias abs call callfar callfar2 clamp cmp defer divmod len lsb lsw lsl lsr memory mkword min max msb msw peek peekw peekf peekbool poke pokew pokef pokebool rsave rsavex rrestore rrestorex rnd rndw rol rol2 ror ror2 setlsb setmsb sgn sizeof sqrtw</Keywords>
|
||||
<Keywords name="Keywords4">alias abs call callfar callfar2 clamp cmp defer divmod len lsb lsw lsl lsr memory mkword min max msb msw peek peekw peekf peekbool poke pokew pokef pokebool rsave rsavex rrestore rrestorex rnd rndw rol rol2 ror ror2 setlsb setmsb sgn sizeof offsetof sqrtw</Keywords>
|
||||
<Keywords name="Keywords5">true false
not and or xor
as to downto |></Keywords>
|
||||
<Keywords name="Keywords6"></Keywords>
|
||||
<Keywords name="Keywords7"></Keywords>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<Keywords name="Keywords1">void const
str
byte ubyte bool
long word uword
float
zp shared split nosplit requirezp nozp struct</Keywords>
|
||||
<Keywords name="Keywords2">%address
%asm
%ir
%asmbinary
%asminclude
%align
%breakpoint
%encoding
%import
%jmptable
%memtop
%launcher
%option
%output
%zeropage
%zpreserved
%zpallowed</Keywords>
|
||||
<Keywords name="Keywords3">inline sub asmsub extsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat unroll
break continue return goto</Keywords>
|
||||
<Keywords name="Keywords4">alias abs call callfar callfar2 clamp cmp defer divmod len lsb lsw lsl lsr memory mkword min max msb msw peek peekw peekf peekbool poke pokew pokef pokebool rsave rsavex rrestore rrestorex rnd rndw rol rol2 ror ror2 setlsb setmsb sgn sizeof sqrtw</Keywords>
|
||||
<Keywords name="Keywords4">alias abs call callfar callfar2 clamp cmp defer divmod len lsb lsw lsl lsr memory mkword min max msb msw peek peekw peekf peekbool poke pokew pokef pokebool rsave rsavex rrestore rrestorex rnd rndw rol rol2 ror ror2 setlsb setmsb sgn sizeof offsetof sqrtw</Keywords>
|
||||
<Keywords name="Keywords5">true false
not and or xor
as to downto |></Keywords>
|
||||
<Keywords name="Keywords6"></Keywords>
|
||||
<Keywords name="Keywords7"></Keywords>
|
||||
|
||||
@@ -156,7 +156,7 @@ contexts:
|
||||
- match: (\b(const)\b)
|
||||
scope: storage.modifier.prog8
|
||||
support:
|
||||
- match: (\b(abs|atan|ceil|cos|cos8u|cos8|cos16u|cos16|deg|floor|ln|log2|rad|round|sin|sgn|sin8u|sin8|sin16u|sin16|sqrt16|sqrt|tan|any|all|len|max|min|reverse|sum|sort|memcopy|memset|memsetw|leftstr|rightstr|strlen|strcmp|strncmp|substr|exit|lsb|msb|lsw|msw|mkword|rnd|rndw|rndf|rol|rol2|ror|ror2|rsave|rrestore|read_flags|sizeof|set_carry|clear_carry|set_irqd|clear_irqd|swap)\b)
|
||||
- match: (\b(abs|atan|ceil|cos|cos8u|cos8|cos16u|cos16|deg|floor|ln|log2|rad|round|sin|sgn|sin8u|sin8|sin16u|sin16|sqrt16|sqrt|tan|any|all|len|max|min|reverse|sum|sort|memcopy|memset|memsetw|leftstr|rightstr|strlen|strcmp|strncmp|substr|exit|lsb|msb|lsw|msw|mkword|rnd|rndw|rndf|rol|rol2|ror|ror2|rsave|rrestore|read_flags|sizeof|offsetof|set_carry|clear_carry|set_irqd|clear_irqd|swap)\b)
|
||||
scope: support.function.prog8
|
||||
variable:
|
||||
- match: (\b\w+\b)
|
||||
|
||||
@@ -14,7 +14,7 @@ syn keyword prog8BuiltInFunc len
|
||||
|
||||
" Miscellaneous functions
|
||||
syn keyword prog8BuiltInFunc cmp divmod lsb msb lsw msw mkword min max peek peekw peekf peekbool poke pokew pokef pokebool rsave rsavex rrestore rrestorex
|
||||
syn keyword prog8BuiltInFunc rol rol2 ror ror2 sizeof setlsb setmsb
|
||||
syn keyword prog8BuiltInFunc rol rol2 ror ror2 sizeof offsetof setlsb setmsb
|
||||
syn keyword prog8BuiltInFunc memory call callfar callfar2 clamp defer alias
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user