From: Warren on
I am trying to solve a lexer Ada design problem, using a
variant record (Token_Unit) definition:

type Token_Type is (
LEX_000,
LEX_BINARY,
LEX_SECTION,
'!',
'"',
'#',
'$',
...etc..
'^',
'_',
'`',
LEX_SFUN3,
LEX_SFUN2,
LEX_SFUN1,
LEX_SFUNN,
LEX_FUN3,
LEX_FUN2,
LEX_FUN1,
LEX_FUNN,
...etc...
LEX_EOF
);

type Token_Unit(Token : Token_Type := LEX_EOF) is
record
case Token is
when LEX_SFUN3 | LEX_SFUN2 | LEX_SFUN1 | LEX_SFUNN
| LEX_FUN3 | LEX_FUN2 | LEX_FUN1 | LEX_FUNN =>
Func : Func_Type;
when LEX_IDENT | LEX_SIDENT | LEX_LNUMBER | LEX_NUMBER
| LEX_HEX | LEX_STRLIT | LEX_INLREM | LEX_FLOAT
| LEX_REM =>
ID : String_ID;
when others =>
null;
end case;
end record;


procedure Get_Token(Object : in out Lexer; Token : out Token_Unit) is

procedure Emit_Token(T : Token_Type) is
T : Token_Type := Token_Type'Val(Character'Pos(Ch));
begin
Token := ( Token => T );
end;

...

end;

In the above, I need to create a Token_Unit from
a single character (there is no "id" in this case). The values
of operator characters are carefully coordinated in the Token_Type
using a representation clause (just FYI).

But the issue is this:

*.adb:339:33: value for discriminant "token" must be static
*.adb:339:33: "T" is not static constant or named number (RM 4.9(5))

I could put a huge case statement in, but I'd prefer not to.

Is there a better way to handle the dynamic creation of
a variant record? I have other scenarios involving a
Func_Type and String_ID as well, which suffer from the same
"must be static" problem.

I should also mention that I am trying to keep the Token_Unit
to 32-bits, for efficiency. If it were possible to
divide up the Token_Type (16-bits) into 13-bits and use
a different descriminant of 3 bits, that would
work also if the total size remained 32. The String_ID
portion (or Func_Type) are both 16-bit.

Warren
From: Georg Bauhaus on
Warren schrieb:

> procedure Get_Token(Object : in out Lexer; Token : out Token_Unit) is
>
> procedure Emit_Token(T : Token_Type) is
> T : Token_Type := Token_Type'Val(Character'Pos(Ch));
> begin
> Token := ( Token => T );
> end;
>
> ...
>
> end;


> In the above, I need to create a Token_Unit from
> a single character (there is no "id" in this case). The values
> of operator characters are carefully coordinated in the Token_Type
> using a representation clause (just FYI).

This text appears to be GNATable:

procedure Emit_Token(T : Token_Type) is
Some_T : Token_Type := Token_Type'Val(Character'Pos(Ch));
subtype Result_Type is Token_Unit (Token => Some_T);
Result : Result_Type;
begin
-- Token := ( Token => T );



Token := Result;
end;

> But the issue is this:
>
> *.adb:339:33: value for discriminant "token" must be static

Is this true?
From: Adam Beneschan on
On Mar 16, 10:11 am, Warren <ve3...(a)gmail.com> wrote:
> I am trying to solve a lexer Ada design problem, using a
> variant record (Token_Unit) definition:
>
>     type Token_Type is (
>         LEX_000,
>         LEX_BINARY,
>         LEX_SECTION,
>         '!',
>         '"',
>         '#',
>         '$',
>         ...etc..
>         '^',
>         '_',
>         '`',
>         LEX_SFUN3,
>         LEX_SFUN2,
>         LEX_SFUN1,
>         LEX_SFUNN,
>         LEX_FUN3,
>         LEX_FUN2,
>         LEX_FUN1,
>         LEX_FUNN,
>         ...etc...
>         LEX_EOF
>     );
>
>     type Token_Unit(Token : Token_Type := LEX_EOF) is
>         record
>             case Token is
>                 when LEX_SFUN3 | LEX_SFUN2 | LEX_SFUN1 | LEX_SFUNN
>                    | LEX_FUN3  | LEX_FUN2  | LEX_FUN1  | LEX_FUNN =>
>                     Func :      Func_Type;
>                 when LEX_IDENT | LEX_SIDENT | LEX_LNUMBER | LEX_NUMBER
>                    | LEX_HEX   | LEX_STRLIT | LEX_INLREM  | LEX_FLOAT
>                    | LEX_REM =>
>                     ID :        String_ID;                                                                                                                                                            
>                 when others =>
>                     null;
>             end case;
>         end record;
>
>     procedure Get_Token(Object : in out Lexer; Token : out Token_Unit) is
>
>         procedure Emit_Token(T : Token_Type) is
>             T : Token_Type := Token_Type'Val(Character'Pos(Ch));
>         begin
>             Token := ( Token => T );
>         end;
>
>         ...        
>
>     end;
>
> In the above, I need to create a Token_Unit from            
> a single character (there is no "id" in this case).

And how is the compiler supposed to know that there is no "id"?

