Subversion Repositories tendra.SVN

Rev

Rev 5 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (c) 2002-2006 The TenDRA Project <http://www.tendra.org/>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific, prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */
/*
                 Crown Copyright (c) 1997, 1998
    
    This TenDRA(r) Computer Program is subject to Copyright
    owned by the United Kingdom Secretary of State for Defence
    acting through the Defence Evaluation and Research Agency
    (DERA).  It is made available to Recipients with a
    royalty-free licence for its use, reproduction, transfer
    to other parties and amendment for any purpose not excluding
    product development provided that any such use et cetera
    shall be deemed to be acceptance of the following conditions:-
    
        (1) Its Recipients shall ensure that this Notice is
        reproduced upon any copies or amended versions of it;
    
        (2) Any amended version of it shall be clearly marked to
        show both the nature of and the organisation responsible
        for the relevant amendment or amendments;
    
        (3) Its onward transfer from a recipient to another
        party shall be deemed to be that party's acceptance of
        these conditions;
    
        (4) DERA gives no warranty or assurance as to its
        quality or suitability for any purpose and DERA accepts
        no liability whatsoever in relation to any use to which
        it may be put.
*/


/*
 * TYPE SYSTEM SPECIFICATION
 *
 * The main type system for the program is specified using the calculus tool.
 * This generates two representations of the type algebra, c_class. The files
 * in obj_tok describe the output type system abstractly in terms of the TenDRA
 * '#pragma token' constructs. These may be used to apply extremely rigorous
 * type checking to the program. The files in obj_c give the implementation of
 * the type system in C terms. The implementation specific parts of the
 * program, including the memory management, is handled in obj_c/c_class.c.
 */

ALGEBRA c_class (1.1) :


/*
 * PRIMITIVE TYPES
 *
 * These are the primitive types from which the algebra is built. int, unsigned
 * and string are self-explanitory. BITSTREAM_P represents a series of bits,
 * and is used to hold any compiled code. PPTOKEN_P represents a list of
 * preprocessing tokens, and is used in macro definitions etc.
 */

int =                   "int" ;
unsigned =              "unsigned" ;
string =                "character *" ;
ulong_type (ulong) =    "unsigned long" ;
BITSTREAM_P (bits) =    "struct bits_tag *" ;
PPTOKEN_P (pptok) =     "struct pptok_tag *" ;


/*
 * TYPE REPRESENTING A CONST-VOLATILE SPECIFIER
 *
 * The const and volatile type qualifiers are represented by an enumeration
 * type (which is actually a bit pattern). An additional value is used to
 * indicate lvalues. Type linkage specifiers are also included.
 */

enum !CV_SPEC (cv) = {
    none =              0,
    const =             1 << 0,
    volatile =          1 << 1,
    lvalue =            1 << 2,

    c =                 1 << 3,
    cpp =               1 << 4,

    qual =              const | volatile,
    mask =              qual | lvalue,
    language =          c | cpp
} ;


/*
 * TYPE REPRESENTING A BUILT-IN TYPE
 *
 * The built-in types have two representations - as a BASE_TYPE (see below) or
 * as a BUILTIN_TYPE. The latter is used primarily as an index into various
 * tables.
 */

enum !BUILTIN_TYPE (ntype) = {
    none =              0,
    char =              1,
    schar =             2,
    uchar =             3,
    sshort =            4,
    ushort =            5,
    sint =              6,
    uint =              7,
    slong =             8,
    ulong =             9,
    sllong =            10,
    ullong =            11,
    float =             12,
    double =            13,
    ldouble =           14,
    void =              15,
    bottom =            16,
    bool =              17,
    ptrdiff_t =         18,
    size_t =            19,
    wchar_t =           20,
    ellipsis =          21
} ;


/*
 * TYPE REPRESENTING A BASIC TYPE
 *
 * The basic types are represented by an enumeration type (which is actually a
 * bit pattern except for the named type component). The composite bitpatterns
 * for the maximally valid combinations are also given. The elaborated type
 * keys are also represented by this type.
 */

enum !BASE_TYPE (btype) = {
    none =              0,
    class =             1,
    struct_ =           2,
    union_ =            3,
    enum_ =             4,
    alias =             5,
    any =               6,
    named =             7,

    signed =            1 << 3,
    unsigned =          1 << 4,
    char =              1 << 5,
    short =             1 << 6,
    int =               1 << 7,
    long =              1 << 8,
    long2 =             1 << 9,
    float =             1 << 10,
    double =            1 << 11,
    void =              1 << 12,
    bottom =            1 << 13,
    bool =              1 << 14,
    ptrdiff_t =         1 << 15,
    size_t =            1 << 16,
    wchar_t =           1 << 17,

    schar =             signed | char,
    uchar =             unsigned | char,
    sshort =            signed | short | int,
    ushort =            unsigned | short | int,
    sint =              signed | int,
    uint =              unsigned | int,
    slong =             signed | long | int,
    ulong =             unsigned | long | int,
    llong =             long | long2,
    sllong =            signed | llong | int,
    ullong =            unsigned | llong | int,
    ldouble =           long | double,

    ellipsis =          1 << 18,
    star =              1 << 19,
    template =          1 << 20,
    typename =          1 << 21,
    args =              1 << 22,
    keyword =           float | double | void | bool | wchar_t,
    other =             keyword | bottom | ptrdiff_t | size_t,
    arith =             int | float,
    scalar =            int | float | star
} ;


