DDLEngine

Files CCore/inc/ddl/DDLEngine.h CCore/src/ddl/DDLEngine.cpp

Files CCore/inc/ddl/DDLMap.h CCore/src/ddl/DDLMap.cpp

Files CCore/inc/ddl/DDLTypedMap.h CCore/src/ddl/DDLTypeMap.cpp

Files CCore/inc/ddl/DDLPlatformTypes.h CCore/src/ddl/DDLPlatformTypes.cpp

Files CCore/inc/ddl/DDLMapTypes.h CCore/src/ddl/DDLMapTypes.cpp

Files CCore/inc/ddl/DDLMapBase.h CCore/src/ddl/DDLMapBase.cpp

Subfolders CCore/inc/ddl CCore/src/ddl

DDL implementation

The directory ddl contains a DDL implementation. It is contained in the namespace DDL. To process a DDL source there are two main classes: TextEngine and FileEngine. The most of content of this directory is a DDL2 parser implementation and not needed to be used directly.

Engines return the result of processing of the following type:


struct EngineResult
 {
  EvalResult *eval;
  BodyNode *body;
  
  EngineResult() : eval(0),body(0) {}
  
  EngineResult(NothingType) : EngineResult() {}
  
  EngineResult(EvalResult *eval_,BodyNode *body_) : eval(eval_),body(body_) {}
  
  EvalResult * operator + () const { return eval; }
  
  bool operator ! () const { return !eval; }
 };

It's a simple lightweight data structure with two fields. eval is a pointer to the EvalResult object, this object contains constant value table. body is a pointer to the root body node, this node represents the DDL source. Walking from this node you can examine the whole source content. If the processing has failed, the result is null.


class TextEngine : NoCopy
 {
   ....

  public: 
   
   TextEngine(PrintBase &msg,StrLen text,StrLen pretext=Empty);
   
   ~TextEngine();
   
   EngineResult process();
 };

The first constructor argument is a stream, where error messages will be printed to. The second is a text to be processed. The third is a "pretext". It is included before the text. To do the job use the method process(). This engine does not support the file inclusion. This engine is one-shoot, it should be used to process one input once. Result objects life-time is ended with the engine life-time end.


template <class FileName,class FileText>
class FileEngine : NoCopy
 {
   ....

  public:
   
   static const ulen DefaultMaxFiles = 1000 ;
   static const ulen DefaultMaxIncludes = 100 ;
   static const ulen DefaultMaxFileLen = MaxULen ;
  
   explicit FileEngine(PrintBase &msg,ulen mem_cap=MaxULen,
                                      ulen max_files=DefaultMaxFiles,
                                      ulen max_inc=DefaultMaxIncludes,
                                      ulen max_file_len=DefaultMaxFileLen);
   
   ~FileEngine();

   EngineResult process(StrLen file_name,StrLen pretext);

   EngineResult process(StrLen file_name);
 };

FileEngine can process a complex input from a real or a virtual file system. Two template parameters controls the file name processing and the file name to the file content mapping. The first constructor argument is a error report stream. Others are different engine limits. The method process() does the job. The first argument is a file name with a DDL text. Additional files may be opened during include operations. The second argument is a "pretext". It is included before the file text. The method process() can be called multiple times for different files. Loaded files are cached. Result objects life-time is ended with the next call of process(), or with the engine life-time end.

The first template parameter FileName is responsible for the file name manipulation. There is a default implementation of this class. It is recommended to use this implementation. Any other implementation must be interface compatible with this particular one.

The second template parameter must do the same thing as the FileToMem class, i.e. load the file content into the memory.


class FileText : NoCopy
 {
  public:

   FileText(StrLen file_name,ulen max_len);

   ~FileText();

   const uint8 * getPtr() const;

   ulen getLen() const;
 };

On HCore targets you can use the class FileToMem as the FileText template parameter.

EvalResult


struct EvalResult : NoCopy
 {
  DynArray<ConstResult> const_table;
  DynArray<LenResult> len_table;
  
  EvalResult() {}
  
  void erase();
  
  ulen_type getLen(const LenNode &node) const;
 };