When you use a record aggregate, you need to specify values for every
component of the record. If the record has a variant part, then the
compiler won't know what components have to be specified unless it
knows what the discriminant is going to be; and it doesn't know what
the discriminants are going to be unless the value of the discriminant
is static. That's why you get the error you're getting:

> But the issue is this:    
>
> *.adb:339:33: value for discriminant "token" must be static
> *.adb:339:33: "T" is not static constant or named number (RM 4.9(5))

You can't get what you want with an aggregate, but Georg's solution
will give you some of what you want, at least. However, this will
leave all the components (besides the discriminants) uninitialized,
and you'll need to assign values into them.

By the way, now that Ada 2005 has the <> construct for aggregates,
it's just occurred to me that maybe 4.3.1(17) can be relaxed a bit, to
make it legal to specify a record aggregate with a nonstatic
discriminant for a variant record, *if* the only component
associations for aggregates are components that are not in variant
parts *and* there is an others=><> in the aggregate (or something
along those lines). I don't know whether it's worthwhile, though.
(It wouldn't help too much in this exact example, since there are no
non-variant components, but if it were expanded to include, say, a
source file name, line number, and column number for each Token_Unit,
then there would be some benefit.) I'll consider making a proposal
for this, depending on how loud a groan Randy, Bob, etc., make when
they read this idea... :)

-- Adam

From: Warren on
Adam Beneschan expounded in
news:c3fa9a0f-99c7-4fff-9310-7e4d769065db(a)s25g2000prd.googlegroups.com:

> On Mar 16, 10:11�am, Warren <ve3...(a)gmail.com> wrote:
>> I am trying to solve a lexer Ada design problem, using a
>> variant record (Token_Unit) definition:
>>
>> � � type Token_Type is (
>> � � � � LEX_000,
>> � � � � LEX_BINARY,
>> � � � � ...etc...
>> � � � � LEX_EOF
>> � � );
>>
>> � � type Token_Unit(Token : Token_Type := LEX_EOF) is
>> � � � � record
....
>> � � � � end record;
>>
>> � � procedure Get_Token(Object : in out Lexer; Token : out Token_Unit
> ) is
>>
>> � � � � procedure Emit_Token(T : Token_Type) is
>> � � � � � � T : Token_Type := Token_Type'Val(Character'Pos(
> Ch));
>> � � � � begin
>> � � � � � � Token := ( Token => T );
>> � � � � end;
>>
>> � � � � ... � � � �
>>
>> � � end;
>>
>> In the above, I need to create a Token_Unit from � � � � � �
>> a single character (there is no "id" in this case).
>
> And how is the compiler supposed to know that there is no "id"?
>
> When you use a record aggregate, you need to specify values for every
> component of the record. If the record has a variant part, then the
> compiler won't know what components have to be specified unless it
> knows what the discriminant is going to be;

Of course. But it is not conceptually inconceivable to
check this at runtime and realize that the value I handed
out will work with what was provided. If not, then
raise an exception.

The point here is that there is a wide number of discriminant values
that map to the same layout.

Now I don't expect anyone to change the rules in Ada to accomodate
my request. I am simply laying out a "problem" and looking for a
suitable "solution".

>> But the issue is this: � �
>>
>> *.adb:339:33: value for discriminant "token" must be static
>> *.adb:339:33: "T" is not static constant or named number (RM 4.9(5))
>
> You can't get what you want with an aggregate, but Georg's solution
> will give you some of what you want, at least. However, this will
> leave all the components (besides the discriminants) uninitialized,
> and you'll need to assign values into them.

I don't currently see "Georg's solution" post, but perhaps it will
arrive soon.

> By the way, now that Ada 2005 has the <> construct for aggregates,
> it's just occurred to me that maybe 4.3.1(17) can be relaxed a bit, to
> make it legal to specify a record aggregate with a nonstatic
> discriminant for a variant record, *if* the only component
> associations for aggregates are components that are not in variant
> parts *and* there is an others=><> in the aggregate (or something
> along those lines). I don't know whether it's worthwhile, though.

As I originally prototyped it, I just shoe-horned it into one
value with nasty C-like conversions. But I am looking for a cleaner
"ada way" to do this.

> ... I'll consider making a proposal
> for this, depending on how loud a groan Randy, Bob, etc., make when
> they read this idea... :)
>
> -- Adam

I wasn't looking for compiler-implementation/language amendments.
Just looking for good advice on how others would takle this problem.
Perhaps the full case statement is the right way, but I gotta say
that it puts a damper on readability.

Warren
From: Jeffrey R. Carter on
Warren wrote:
>>> procedure Emit_Token(T : Token_Type) is
>>> T : Token_Type := Token_Type'Val(Character'Pos(
>> Ch));
>>> begin
>>> Token := ( Token => T );
>>> end;

I missed a bunch of this thread. But you can do what you want:

declare
Result : Token_Unit (Token => T);
begin
Token := Result;
end;

Quite possibly this is also "Georg's solution".

--
Jeff Carter
"Clear? Why, a 4-yr-old child could understand this
report. Run out and find me a 4-yr-old child. I can't
make head or tail out of it."
Duck Soup
94