/*
 * TYPE REPRESENTING AN INTEGRAL TYPE
 *
 * An integral type can be one of the built-in types, an integral promotion
 * type or an arithmetic conversion type. The promotion type for each integral
 * type is stored as part of its definition.
 */

union INT_TYPE (itype) = {
    TYPE prom ;
    LIST TYPE cases ;
    BUILTIN_TYPE unprom = "ntype_none" ;
    ulong_type itok = "LINK_NONE" ;
    ulong_type ntok = "LINK_NONE" ;
    ulong_type diag = "LINK_NONE" ;
} + {
    basic -> {
        /* Built-in types */
        BASE_TYPE rep ;
        BUILTIN_TYPE no ;
    },
    bitfield -> {
        /* Bitfield types */
        TYPE sub ;
        BASE_TYPE rep ;
        NAT size ;
        DECL_SPEC info ;
    },
    promote -> {
        /* Promotion types */
        INT_TYPE arg ;
    },
    arith -> {
        /* Arithmetic conversion types */
        INT_TYPE arg1, arg2 ;
    },
    literal -> {
        /* Target dependent literal type */
        NAT nat ;
        int spec ;
        int form, suff ;
        IDENTIFIER tok ;
    },
    token -> {
        /* Tokenised integral type */
        IDENTIFIER tok ;
        LIST TOKEN args ;
    }
} ;


/*
 * TYPE REPRESENTING A FLOATING POINT TYPE
 *
 * A floating point type can be one of the built-in types or an arithmetic
 * conversion type. Note that all floating point types are their own arithmetic
 * promotions, but they do have distinct argument promotions.
 */

union FLOAT_TYPE (ftype) = {
    TYPE arg_prom ;
    ulong_type ftok = "LINK_NONE" ;
    ulong_type ntok = "LINK_NONE" ;
    ulong_type diag = "LINK_NONE" ;
    LIST FLOAT small = "NULL_list ( FLOAT )" ;
} + {
    basic -> {
        /* Built-in types */
        BASE_TYPE rep ;
        BUILTIN_TYPE no ;
    },
    arg_promote -> {
        /* Argument promotion types */
        FLOAT_TYPE arg ;
    },
    arith -> {
        /* Arithmetic conversion types */
        FLOAT_TYPE arg1, arg2 ;
    },
    token -> {
        /* Tokenised floating type */
        IDENTIFIER tok ;
        LIST TOKEN args ;
    }
} ;


/*
 * TYPE REPRESENTING CLASS INFORMATION
 *
 * This type is a bitpattern giving information about a class, for example, if
 * it is complete, whether it has base classes, non-static data members, and so
 * on.
 */

enum !CLASS_INFO (cinfo) = {
    none =              0,
    complete =          1 << 0,         /* completed definition */
    defined =           1 << 1,         /* started definition */
    struct_ =           1 << 2,         /* structure class */
    union_ =            1 << 3,         /* union class */
    template =          1 << 4,         /* template class */
    token =             1 << 5,         /* tokenised structure */
    pod =               1 << 6,         /* plain ol' data structure */
    nested =            1 << 7,         /* is nested class */
    rescan =            1 << 8,         /* expands by rescanning */
    recursive =         1 << 9,         /* recursively defined */
    incomplete =        1 << 10,        /* warn if not completed */
    base =              1 << 11,        /* has base class */
    multiple_base =     1 << 12,        /* multiple inheritance */
    virtual_base =      1 << 13,        /* has virtual base class */
    templ_base =        1 << 14,        /* has template base class */
    ambiguous =         1 << 15,        /* has ambiguous base class */
    empty =             1 << 16,        /* empty class */
    private =           1 << 17,        /* non-public data member */
    const =             1 << 18,        /* const data member */
    static =            1 << 19,        /* static data member */
    function =          1 << 20,        /* function member */
    params =            1 << 21,        /* layout dependent on parameters */
    polymorphic =       1 << 22,        /* virtual function */
    poly_base =         1 << 23,        /* polymorphic base class */
    abstract =          1 << 24,        /* pure function */
    trivial_constr =    1 << 25,        /* trivial constructor */
    trivial_destr =     1 << 26,        /* trivial destructor */
    trivial_copy =      1 << 27,        /* trivial copy constructor */
    trivial_assign =    1 << 28,        /* trivial assign operator */
    const_copy =        1 << 29,        /* const copy constructor */
    const_assign =      1 << 30,        /* const assign operator */
    usr_constr =        1 << 31,        /* user defined constructor */

    key =               struct_ | union_,
    non_aggregate =     private | usr_constr | base | polymorphic | token,
    force_copy =        static | function | params,
    trivial_make =      trivial_constr | trivial_copy | trivial_assign,
    trivial =           trivial_make | trivial_destr,
    implicit =          trivial | const_copy | const_assign,
    default =           implicit | empty | pod
} ;


/*
 * TYPE REPRESENTING CLASS USAGE INFORMATION
 *
 * This type is a bitpattern used to represent information on how a class is
 * used.
 */

enum !CLASS_USAGE (cusage) = {
    none =              0,
    address =           1 << 0,         /* address of incomplete */
    destr =             1 << 1,         /* destroyed incomplete */
    delete =            1 << 2,         /* deleted incomplete */
    delete_array =      1 << 3          /* deleted incomplete array */
} ;