EvalResult contains two tables. Each constant, defined in the DDL2 source, has an associated ConstNode object. This object contains the field index. The entry in the const_table with this index contains the calculated value of the constant. Each array type with an explicit array length has an associated LenNode object. This object contains the field index. The entry in the len_table with this index contains the calculated value of the length.


struct ConstResult
 {
  TypeNode *type;
  ConstNode *node;
  Value value;
  
  void set(ConstNode *node,const Value &value);

  struct PrintOptType
   {
    EvalResult &result;
    
    PrintOptType(EvalResult &result_) : result(result_) {}
   };
  
  template <class P>
  void print(P &out,PrintOptType opt) const;
 };

ConstResult contains three fields. type is a TypeNode pointer, node is a ConstNode pointer, value is the calculated constant value. This class is printable. To print you must provide the option, bounded to the original EvalResult object.


struct LenResult
 {
  LenNode *node;
  ulen_type value;
  
  void set(LenNode *node,ulen_type value);
 
  template <class P>
  void print(P &out) const;
 };

LenResult contains two fields. node is a LenNode pointer, value is the calculated length value.


struct LenNode
 {
  ....

  ulen index;
 };

struct ConstNode
 {
  ....

  ScopeNode *parent;
  ulen depth;

  NameIdNode name;

  ulen index;
 };

struct ScopeNode
 {
  ....

  ScopeNode *parent;
  
  NameIdNode name;
 };

struct NameIdNode
 {
  ....

  PosName name;
  
  StrLen getStr() const { return name.str; }
 };

All LenNodes are zero-based indexed. The correspondent index is assigned to the index field.

All ConstNodes are zero-based indexed. The correspondent index is assigned to the index field. ConstNode contains also the filed name with its name and the field parent with the pointer to the ScopeNode which it belongs to. depth is the scope depth.

ScopeNode has the field parent with the pointer to the ScopeNode which it belongs to. It also has the field name with the scope name.

NameIdNode has the method getStr(). This method returns the name of the item.


union Value
 {
  imp_sint8  val_sint8;
  imp_uint8  val_uint8;
  imp_sint16 val_sint16;
  imp_uint16 val_uint16;
  imp_sint32 val_sint32;
  imp_uint32 val_uint32;
  imp_sint64 val_sint64;
  imp_uint64 val_uint64;
  
  imp_sint   val_sint;
  imp_uint   val_uint;
  imp_ulen   val_ulen;
  
  SLen       val_slen;
  Text       val_text;
  IP         val_ip;
  
  Block      val_block;
  Ptr        val_ptr;

  // methods
  
  template <class Type>
  Type get() const;
  
  template <class Type>
  void set(Type val);
 };

Value is a union of different types. The actual member depends on the value type. You may use get<Type>() and set<Type>() methods to get and set values.

To represent integral types imp_XXX are used.


struct imp_XXX
 {
  XXX_integral_type value;

  ....
 };
 

Integral types are: sint8, uint8, ... and sint_type, uint_type, ulen_type. Last three types are platform-dependent.

Text represents text type.


struct Text
 {
  StrLen str;
  
  // constructors
  
  Text() {}
  
  Text(StrLen str_) : str(str_) {}
  
  // print object
  
  template <class P>
  void print(P &out) const;
 };

IP represents ip type.


struct IP
 {
  uint8 address[4];
  
  // constructors
  
  IP() : address{} {}
  
  IP(uint8 a1,uint8 a2,uint8 a3,uint8 a4) : address{a1,a2,a3,a4} {}
  
  // methods
  
  uint32 toInt() const;
  
  // print object
  
  template <class P>
  void print(P &out) const;
 };

Non-scalar values, like structures and arrays, are represented using the type Block.


struct Block
 {
  PtrLen<Value> data;

  ....
 };

Each member of the range data is the value of the correspondent element of aggregate.

Pointer values are represented using the type Ptr.


struct Ptr
 {
  PtrNode *ptr_node;
  bool null;

  ....
 };

struct PtrNode
 {
  PtrNode *parent;
  ulen_type index;
  TypeNode *type;

  ....
 };

The field ptr_node points to the PtrNode object. This object contains three fields. type describes the type of the pointee constant or sub-constant. If this constant is a full constant, then parent is null and index is the ConstNode index. Otherwise parent represents the aggregate, the sub-constant is an element of, and index is the aggregate element index.

