From: Warren on 16 Mar 2010 13:11 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 16 Mar 2010 14:31 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 16 Mar 2010 14:57 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 16 Mar 2010 16:01 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 16 Mar 2010 16:09 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
|
Next
|
Last
Pages: 1 2 3 4 5 6 Prev: Using gnat & ncurses Next: segfault with large-ish array with GNAT |