/*
 * TYPE REPRESENTING A CLASS TYPE
 *
 * A class type has an associated type name, type key (class, struct or union),
 * and class information. The hash table entries for the constructors and
 * destructors, plus a list of the conversion functions on the class are
 * maintained within the class definition. The class members themselves are
 * just a namespace. The base classes are represented by a graph.
 */

union CLASS_TYPE (ctype) = {
    IDENTIFIER name ;
    CLASS_INFO info ;
    CLASS_USAGE usage ;
    NAMESPACE member ;
    GRAPH base ;
    unsigned no_bases ;
    TYPE prev ;
    TYPE form = "NULL_type" ;
    IDENTIFIER constr = "NULL_id" ;
    IDENTIFIER destr = "NULL_id" ;
    VIRTUAL virt = "NULL_virt" ;
    LIST GRAPH vbase = "NULL_list ( GRAPH )" ;
    LIST IDENTIFIER conv = "NULL_list ( IDENTIFIER )" ;
    LIST CLASS_TYPE chums = "NULL_list ( CLASS_TYPE )" ;
    LIST IDENTIFIER pals = "NULL_list ( IDENTIFIER )" ;
    LIST IDENTIFIER nest = "NULL_list ( IDENTIFIER )" ;
    ulong_type tok1 = "LINK_NONE" ;
    ulong_type tok2 = "LINK_NONE" ;
} + {
    basic -> {
        /* empty */
    }
} ;


/*
 * TYPE REPRESENTING A GRAPH OF DERIVED CLASSES
 *
 * This type is used to represent the directed acyclic graphs of base classes
 * associated with a class. Each node of this graph consists of a class and a
 * list of its base classes. The access of each base class, and other
 * information, is recorded. Identical virtual bases are linked using the equal
 * field. The next field is used to link all instances of a class within a
 * graph, whether virtual or not.
 */

union GRAPH (graph) = {
    CLASS_TYPE head ;
    DECL_SPEC access ;
    LIST GRAPH tails = "NULL_list ( GRAPH )" ;
    GRAPH top = "NULL_graph" ;
    GRAPH equal = "NULL_graph" ;
    GRAPH up = "NULL_graph" ;
    unsigned no = "0" ;
    OFFSET off = "NULL_off" ;
    LIST IDENTIFIER member = "NULL_list ( IDENTIFIER )" ;
    ulong_type tok1 = "LINK_NONE" ;
    ulong_type tok2 = "LINK_NONE" ;
} + {
    basic -> {
        /* empty */
    }
} ;


/*
 * TYPE REPRESENTING A VIRTUAL FUNCTION
 *
 * This type is used to represent a virtual function table or an entry of such
 * a table. Each table entry has an associated function plus information on
 * where this was inherited from and any difference in the return type of an
 * overriding function.
 */

union VIRTUAL (virt) = {
    IDENTIFIER func ;
    ulong_type no ;
    GRAPH base ;
    VIRTUAL next = "NULL_virt" ;
} + {
    table -> {
        /* Virtual function table */
        OFFSET off ;
        LIST VIRTUAL entries = "NULL_list ( VIRTUAL )" ;
        ulong_type tok = "LINK_NONE" ;
        ulong_type tbl = "LINK_NONE" ;
        ulong_type rtti = "LINK_NONE" ;
        int rtti_used = "0" ;
    },
    simple -> {
        /* New virtual function */
    },
    override -> {
        /* Overriding virtual function */
        GRAPH ret ;
        IDENTIFIER orig ;
        GRAPH src ;
    },
    inherit -> {
        /* Inherited primary function */
    },
    complex -> {
        /* Inherited overriding virtual function */
        GRAPH ret ;
        IDENTIFIER orig ;
        GRAPH src ;
    },
    link -> {
        /* Symbolic link */
        PTR VIRTUAL to ;
    }
} ;


/*
 * TYPE REPRESENTING AN ENUMERATION TYPE
 *
 * An enumeration type has an associated type name, a class information field
 * (which is only used to indicate whether the type is complete), and an
 * underlying integral type. The enumerators themselves are given as a simple
 * list (note that they do not form a namespace).
 */

union ENUM_TYPE (etype) = {
    IDENTIFIER name ;
    CLASS_INFO info ;
    TYPE rep ;
    TYPE form = "NULL_type" ;
    LIST IDENTIFIER values = "NULL_list ( IDENTIFIER )" ;
    EXP value = "NULL_exp" ;
    ulong_type plus = "0" ;
} + {
    basic -> {
        /* empty */
    }
} ;


/*
 * TYPE REPRESENTING A TYPE
 *
 * The types are represented by a union type, with one field per type
 * class. Any type may be qualified using const, volatile and lvalue.
 */