If the pointer is a null pointer of some type, then the field null is true and ptr_node->type describes the type.


struct TypeNode
 {
  struct Base
   {
    enum Type
     {
      Type_none = 0,
      
      Type_sint,
      Type_uint,
      Type_ulen,
      
      Type_sint8,
      Type_uint8,
      Type_sint16,
      Type_uint16,
      Type_sint32,
      Type_uint32,
      Type_sint64,
      Type_uint64,
      
      Type_text,
      Type_ip,
      
      TypeIntMin=Type_sint,
      TypeIntMax=Type_uint64
     };
    
    Type type;
    
    explicit Base(Type type_) : type(type_) {}
    
    bool isIntegral() const { return type && type<Type_text ; }
    
    bool isText() const { return type==Type_text; }
    
    bool isIP() const { return type==Type_ip; }
   };
  
  struct Ref
   {
    AnyPtr<AliasNode,StructNode> ptr;

    ....
   };
  
  struct Ptr
   {
    TypeNode *type_node;

    ....
   };
  
  struct PolyPtr
   {
    TypeList *type_list;
    
    ....
   };
  
  struct Array
   {
    TypeNode *type_node;

    ....
   };
  
  struct ArrayLen
   {
    TypeNode *type_node;
    
    LenNode len_node;

    ....
   };
  
  struct Struct
   {
    StructNode *struct_node;

    ....
   };
  
  AnyPtr<Base,Ref,Ptr,PolyPtr,Array,ArrayLen,Struct> ptr;

  .... 
 };

TypeNode is used to represent a type. Different type classes are encoded using AnyPtr field ptr. For example, to encode the type uint8, ptr is initialized by the pointer to the object of type TypeNode::Base and the field type of this object has the value TypeNode::Base::Type_uint8.


struct AliasNode
 {
  ....

  TypeNode *type_node;

  TypeNode *result_type; // don't point to TypeNode Ref with another alias
 };

AliasNode repesents a type declaration. The field result_type points to some "resulting" TypeNode, this node represents the aliased type and is not a Ref node with another AliasNode.


struct StructNode
 {
  ....

  ScopeNode scope_node;

  ForwardList<FieldNode> field_list;

  ulen dep_index;
 };

StructNode represents a structure declaration. The field scope_node represents the correspondent scope. The field field_list is the list of structure fields. dep_index is a zero-based index of the structure. These indexes respect structure dependencies: if the structure A has a filed of the structure type B (or B[] or B[Len]), then the dep_index of the B is less than the dep_index of the A.


struct FieldNode
 {
  ....

  FieldNode *next;

  NameIdNode name;
  TypeNode *type_node;

  ulen index;
  ulen field_index;
 };

FieldNode describes a structure field. index is a zero-based field index among all fields of all structures. field_index is a zero-based field index of this particular structure. name describes the field name and type_node — the field type.


/* struct TypeListNode */

struct TypeListNode
 {
  ....

  TypeListNode *prev;

  TypeNode *type_node;
 };

/* type TypeList */

using TypeList = CountList<TypeListNode> ;

These entities are used to represent a type list.

Map

The best way to deal with a DDL processing result is to map it into a block of memory. The class Map is to do it.


class Map : NoCopy
 {
   ....

  public:
  
   explicit Map(EngineResult result);
  
   ~Map();
  
   ulen getLen() const;
  
   void operator () (void *mem);
  
   bool findStruct(StrLen name,const TypeDesc &desc); 
  
   void * findConst(StrLen name,const TypeDesc &desc);
 };

You create an object of the type Map, providing the EngineResult as the argument. Then you have to allocate an aligned block of memory of the length getLen(). Once it's done, use the overloaded operator () to map data into this memory block. You may destroy the Map object and the Engine object at this point and keep the memory block as long as required. To find a particular constant you can use the method findConst() with the constant name and type, encoded using the class TypeDesc. If there is no such constant or types mismatch then null is returned. Otherwise the pointer to the mapped value is returned.

There is a simple helper class MapBase to help with the memory allocation for a Map object (the actual implementation is slightly different):


class MapBase : NoCopy
 {
   void *mem;
  
  public:

   template <class Map>
   explicit MapBase(Map &map)
    {
     mem=MemAlloc(map.getLen());
     
     map(mem);
    }
   
   ~MapBase()
    {
     MemFree(mem);
    }
 };


