Pretty much any compiler tutorial will cover it.
-- Scanner stuff.
type Root_Token is abstract tagged record
Line, Column : Natural;
end record;
-- For Delimiters.
type Simple_Token is new Root_Token with null record;
-- Anything with words, i.e. keywords or identifiers.
type Tokens is new Root_Token with record
Lexeme : Unbounded_String;
end record;
type Keyword_Tokens is new Tokens with null record;
-- Parser stuff.
type Root_Node is tagged record...
type Expression is new Root_Node with...
type Simple_Expression is new Expression with... or
type Root_Expression is tagged record with...
type Simple_Expression is new Root_Expression with...
For example. Or you could have different roots for different types of hierarchy, this is what Clang does.