union TYPE (type) = {
    /* Type qualifiers */
    CV_SPEC qual ;
    IDENTIFIER name = "NULL_id" ;
} + {
    pre -> {
        /* Pre-types (used during parsing only) */
        BASE_TYPE rep ;
        QUALIFIER nqual ;
    },
    integer -> {
        /* Integer types */
        INT_TYPE rep ;
        INT_TYPE sem ;
    },
    floating -> {
        /* Floating point types */
        FLOAT_TYPE rep ;
        FLOAT_TYPE sem ;
    },
    top, bottom -> {
        /* The void types */
    },
    ptr, ref -> {
        /* Pointer and reference types */
        TYPE sub ;
    },
    ptr_mem -> {
        /* Pointer to member types */
        CLASS_TYPE of ;
        TYPE sub ;
    },
    func -> {
        /* Function types */
        TYPE ret ;
        LIST TYPE ptypes ;
        int ellipsis ;
        CV_SPEC mqual ;
        LIST TYPE mtypes ;
        NAMESPACE pars ;
        LIST IDENTIFIER pids ;
        LIST TYPE except ;
    },
    array -> {
        /* Array types */
        TYPE sub ;
        NAT size ;
    },
    bitfield -> {
        /* Bitfield types */
        INT_TYPE defn ;
    },
    compound -> {
        /* Class types */
        CLASS_TYPE defn ;
    },
    enumerate -> {
        /* Enumeration types */
        ENUM_TYPE defn ;
    },
    token -> {
        /* Tokenised type */
        IDENTIFIER tok ;
        LIST TOKEN args ;
        INSTANCE app = "NULL_inst" ;
    },
    templ -> {
        /* Template type */
        TOKEN sort ;
        TYPE defn ;
        int fix ;
    },
    instance -> {
        /* Template member type */
        IDENTIFIER id ;
        DECL_SPEC access ;
    },
    dummy -> {
        /* Dummy special token type */
        int tok ;
    },
    error -> {
        /* Error propagation type */
    }
} ;


/*
 * TYPE REPRESENTING A DECLARATION SPECIFIER
 *
 * The basic declaration specifiers (i.e. the storage class specifiers, the
 * function specifiers, friend and typedef) are represented by an enumeration
 * type (which is actually a bit pattern). Other declaration and linkage
 * information is also included, including access specifiers. The fact that
 * public < protected < private is used extensively. The values none, static
 * and extern are also used to specify the linkage of an object.
 */

enum DECL_SPEC (dspec) = {
    none =              0,
    used =              1 << 0,
    called =            1 << 1,
    defn =              1 << 2,
    inherit =           1 << 3,
    alias =             1 << 4,
    done =              1 << 5,

    static =            1 << 6,
    extern =            1 << 7,
    auto =              1 << 8,
    register =          1 << 9,
    mutable =           1 << 10,
    inline =            1 << 11,
    virtual =           1 << 12,
    explicit =          1 << 13,
    friend =            1 << 14,
    typedef =           1 << 15,

    public =            1 << 16,
    protected =         2 << 16,
    private =           3 << 16,

    public2 =           public << 2,
    protected2 =        protected << 2,
    private2 =          private << 2,

    c =                 1 << 20,
    cpp =               1 << 21,

    ignore =            1 << 22,
    implicit =          1 << 23,
    instance =          1 << 24,
    main =              1 << 25,
    pure =              1 << 26,
    reserve =           1 << 27,
    temp =              1 << 28,
    template =          1 << 29,
    token =             1 << 30,
    trivial =           1 << 31,

    linkage =           static | extern,
    storage =           static | extern | auto | register | mutable,
    function =          inline | virtual | explicit,
    keyword =           storage | function | friend | typedef,
    duplicate =         keyword,
    access =            public | protected | private,
    access2 =           public2 | protected2 | private2,
    language =          c | cpp,
    other =             ignore | implicit | instance | main | pure |
                        reserve | temp | template | token | trivial
} ;


/*
 * TYPE REPRESENTING A HASH TABLE ENTRY
 *
 * Identifier names are represented by a hash table entry. There are several
 * different types of names (simp1e strings, destructor names and so on). Each
 * hash table entry contains, in effect, a built-in namespace member indicating
 * the underlying meaning of this name. It also contains the hash value for
 * this entry.
 */

union HASHID (hashid) = {
    IDENTIFIER id = "NULL_id" ;
    IDENTIFIER cache = "NULL_id" ;
    HASHID next ;
    ulong_type hash ;
} + {
    name, ename -> {
        /* Simple and extended identifiers */
        string text ;
    },
    constr, destr, conv -> {
        /* Constructors, destructors and conversion functions */
        TYPE type ;
        IDENTIFIER tid ;
    },
    op -> {
        /* Overloaded operator name */
        int lex ;
    },
    anon -> {
        /* Unnamed identifier */
        ulong_type uniq ;
    }
} ;


/*
 * TYPE REPRESENTING AN IDENTIFIER QUALIFIER
 *
 * These values are used to identify how an identifier is qualified, either
 * unqualified, a nested qualifier (for example A::B::n), a full nested
 * qualifier (for example ::A::B::n), or a top nested qualifier (for example
 * ::n). A value to mark resolved overloaded functions is also included.
 */

enum !QUALIFIER (qual) = {
    none =              0,
    nested =            1,
    full =              2,
    top =               3,
    mark =              4,
    explicit =          nested | full | top
} ;


/*
 * TYPE REPRESENTING AN IDENTIFIER
 *
 * Identifiers have an associated hash table entry, indicating the identifier
 * name, plus a location indicating where the identifier was first declared.
 * The various things an identifier can represent are given by the different
 * fields of the union.
 */