/* consts */

enum TypeTag
 {
  // basic
 
  TypeTag_sint,         // sint_type
  TypeTag_uint,         // uint_type
  TypeTag_ulen,         // ulen_type
  
  TypeTag_sint8,        // sint8
  TypeTag_uint8,        // uint8
  TypeTag_sint16,       // sint16
  TypeTag_uint16,       // uint16
  TypeTag_sint32,       // sint32
  TypeTag_uint32,       // uint32
  TypeTag_sint64,       // sint64
  TypeTag_uint64,       // uint64
  
  TypeTag_text,         // StrLen
  TypeTag_ip,           // uint32
  
  // other
  
  TypeTag_ptr,          // DataPtr
  TypeTag_polyptr,      // TypedDataPtr
  TypeTag_array,        // ArrayPtr -> elem[len]
  TypeTag_array_len,    // elem[len]
  TypeTag_array_getlen, // elem[len]
  
  TypeTag_struct,       // {field1,field2,...}
  
  // none
  
  TypeTag_none,
  
  // int
  
  TypeTag_int = TypeTag_sint 
 };

/* struct TypeDesc */

struct TypeDesc
 {
  const TypeTag tag;
  
  explicit TypeDesc(const TypeTag tag_) : tag(tag_) {}
 };

TypeDesc, in fact, is a base class for the family of derived classes, designed to represent different type classes. The field tag has a describing type value, and derived classes has additional fields with extra information if required.


struct TypeDesc_basic : TypeDesc
 {
  explicit TypeDesc_basic(TypeTag tag);
 };

This class is to represent basic types. You provide in constructor argument the correspondent type tag.


struct TypeDesc_ptr : TypeDesc
 {
  const TypeDesc &type;
  
  explicit TypeDesc_ptr(const TypeDesc &type);
 };

This class represents single type pointers. You provide in constructor argument the type descriptor.


template <ulen TypeCount>
struct TypeDesc_polyptr : TypeDesc_polyptr_base
 {
  const Type buf[TypeCount];
 
  template <class ... TT>
  explicit TypeDesc_polyptr(const TT & ... tt);
 };

This class represents polymorphic pointer types. You provide in constructor arguments a list of type descriptors. TypeCount is a number of types.


struct TypeDesc_array : TypeDesc
 {
  const TypeDesc &type;
  
  explicit TypeDesc_array(const TypeDesc &type);
 };

This class represents array types without length. You provide in constructor argument the element type descriptor.


struct TypeDesc_array_len : TypeDesc
 {
  const TypeDesc &type;
  const ulen_type len;
  
  TypeDesc_array_len(const TypeDesc &type,ulen_type len);
 };

This class represents array types with a given length. You provide in constructor arguments the element type descriptor and the array length.


struct TypeDesc_array_getlen : TypeDesc
 {
  const TypeDesc &type;
  mutable ulen_type len; // filled by findConst() method
  
  explicit TypeDesc_array_getlen(const TypeDesc &type);
 };

This class represents array types with a given length. You provide in constructor argument the element type descriptor. But the actual array length is filled by the method findConst(). This descriptor must participate in findConst() directly or indirectly to be used later.


template <ulen FieldCount>
struct TypeDesc_struct : TypeDesc_struct_base
 {
  const Field buf[FieldCount];
  
  template <class ... TT>
  explicit TypeDesc_struct(const TT & ... tt);
 };

This class represents structure types. You provide in constructor arguments a list of field type descriptors. FieldCount is a number of fields. This structure has some internal fields, these fields are filled by the method findConst(). This descriptor must participate in findConst() directly or indirectly to be used later.

DataPtr

DataPtr is a helper class. It is a "universal pointer" class. You may initialize an object of this type by the value, returned by the method findConst().


