> On Jan 22, 2025, at 12:20, Martin Uecker <uec...@tugraz.at> wrote:
> 
> Am Mittwoch, dem 22.01.2025 um 18:11 +0100 schrieb Martin Uecker:
>> Am Mittwoch, dem 22.01.2025 um 16:37 +0000 schrieb Qing Zhao:
>>> 
>>>> On Jan 22, 2025, at 11:22, Martin Uecker <uec...@tugraz.at> wrote:
>>>> 
>>>> 
>>>> Hello Michael,
>>>> 
>>>> Am Mittwoch, dem 22.01.2025 um 16:54 +0100 schrieb Michael Matz:
>>>>> On Wed, 22 Jan 2025, Martin Uecker wrote:
>>>>> 
>>>>>>>> So you do not need to look further.  But maybe I am missing something 
>>>>>>>> else.
>>>>>>> 
>>>>>>> Like ...
>>>>>>> 
>>>>>>>>> Note further that you may have '{ .y[1][3].z }', which is still not a 
>>>>>>>>> designation, but an expression under your proposal, whereas
>>>>>>>>> '{ .y[1][3].z = 1 }' would remain a designation.  This shows that you 
>>>>>>>>> now need arbitrary look-ahead to disambiguate the two.  A Very Bad 
>>>>>>>>> Idea.
>>>>>>> 
>>>>>>> ... this?
>>>>>> 
>>>>>> In .y[1][3].z  after .y you can decide whether y is a member of the
>>>>>> struct being initialized.  If it is, it is a designator and if not
>>>>>> it must be an expression.
>>>>> 
>>>>> If y is not a member it must be an expression, true.  But if it's a 
>>>>> member 
>>>>> you don't know, it may be a designation or an expression.
>>>> 
>>>> In an initializer I know all the members.
>>> 
>>> I am not familiar with the parser, so, I am a little confused about the 
>>> following:
>>> 
>>> Suppose we have:
>>> 
>>> struct foo {
>>>  int z;
>>>  float f;
>>> }
>>> 
>>> struct bar {
>>>  char *array __attribute__ ((counted_by (.y[1][3].z + 4)));
>>>  struct foo y[5][10];
>>> }
>>> 
>>> So, in the above, when parsing the above expression inside counted_by, can 
>>> the
>>> current parser be easily to be extended to parse it?
>> 
>> No, I don't think this can be done easily. The issue is that you do
>> not know the declaration for y because it hasn't been parsed yet. 
>> 
>> If you forward reference some struct member, you have several
>> possibilities:
>> 
>> - use it only in limited contexts where you do not need to know
>>  the type (e.g. this works for goto labels) or for a basic
>>  counted_by attribute that only takes an identifier as we have it now.
>> 
>> - simply assume it has a certain type (size_t as is proposed in the 
>>  WG14 paper Joseph mentioned) and fail later if it does not.
>> 
>> 
>> Both options would rule the construct above (but there could be
>> workarounds). 
> 
> One of the workarounds could be to instead call a function (which could
> be inlined later) and that function takes a pointer to the member. 
> Then it does not need to now anything about any member, e.g.:
> 
> 
> struct foo {
>  int z;
>  float f;
> }
> 
> size_t bar_count(struct bar *);
> 
> struct bar {
>  char *array __attribute__ ((counted_by (bar_count(__self__))));
>  struct foo y[5][10];
> }
> 
> size_t bar_count(struct bar *p)
> {
>  return p->y[1][3].z +4;
> }
> 
> 
In this workaround, we also need to introduce a new key word “__self__”,  
Is this the same as the “__self__” Joseph mentioned in a previous email 
(I copied Joseph’s word in below for easy reference):


"But if you want a less-limited feature that allows for expressions, you 
need some syntax for referring to a structure member that's not ambiguous.  
For example, some new notation such as __self__.len1 to refer to a member 
of the closest enclosing structure definition when in counted_by (while 
being invalid except in counted_by inside a structure definition).  
(That's just one example of how you might define syntax that avoids 
ambiguity.)”

So, for the following two approaches to represent expression as argument of 
“counted_by” attribute:

A.  Allowing  function call as the argument, and the new key word “__self__” is 
passed to this function to
reference members of the closest enclosing structure.

> struct bar {
>  char *array __attribute__ ((counted_by (bar_count(__self__))));
>  struct foo y[5][10];
> }


B. Allowing expression with __self__ as the argument:

> struct bar {
>  char *array __attribute__ ((counted_by (__self__.y[1][3].z + 4)));
>  struct foo y[5][10];
> }


My question:

Which is better, A or B? 


Thanks a lot for your help.

Qing

> 
>> Other alternatives are:
>> 
>> - you have same kind of forward declaration (as we have for
>>  parameters  as GNU extension). In the context of C, this is the
>>  cleanest solution but either requires forward declaring the
>>  full struct (which can be done in C23) or new syntax for only
>>  forward declaring the member.
> 
> A possible C23 workaround could be:
> 
> struct foo {
>  int z;
>  float f;
> }
> 
> struct bar {
>  char *array __attribute__ ((counted_by (*))); 
>  // star indicates missing size exppression
>  struct foo y[5][10];
> }
> 
> struct bar { // redeclare with known size
>  char *array __attribute__ ((counted_by (.y[1][3].z + 4)));
>  struct foo y[5][10];
> }
> 
> 
> Martin
> 
> 
>> 
>> - or you use some delayed parsing where you store away the tokens
>>  and parse it later when all structure members are done. I think
>>  this is a highly problematic approach for a variety of reasons.
>> 
>> 
>> Martin
>> 
>> 
>>> 
>>> thanks.
>>> 
>>> Qing
>>>> 
>>>> Martin 
>>>> 
>>>> 
>>> 
>> 
> 

Reply via email to