union IDENTIFIER (id) = {
    HASHID name ;
    DECL_SPEC storage ;
    NAMESPACE parent ;
    LOCATION loc ;
    IDENTIFIER alias = "%0" ;
    ulong_type no = "LINK_NONE" ;
    ulong_type dump = "LINK_NONE" ;
} + {
    dummy -> {
        /* Undefined identifier */
    },
    keyword, iso_keyword, reserved -> {
        /* Keywords */
    },
    builtin -> {
        /* Built-in operators */
        TYPE ret ;
        LIST TYPE ptypes ;
    },
    obj_macro -> {
        /* Object-like macros */
        PPTOKEN_P defn ;
    },
    func_macro -> {
        /* Function-like macros */
        PPTOKEN_P defn ;
        LIST HASHID params ;
        unsigned no_params ;
    },
    predicate -> {
        /* Predicates */
        LIST PPTOKEN_P values = "NULL_list ( PPTOKEN_P )" ;
    },
    class_name, enum_name,
    class_alias, enum_alias, type_alias -> {
        /* Type names */
        TYPE defn ;
        BASE_TYPE rep = "btype_none" ;
    },
    nspace_name, nspace_alias -> {
        /* Namespace names */
        NAMESPACE defn ;
    },
    variable, parameter, stat_member -> {
        /* Variables (including static members) */
        TYPE type ;
        EXP init = "NULL_exp" ;
        EXP term = "NULL_exp" ;
    },
    weak_param -> {
        /* Non-prototype function parameters */
    },
    function, mem_func, stat_mem_func -> {
        /* Functions (including member functions) */
        TYPE type ;
        IDENTIFIER over ;
        TYPE form = "NULL_type" ;
        LIST CLASS_TYPE chums = "NULL_list ( CLASS_TYPE )" ;
        EXP defn = "NULL_exp" ;
    },
    member -> {
        /* Simple data member */
        TYPE type ;
        OFFSET off = "NULL_off" ;
        GRAPH base = "NULL_graph" ;
    },
    enumerator -> {
        /* Enumerators */
        TYPE etype ;
        EXP value ;
    },
    label -> {
        /* Labels */
        int op ;
        EXP stmt = "NULL_exp" ;
        EXP gotos = "NULL_exp" ;
        LIST VARIABLE vars = "NULL_list ( VARIABLE )" ;
    },
    token -> {
        /* Tokens */
        TOKEN sort ;
        IDENTIFIER alt ;
    },
    ambig -> {
        /* Ambiguous identifier */
        LIST IDENTIFIER ids ;
        int over ;
    },
    undef -> {
        /* Undefined identifier */
        TYPE form = "NULL_type" ;
    },
    pending -> {
        /* Pending identifier (used in spec input) */
        unsigned itag ;
        TYPE type ;
    }
} ;


/*
 * TYPE REPRESENTING A NAMESPACE MEMBER
 *
 * There are two kinds of namespace member, small and large, corresponding to
 * the two kinds of namespace. The important section consists of two
 * identifiers, giving the current meanings of a name in the namespace.
 * Everything else is just links to other members.
 */

union MEMBER (member) = {
    IDENTIFIER id = "NULL_id" ;
    IDENTIFIER alt = "NULL_id" ;
    MEMBER next ;
} + {
    small -> {
        /* empty */
    },
    large -> {
        MEMBER tnext ;
    }
} ;


/*
 * TYPE REPRESENTING A NAMESPACE
 *
 * There are two kinds of namespace, small and large. The small namespaces are
 * the block and parameter spaces, the large ones are the class and namespace
 * spaces. Every namespace has an associated namespace name (which may be the
 * null identifier). A small namespace consists of a simple linked list of
 * small members (in reverse order of declaration). A large namespace consists
 * of a hash table of large members, plus a list of all such members in order
 * of declaration. The distinct orders reflect the distinct purposes the two
 * kinds of namespace are put to.
 */

union NAMESPACE (nspace) = {
    IDENTIFIER name ;
    MEMBER last = "NULL_member" ;
    MEMBER prev = "NULL_member" ;
    NAMESPACE parent ;
    LIST NAMESPACE use = "NULL_list ( NAMESPACE )" ;
    LIST NAMESPACE join = "NULL_list ( NAMESPACE )" ;
    STACK IDENTIFIER set = "NULL_stack ( IDENTIFIER )" ;
    ulong_type dump = "LINK_NONE" ;
} + {
    block, param, dummy, label, templ -> {
        /* Member list */
    },
    named, unnamed, global, ctype -> {
        /* Member hash table */
        MEMBER first = "NULL_member" ;
        LIST IDENTIFIER extra = "NULL_list ( IDENTIFIER )" ;
        ulong_type size ;
        PTR MEMBER table ;
    }
} ;


/*
 * TYPE REPRESENTING AN INTEGER LITERAL
 *
 * An integer literal (or constant integral expression) is represented by a
 * sign and a list of numbers in the range [0,0xffff] representing the value
 * base 0x10000. The case where there is only one digit is dealt with
 * separately. It is also possible to form an integer literal from an
 * expression.
 */

union NAT (nat) = {
    /* empty */
} + {
    small -> {
        /* Single digit */
        unsigned value ;
    },
    large -> {
        /* Multiple digits */
        LIST unsigned values ;
    },
    calc -> {
        /* Calculated value */
        EXP value ;
        ulong_type tok = "LINK_NONE" ;
    },
    neg -> {
        /* Negation */
        NAT arg ;
    },
    token -> {
        /* Tokenised expression */
        IDENTIFIER tok ;
        LIST TOKEN args ;
    }
} ;


/*
 * TYPE REPRESENTING A FLOATING POINT LITERAL
 *
 * A floating point literal is represented by a sign, two strings giving the
 * digits before and after the decimal point, plus an exponent.
 */

union FLOAT (flt) = {
    ulong_type tok = "LINK_NONE" ;
} + {
    simple -> {
        /* Simple literal */
        string int_part ;
        string frac_part ;
        NAT exponent ;
    }
} ;