struct DataPtr
 {
  void *ptr;
  
  // constructors
  
  DataPtr() : ptr(0) {}
  
  DataPtr(void *ptr_) : ptr(ptr_) {}
  
  // methods
  
  void * operator + () const { return ptr; }
  
  bool operator ! () const { return !ptr; }
  
  struct Proxy
   {
    void *ptr;
    
    Proxy(void *ptr_) : ptr(ptr_) {}
    
    template <class T>
    operator T() const;
   };
  
  Proxy operator * () const { return ptr; }
  
  DataPtr elem(const TypeDesc_struct_base &desc,ulen ind) const;
  
  DataPtr select(const TypeDesc_struct_base &desc,ulen ind) const;
  
  struct ProxyRange
   {
    void *ptr;
    ulen len;
    
    ProxyRange(void *ptr_,ulen len_) : ptr(ptr_),len(len_) {}
    
    template <class T>
    operator PtrLen<T>() const;
   };
  
  ProxyRange range(ulen len) const { return ProxyRange(ptr,len); }
 };

Then you may use this object to get the constant value. Use the operator * and assign the result to the variable of the proper type. You may find the proper type in the TypeTag definition above.

You cannot use the operator *, however, if the constant type is a structure or an array with length. For structure types you may use the method select() to create a DataPtr to the desired field. The first argument is a structure type descriptor, the second is the zero-based field index. The descriptor contains inside some internal values, filled by the method findConst() to locate a particular field.

If the constant type is an array without length, you can cast to the type ArrayPtr, but you can also use the type PtrLen<T>, where the type T corresponds to the element type. Again, you cannot do it, if the element type is a structure or an array with length.


struct ArrayPtr
 {
  void *ptr;
  ulen len;

  ArrayPtr() : ptr(0),len(0) {}
  
  ArrayPtr(void *ptr_,ulen len_) : ptr(ptr_),len(len_) {}
 };

This structure holds a pointer to the first element of the array and the number of the array elements. You may initialize an object of type DataPtr from this pointer.

If a DataPtr object corresponds to an array with length, you may use the method range() to build a PtrLen<T> object to access array elements. Just cast the return value to the proper range type. The element type cannot be a structure or array with length in this case.

To deal with an array of structures, use the method elem(). It returns a pointer to the element with the given index. You must provide the structure descriptor.

TypedDataPtr

This class is used to deal with polymorphic pointers. It inherits the type DataPtr and has the additional field type. The value of this field is a 1-based index of the pointer type from the type list. It is zero if the pointer is a typeless null.


struct TypedDataPtr : DataPtr
 {
  ulen type; // 1-based type index
  
  // constructors
  
  TypedDataPtr() : type(0) {}
  
  TypedDataPtr(void *ptr,ulen type_) : DataPtr(ptr),type(type_) {}
 };

TypedMap

The most convenient way to map DDL data is the class TypedMap. But with this class you are bounded by the given set of DDL structure types. These type set is represented by the template parameter TypeSet. You should use the utility DDLTypeSet to generate the definition of this class from the DDL source.


template <class TypeSet>
class TypedMap : NoCopy
 {
   ....

  public:
   
   explicit TypedMap(EngineResult result);
   
   ~TypedMap();
   
   ulen getLen() const { return total; }
   
   void operator () (void *mem);
   
   template <class T>
   T * findConst(StrLen name);
   
   template <class T>
   T takeConst(StrLen name);
 };

TypedMap class usage is the same as for Map class. The difference is you have two methods to get a particular constant value.

findConst() searches for the constant with the given name and with the given type and returns a pointer to it. Null is returned if there is no such constant or it has a different type. The type is specified as the template parameter.

takeConst() does the same, but it returns the value and throw an exception on error.

In this case you always get a value of some C++ type, compatible with the DDL type. These types are available from the ddl/DDLMapTypes.h include file.

For integral types the compatible type is an integral C++ type. I.e. uint8 is mapped as uint8 etc. sint is mapped as sint_type, uint as uint_type and ulen as ulen_type.

ip is mapped as uint32.

text is mapped as MapText.


struct MapText
 {
  // data
  
  char *ptr;
  ulen len;
  
  // methods
  
  StrLen getStr() const { return StrLen(ptr,len); }
  
  // cast
  
  operator StrLen() const { return getStr(); }
 };

Pointers are mapped as MapPtr.


template <class T>
struct MapPtr // layout-compatible with MapPtr<char>
 {
  // data
  
  void *ptr;
  
  // object ptr
  
  void * operator + () const { return ptr; }
  
  bool operator ! () const { return !ptr; }
  
  T * getPtr() const { return static_cast<T *>(ptr); }
  
  T & operator * () const { return *getPtr(); }
  
  T * operator -> () const { return getPtr(); }
  
  // cast
  
  operator T * () const { return getPtr(); }
 };