/*
 * TYPE REPRESENTING A STRING LITERAL
 *
 * A string literal consists of a sequence of characters of a given length.
 * Characters, wide characters, strings and wide strings are represented by
 * distinct fields of the union.
 */

union STRING (str) = {
    STRING next = "NULL_str" ;
} + {
    simple -> {
        /* Simple literals */
        ulong_type len ;
        string text ;
        unsigned kind ;
        ulong_type tok = "LINK_NONE" ;
    }
} ;


/*
 * TYPE REPRESENTING A TEST
 *
 * Test and comparison operators are represented by an enumeration type which
 * happen to be in the same order as the TDF encoding. Complementary tests
 * (for example '<' and '>=') always add up to the same value, negate.
 */

enum !NTEST (ntest) = {
    eq =                0,
    greater =           1,
    greater_eq =        2,
    less =              3,
    less_eq =           4,
    not_eq =            5,
    not_greater =       6,
    not_greater_eq =    7,
    not_less =          8,
    not_less_eq =       9,
    not_not_eq =        10,
    none =              11,
    negate =            eq + not_eq,
    not =               not_eq,
    not_not =           not_not_eq
} ;


/*
 * TYPE REPRESENTING A ROUNDING MODE
 *
 * Floating point rounding modes are represented by an enumeration type which
 * happen to be in the same order as the TDF encoding.
 */

enum !RMODE (rmode) = {
    as_state =          0,
    to_nearest =        1,
    to_larger =         2,
    to_smaller =        3,
    to_zero =           4
} ;


/*
 * TYPE REPRESENTING AN EXPRESSION OR STATEMENT
 *
 * The expressions and statements are represented by a union type, with one
 * field per expression or statement class. Every expression has an associated
 * type.
 */

union EXP (exp) = {
    /* Expression type */
    TYPE type ;
} + {
    identifier, member, ambiguous, undeclared -> {
        /* Identifiers */
        IDENTIFIER id ;
        QUALIFIER qual ;
    },
    int_lit -> {
        /* Integer literal */
        NAT nat ;
        unsigned etag ;
    },
    float_lit -> {
        /* Floating point literal */
        FLOAT flt ;
    },
    char_lit -> {
        /* Character literal */
        STRING str ;
        int digit ;
    },
    string_lit -> {
        /* String literal */
        STRING str ;
    },
    value -> {
        /* Undefined value */
    },
    null, zero -> {
        /* Null value (null pointer, zero etc.) */
    },
    paren, copy -> {
        /* Identity operation (used for parentheses) */
        EXP arg ;
    },
    assign -> {
        /* Assignment */
        EXP ref, arg ;
    },
    init -> {
        /* Initialisation */
        IDENTIFIER id ;
        EXP arg ;
    },
    preinc -> {
        /* Pre-increment */
        EXP ref, op ;
        int becomes ;
    },
    postinc -> {
        /* Post-increment */
        EXP ref, value, op ;
    },
    indir -> {
        /* Indirection */
        EXP ptr ;
        int index = "0" ;
    },
    contents -> {
        /* Contents */
        EXP ptr ;
    },
    address -> {
        /* Address of an object */
        EXP arg ;
    },
    address_mem -> {
        /* Address of a member */
        EXP arg ;
        int paren ;
    },
    func -> {
        /* Function call */
        EXP fn ;
        LIST EXP args ;
        unsigned extra = "0" ;
    },
    func_id -> {
        /* Named function call */
        IDENTIFIER id ;
        LIST EXP args ;
        EXP virt ;
        unsigned extra = "0" ;
    },
    call -> {
        /* Member function call */
        EXP ptr, arg ;
        GRAPH base ;
    },
    negate, compl, not, abs -> {
        /* Simple unary operations */
        EXP arg ;
    },
    plus, minus, mult, div, rem,
    and, or, xor, log_and, log_or,
    lshift, rshift, max, min -> {
        /* Simple binary operations */
        EXP arg1, arg2 ;
    },
    test -> {
        /* Compare against null value */
        NTEST tst ;
        EXP arg ;
    },
    compare -> {
        /* Compare two values */
        NTEST tst ;
        EXP arg1, arg2 ;
    },
    cast -> {
        /* Casts */
        unsigned conv ;
        EXP arg ;
    },
    base_cast -> {
        /* Base class conversion */
        unsigned conv ;
        EXP arg ;
        OFFSET off ;
    },
    dyn_cast -> {
        /* Dynamic cast */
        EXP arg ;
        EXP except ;
    },
    add_ptr -> {
        /* Add a value to a pointer */
        EXP ptr ;
        OFFSET off ;
        int virt ;
    },
    offset_size -> {
        /* Size of offset */
        OFFSET off ;
        TYPE step ;
        int pad ;
    },
    constr -> {
        /* Constructor call */
        EXP call, obj, alt ;
        int info ;
    },
    destr -> {
        /* Destructor call */
        EXP call, obj ;
        EXP count = "NULL_exp" ;
    },
    alloc -> {
        /* Allocator call */
        EXP call, init ;
        EXP garbage, size ;
    },
    dealloc -> {
        /* Deallocator call */
        EXP term, call ;
        EXP arg, size ;
    },
    rtti -> {
        /* Run-time type information */
        EXP arg ;
        EXP except ;
        int op ;
    },
    rtti_type -> {
        /* Run-time type information */
        TYPE arg ;
        int op ;
    },
    rtti_no -> {
        /* Arithmetic type number */
        TYPE arg ;
    },
    dynamic -> {
        /* Dynamic initialiser */
        EXP arg ;
    },
    aggregate -> {
        /* Aggregate initialisers */
        LIST EXP args ;
        LIST OFFSET offs ;
    },
    initialiser -> {
        /* Compound initialisers */
        LIST EXP args ;
        LIST OFFSET offs ;
        int kind ;
        unsigned virt, base ;
    },
    nof -> {
        /* Array initialisers */
        EXP start ;
        NAT size ;
        EXP pad ;
        EXP end ;
    },
    comma -> {
        /* Comma operator */
        LIST EXP args ;
    },
    set, unused -> {
        /* Variable analysis operators */
        EXP arg ;
    },
    reach, unreach -> {
        /* Flow analysis operators */
        EXP parent = "NULL_exp" ;
        EXP body ;
    },
    sequence -> {
        /* Sequence of statements */
        EXP parent = "NULL_exp" ;
        LIST EXP first, last ;
        NAMESPACE decl ;
        int block ;
    },
    solve_stmt -> {
        /* Label complex */
        EXP parent = "NULL_exp" ;
        EXP body ;
        LIST IDENTIFIER labels = "NULL_list ( IDENTIFIER )" ;
        LIST IDENTIFIER vars = "NULL_list ( IDENTIFIER )" ;
    },
    decl_stmt -> {
        /* Declaration statement */
        EXP parent = "NULL_exp" ;
        IDENTIFIER id ;
        EXP body ;
    },
    if_stmt -> {
        /* If statement */
        EXP parent = "NULL_exp" ;
        EXP cond ;
        EXP true_code, false_code ;
        IDENTIFIER label ;
    },
    while_stmt -> {
        /* While and for statements */
        EXP parent = "NULL_exp" ;
        EXP cond ;
        EXP body = "NULL_exp" ;
        IDENTIFIER break_lab ;
        IDENTIFIER cont_lab ;
        IDENTIFIER loop_lab ;
        LIST IDENTIFIER cond_id = "NULL_list ( IDENTIFIER )" ;
    },
    do_stmt -> {
        /* Do statements */
        EXP parent = "NULL_exp" ;
        EXP cond ;
        EXP body = "NULL_exp" ;
        IDENTIFIER break_lab ;
        IDENTIFIER cont_lab ;
        IDENTIFIER loop_lab ;
    },
    switch_stmt -> {
        /* Switch statement */
        EXP parent = "NULL_exp" ;
        EXP control ;
        EXP body ;
        LIST NAT cases = "NULL_list ( NAT )" ;
        LIST IDENTIFIER case_labs = "NULL_list ( IDENTIFIER )" ;
        IDENTIFIER default_lab = "NULL_id" ;
        int exhaust ;
        IDENTIFIER break_lab ;
    },
    hash_if -> {
        /* #if statement */
        EXP parent = "NULL_exp" ;
        EXP cond ;
        EXP true_code, false_code ;
        EXP last = "NULL_exp" ;
    },
    return_stmt -> {
        /* Return statement */
        EXP parent = "NULL_exp" ;
        EXP value ;
    },
    goto_stmt -> {
        /* Goto statement (including break and continue statements) */
        EXP parent = "NULL_exp" ;
        IDENTIFIER label ;
        EXP join ;
        EXP next ;
    },
    label_stmt -> {
        /* Labelled statement (including case and default statements) */
        EXP parent = "NULL_exp" ;
        IDENTIFIER label ;
        EXP body ;
        IDENTIFIER next = "NULL_id" ;
    },
    try_block -> {
        /* Try block */
        EXP parent = "NULL_exp" ;
        EXP body ;
        int func ;
        LIST EXP handlers = "NULL_list ( EXP )" ;
        LIST TYPE htypes = "NULL_list ( TYPE )" ;
        EXP ellipsis = "NULL_exp" ;
        LIST TYPE ttypes = "NULL_list ( TYPE )" ;
        LIST LOCATION tlocs = "NULL_list ( LOCATION )" ;
        ulong_type no = "LINK_NONE" ;
    },
    handler -> {
        /* Exception handler */
        EXP parent = "NULL_exp" ;
        IDENTIFIER except ;
        EXP body ;
        ulong_type diag = "LINK_NONE" ;
    },
    exception -> {
        /* Throw expression */
        EXP arg ;
        EXP size, destr ;
        int expl ;
    },
    thrown -> {
        /* Caught expression */
        int done ;
    },
    op -> {
        /* Undetermined operation */
        int lex ;
        EXP arg1, arg2 ;
    },
    opn -> {
        /* Undetermined operation */
        int lex ;
        LIST EXP args ;
    },
    assembler -> {
        /* asm expression */
        STRING op ;
        LIST EXP args ;
    },
    uncompiled -> {
        /* Uncompiled expression */
        LOCATION start ;
        PPTOKEN_P defn ;
    },
    location -> {
        /* Location expression */
        LOCATION end ;
        EXP arg ;
    },
    fail -> {
        /* Install-time failure */
        string msg ;
    },
    token -> {
        /* Tokenised expression */
        EXP parent = "NULL_exp" ;
        IDENTIFIER tok ;
        LIST TOKEN args ;
    },
    dummy -> {
        /* Dummy expression */
        EXP value ;
        ulong_type no ;
        OFFSET off ;
        int virt = "0" ;
        int cont ;
    }
} ;