Polymorphic pointers are mapped as MapPolyPtr.


template <class ... TT>
struct MapPolyPtr // layout-compatible with MapPolyPtr<>
 {
  // data
  
  void *ptr;
  ulen type;
  
  // methods
  
  using AnyPtrType = AnyPtr<TT...> ;
  
  AnyPtrType getPtr() const;

  // cast
  
  operator AnyPtrType() const { return getPtr(); }
 };

Arrays are mapped as MapRange.


template <class T>
struct MapRange // layout-compatible with MapRange<char>
 {
  // data
  
  void *ptr;
  ulen len;
  
  // methods
  
  PtrLen<T> getRange() const;
  
  // cast
  
  operator PtrLen<T> () const { return getRange(); }
 };

Finally, structure types are mapped using C++ structure definitions from the TypeSet class.

Example

Here is LangTypes.ddl file.

/* LangTypes.ddl */
//----------------------------------------------------------------------------------------
//
//  Project: CondLangLR1 1.00
//
//  License: Boost Software License - Version 1.0 - August 17th, 2003 
//
//            see http://www.boost.org/LICENSE_1_0.txt or the local copy
//
//  Copyright (c) 2015 Sergey Strukov. All rights reserved.
//
//----------------------------------------------------------------------------------------

type AtomIndex = uint32 ;
type SyntIndex = uint32 ;
type KindIndex = uint32 ;
type ElementIndex = uint32 ;
type RuleIndex = uint32 ;
type StateIndex = uint32 ;
type FinalIndex = uint32 ;

struct Lang
 {
  Atom[] atoms;
  Synt[] synts;
  Synt * [] lang;
  Element[] elements;
  Rule[] rules;
  TopRule[] top_rules;
  State[] states;
  Final[] finals;
 };

struct Atom
 {
  AtomIndex index;
  text name;
  
  Element *element;
 };

struct Synt
 {
  SyntIndex index;
  text name;
  
  Kind[] kinds;
  Rule * [] rules;
 };

struct Kind
 {
  KindIndex kindex; // index among all kinds
  KindIndex index; // index in synt array
  text name;

  Synt *synt;
  
  Element *element;
  
  TopRule * [] rules;
 };

struct Element
 {
  ElementIndex index;
  
  {Atom,Kind} * elem;
 };

struct Rule
 {
  RuleIndex index;
  text name;

  Kind *result;

  type Arg = {Atom,Synt} * ;

  Arg[] args;
 };
 
struct TopRule
 {
  RuleIndex index;
  text name;
  
  Rule *bottom;

  Kind *result;

  type Arg = {Atom,Kind} * ;

  Arg[] args;
 }; 

struct State
 {
  StateIndex index;
  Final *final;

  struct Transition
   {
    Element *element;
    State *state;
   };

  Transition[] transitions;
 };

struct Final
 {
  FinalIndex index;

  struct Action
   {
    Atom *atom; // null for (End)
    Rule *rule; // null for <- ( STOP if atom is (END) )
   };

  Action[] actions;
 };

DDLTypeSet generates two C++ header files: LanTypeDef.gen.h and LangTypeSet.gen.h.

The first defines C++ structure types and aliases.

/* struct TypeDefCore */

struct TypeDefCore
 {
  // types

  struct S1; // #Final#Action
  struct S2; // #Final
  struct S3; // #State#Transition
  struct S4; // #State
  struct S5; // #TopRule
  struct S6; // #Rule
  struct S7; // #Element
  struct S8; // #Kind
  struct S9; // #Synt
  struct S10; // #Atom
  struct S11; // #Lang

  using A1 = DDL2::MapPolyPtr< S10 , S8 > ; // #TopRule#Arg
  using A2 = DDL2::MapPolyPtr< S10 , S9 > ; // #Rule#Arg
  using A3 = uint32 ; // #FinalIndex
  using A4 = uint32 ; // #StateIndex
  using A5 = uint32 ; // #RuleIndex
  using A6 = uint32 ; // #ElementIndex
  using A7 = uint32 ; // #KindIndex
  using A8 = uint32 ; // #SyntIndex
  using A9 = uint32 ; // #AtomIndex


  using XXX8226D906_9898_43AA_B1BE_D60B0A6E31C8 = TypeDefCore ;

  // structures

  struct S1
   {
    DDL2::MapPtr< S10 > atom;
    DDL2::MapPtr< S6 > rule;

    struct Ext;
   };

  struct S2
   {
    A3 index;
    DDL2::MapRange< S1 > actions;

    using Action = XXX8226D906_9898_43AA_B1BE_D60B0A6E31C8::S1 ;

    struct Ext;
   };

  struct S3
   {
    DDL2::MapPtr< S7 > element;
    DDL2::MapPtr< S4 > state;

    struct Ext;
   };

  struct S4
   {
    A4 index;
    DDL2::MapPtr< S2 > final;
    DDL2::MapRange< S3 > transitions;

    using Transition = XXX8226D906_9898_43AA_B1BE_D60B0A6E31C8::S3 ;

    struct Ext;
   };

  struct S5
   {
    A5 index;
    DDL2::MapText name;
    DDL2::MapPtr< S6 > bottom;
    DDL2::MapPtr< S8 > result;
    DDL2::MapRange< A1 > args;

    using Arg = XXX8226D906_9898_43AA_B1BE_D60B0A6E31C8::A1 ;

    struct Ext;
   };

  struct S6
   {
    A5 index;
    DDL2::MapText name;
    DDL2::MapPtr< S8 > result;
    DDL2::MapRange< A2 > args;

    using Arg = XXX8226D906_9898_43AA_B1BE_D60B0A6E31C8::A2 ;

    struct Ext;
   };

  struct S7
   {
    A6 index;
    DDL2::MapPolyPtr< S10 , S8 > elem;

    struct Ext;
   };

  struct S8
   {
    A7 kindex;
    A7 index;
    DDL2::MapText name;
    DDL2::MapPtr< S9 > synt;
    DDL2::MapPtr< S7 > element;
    DDL2::MapRange< DDL2::MapPtr< S5 > > rules;

    struct Ext;
   };

  struct S9
   {
    A8 index;
    DDL2::MapText name;
    DDL2::MapRange< S8 > kinds;
    DDL2::MapRange< DDL2::MapPtr< S6 > > rules;

    struct Ext;
   };

  struct S10
   {
    A9 index;
    DDL2::MapText name;
    DDL2::MapPtr< S7 > element;

    struct Ext;
   };

  struct S11
   {
    DDL2::MapRange< S10 > atoms;
    DDL2::MapRange< S9 > synts;
    DDL2::MapRange< DDL2::MapPtr< S9 > > lang;
    DDL2::MapRange< S7 > elements;
    DDL2::MapRange< S6 > rules;
    DDL2::MapRange< S5 > top_rules;
    DDL2::MapRange< S4 > states;
    DDL2::MapRange< S2 > finals;

    struct Ext;
   };

  // extra

 };

using XXX212CD757_09B3_4D89_BE20_65C1E4E5A819 = TypeDefCore ;

namespace TypeDef {

    using StateIndex = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::A4 ;
    using KindIndex = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::A7 ;
    using RuleIndex = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::A5 ;
    using SyntIndex = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::A8 ;
    using AtomIndex = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::A9 ;
    using ElementIndex = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::A6 ;
    using FinalIndex = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::A3 ;
    using Atom = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S10 ;
    using Kind = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S8 ;
    using Lang = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S11 ;
    using Rule = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S6 ;
    using Synt = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S9 ;
    using Element = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S7 ;
    using TopRule = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S5 ;
    using Final = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S2 ;
    using State = XXX212CD757_09B3_4D89_BE20_65C1E4E5A819::S4 ;

} // namespace TypeDef

You should use TypeDef namespace to refer a particular structure or a type alias. Use the same name, as the name of the DDL entity.

To use this file include it in your C++ source code inside some namespace to isolate it from the other stuff.

Each structure definition contains the declaration of the inner structure Ext. You may provide definitions of these structures to add additional functions to work with these structures.

The second file contains a definition of the TypeSet class.

/* struct TypeSet */

struct TypeSet : TypeDefCore
 {
  ....
 };

....

Use this class as the template argument for the TypedMap class template.