/*
 * TYPE REPRESENTING AN OFFSET
 *
 * This type is used to represent an offset between two pointers. The type
 * construct gives the offset between successive elements of an array of that
 * type. The other constructs are fairly obvious.
 */

union OFFSET (off) = {
    /* empty */
} + {
    zero -> {
        /* Zero offset */
        TYPE type ;
    },
    type -> {
        /* Type offset */
        TYPE type ;
    },
    array -> {
        /* Array offset */
        TYPE type ;
        unsigned arg ;
    },
    extra -> {
        /* Extra offset for array allocator */
        TYPE type ;
        int scale ;
    },
    base -> {
        /* Base class offset */
        GRAPH graph ;
    },
    deriv -> {
        /* Derived class offset */
        GRAPH graph ;
        OFFSET direct ;
        OFFSET indirect ;
    },
    member -> {
        /* Member offset */
        IDENTIFIER id ;
    },
    ptr_mem -> {
        /* Pointer member offset */
        EXP arg ;
    },
    negate -> {
        /* Offset negation */
        OFFSET arg ;
    },
    plus -> {
        /* Offset addition */
        OFFSET arg1, arg2 ;
    },
    mult -> {
        /* Offset multiplication */
        OFFSET arg1 ;
        EXP arg2 ;
    },
    ptr_diff -> {
        /* Pointer difference */
        EXP ptr1, ptr2 ;
    },
    token -> {
        /* Tokenised offset */
        IDENTIFIER tok ;
        LIST TOKEN args ;
    }
} ;


/*
 * TYPE REPRESENTING A TOKEN
 *
 * This type is used to represent a TDF token. The various fields correspond to
 * the kinds of token - expressions, statements, types etc. Each simple
 * component also contains a field for holding a value of that kind, thus a
 * list of token arguments can themselves be expressed as a list of tokens.
 */

union TOKEN (tok) = {
    /* empty */
} + {
    exp -> {
        /* Expression tokens */
        TYPE type ;
        int constant ;
        EXP value ;
    },
    stmt -> {
        /* Statement tokens */
        EXP value ;
    },
    nat, snat -> {
        /* Integer constant tokens */
        NAT value ;
    },
    type -> {
        /* Type tokens */
        BASE_TYPE kind ;
        TYPE value ;
        TYPE alt = "NULL_type" ;
    },
    func -> {
        /* Function tokens */
        TYPE type ;
        IDENTIFIER defn = "NULL_id" ;
        TOKEN proc = "NULL_tok" ;
    },
    member -> {
        /* Class member tokens */
        TYPE of ;
        TYPE type ;
        OFFSET value ;
    },
    class -> {
        /* Template class tokens */
        TYPE type ;
        IDENTIFIER value ;
        TYPE alt = "NULL_type" ;
    },
    proc -> {
        /* Procedure tokens */
        TOKEN res ;
        NAMESPACE pars ;
        int key ;
        INSTANCE apps = "NULL_inst" ;
        LIST IDENTIFIER bids = "NULL_list ( IDENTIFIER )" ;
        LIST IDENTIFIER pids = "NULL_list ( IDENTIFIER )" ;
    },
    templ -> {
        /* Template tokens */
        DECL_SPEC usage ;
        NAMESPACE pars ;
        INSTANCE apps = "NULL_inst" ;
        LIST IDENTIFIER pids = "NULL_list ( IDENTIFIER )" ;
        LIST TOKEN dargs = "NULL_list ( TOKEN )" ;
    }
} ;


/*
 * TYPE REPRESENTING A TEMPLATE INSTANCE
 *
 * A template instance consists of an identifier, a type giving the template
 * form and a specifier giving declaration information.
 */

union INSTANCE (inst) = {
    TYPE form ;
    INSTANCE alias = "%0" ;
    INSTANCE next ;
} + {
    templ -> {
        /* Template instance */
        IDENTIFIER id ;
        TYPE spec = "NULL_type" ;
        DECL_SPEC access ;
        PPTOKEN_P mode = "NULL" ;
        LIST IDENTIFIER mems = "NULL_list ( IDENTIFIER )" ;
        INSTANCE prev ;
    },
    token -> {
        /* Token type instance */
        ulong_type no = "LINK_NONE" ;
    }
} ;


/*
 * TYPE REPRESENTING A VARIABLE ANALYSIS STATE
 *
 * This type is used in the variable analysis routines to record the state of a
 * local variable.
 */

struct VARIABLE (var) = {
    IDENTIFIER id ;
    DECL_SPEC info ;
} ;


/*
 * TYPE REPRESENTING AN ERROR
 *
 * An error can be either a simple message, described by an error number, or a
 * compound formed from two other errors. Some trickery is used to store the
 * arguments for a simple error after its size field.
 */

union ERROR (err) = {
    int severity ;
} + {
    simple -> {
        /* Simple errors */
        int number ;
        unsigned size = "0" ;
        /* arguments ... */
    },
    compound -> {
        /* Compound errors */
        ERROR head, tail ;
    }
} ;


/*
 * TYPE REPRESENTING A FILE POSITION
 *
 * A file position consists of a line number plus a pointer to a type giving
 * the file name.
 */

struct LOCATION (loc) = {
    ulong_type line ;
    ulong_type column ;
    PTR POSITION posn ;
} ;

struct POSITION (posn) = {
    string file ;
    string input ;
    string base ;
    string dir ;
    ulong_type offset ;
    PTR LOCATION from ;
    ulong_type datestamp ;
    ulong_type tok = "LINK_NONE" ;
} ;