Subversion Repositories tendra.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
                 Crown Copyright (c) 1997
    
    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.
*/


%types%

/*
    TYPES

    The types are fairly self-explanitory.  There are types for each of
    the concepts in the syntax, plus list types for most of them.
*/

CLASS-ID ;
FLAG ;
IDENTIFIER ;
NUMBER ;
TYPE ;
STRING ;

ARGUMENT ;
COMPONENT ;
ECONST ;
ENUM ;
FIELD ;
IDENTITY ;
MAP ;
PRIMITIVE ;
STRUCTURE ;
UNION ;

ARGUMENT-LIST ;
COMPONENT-LIST ;
ECONST-LIST ;
ENUM-LIST ;
FIELD-LIST ;
IDENTITY-LIST ;
MAP-LIST ;
PRIMITIVE-LIST ;
STRUCTURE-LIST ;
UNION-LIST ;


%terminals%

/*
    TERMINALS

    The terminals are in three groups, identifiers etc., keywords and
    symbols.
*/

identifier : () -> ( :IDENTIFIER ) ;
number : () -> ( :NUMBER ) ;
string : () -> ( :STRING ) ;

algebra ;
enum ;
struct ;
union ;
import ;

extras ;
identities ;
maps ;
primitives ;
structures ;
unions ;
with ;

list ;
ptr ;
stack ;
vec ;
vec-ptr ;

and ;
arrow ;
close-brace ;
close-round ;
close-square ;
colon ;
colon-colon ;
comma ;
compl ;
div ;
dot ;
eof ;
equal ;
exclaim ;
hash ;
lshift ;
minus ;
open-brace ;
open-round ;
open-square ;
or ;
plus ;
question ;
rem ;
rshift ;
semicolon ;
star ;
xor ;
!unknown ;


%productions%


/*
    ACTION DECLARATIONS

    Only the declarations of the various actions are given here.  They
    are described in more detail in the actions definition file.
*/

<zero> : () -> ( :FLAG ) ;
<one> : () -> ( :FLAG ) ;
<two> : () -> ( :FLAG ) ;
<three> : () -> ( :FLAG ) ;

<syntax-error> : () -> () ;

<null-string> : () -> ( :STRING ) ;
<null-identifier> : () -> ( :IDENTIFIER ) ;

<default-name> : ( :IDENTIFIER ) -> ( :IDENTIFIER ) ;
<make-class-id> : ( :IDENTIFIER, :IDENTIFIER, :FLAG ) -> ( :CLASS-ID ) ;

<find-type> : ( :IDENTIFIER ) -> ( :TYPE ) ;
<ptr-type> : ( :TYPE ) -> ( :TYPE ) ;
<list-type> : ( :TYPE ) -> ( :TYPE ) ;
<stack-type> : ( :TYPE ) -> ( :TYPE ) ;
<vec-type> : ( :TYPE ) -> ( :TYPE ) ;
<vec-ptr-type> : ( :TYPE ) -> ( :TYPE ) ;
<quoted-type> : ( :STRING ) -> ( :TYPE ) ;
<error-type> : () -> ( :TYPE ) ;

<null-econst> : () -> ( :ECONST-LIST ) ;
<make-econst> : ( :IDENTIFIER ) -> ( :ECONST ) ;
<join-econst> : ( :ECONST, :ECONST-LIST ) -> ( :ECONST-LIST ) ;
<set-econst> : ( :NUMBER ) -> () ;

<null-primitive> : () -> ( :PRIMITIVE-LIST ) ;
<make-primitive> : ( :CLASS-ID, :STRING ) -> ( :PRIMITIVE ) ;
<join-primitive> : ( :PRIMITIVE, :PRIMITIVE-LIST ) -> ( :PRIMITIVE-LIST ) ;

<null-identity> : () -> ( :IDENTITY-LIST ) ;
<make-identity> : ( :CLASS-ID, :TYPE ) -> ( :IDENTITY ) ;
<join-identity> : ( :IDENTITY, :IDENTITY-LIST ) -> ( :IDENTITY-LIST ) ;

<exp-crt> : () -> ( :NUMBER ) ;
<exp-id> : ( :IDENTIFIER ) -> ( :NUMBER ) ;
<exp-neg> : ( :NUMBER ) -> ( :NUMBER ) ;
<exp-compl> : ( :NUMBER ) -> ( :NUMBER ) ;
<exp-mult> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-div> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-rem> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-plus> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-minus> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-lshift> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-rshift> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-and> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-xor> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;
<exp-or> : ( :NUMBER, :NUMBER ) -> ( :NUMBER ) ;

<null-enum> : () -> ( :ENUM-LIST ) ;
<get-enum> : ( :IDENTIFIER ) -> ( :ECONST-LIST ) ;
<make-enum> : ( :CLASS-ID, :FLAG, :ECONST-LIST, :ECONST-LIST ) -> ( :ENUM ) ;
<join-enum> : ( :ENUM, :ENUM-LIST ) -> ( :ENUM-LIST ) ;

<null-component> : () -> ( :COMPONENT-LIST ) ;
<make-component> : ( :IDENTIFIER, :TYPE, :STRING ) -> ( :COMPONENT ) ;
<join-component> : ( :COMPONENT, :COMPONENT-LIST ) -> ( :COMPONENT-LIST ) ;
<link-component> : ( :COMPONENT-LIST, :COMPONENT-LIST ) -> ( :COMPONENT-LIST ) ;

<null-structure> : () -> ( :STRUCTURE-LIST ) ;
<make-structure> : ( :CLASS-ID, :IDENTIFIER, :COMPONENT-LIST ) -> ( :STRUCTURE ) ;
<join-structure> : ( :STRUCTURE, :STRUCTURE-LIST ) -> ( :STRUCTURE-LIST ) ;

<null-field> : () -> ( :FIELD-LIST ) ;
<make-field> : ( :IDENTIFIER, :COMPONENT-LIST, :FLAG ) -> ( :FIELD ) ;
<join-field> : ( :FIELD, :FIELD-LIST ) -> ( :FIELD-LIST ) ;
<link-field> : ( :FIELD-LIST, :FIELD-LIST ) -> ( :FIELD-LIST ) ;
<set-field-cmp> : ( :FIELD-LIST, :IDENTIFIER, :COMPONENT-LIST ) -> () ;

<null-argument> : () -> ( :ARGUMENT-LIST ) ;
<make-argument> : ( :IDENTIFIER, :TYPE ) -> ( :ARGUMENT ) ;
<join-argument> : ( :ARGUMENT, :ARGUMENT-LIST ) -> ( :ARGUMENT-LIST ) ;
<link-argument> : ( :ARGUMENT-LIST, :ARGUMENT-LIST ) -> ( :ARGUMENT-LIST ) ;

<null-map> : () -> ( :MAP-LIST ) ;
<make-map> : ( :IDENTIFIER, :TYPE, :ARGUMENT-LIST, :FLAG ) -> ( :MAP ) ;
<join-map> : ( :MAP, :MAP-LIST ) -> ( :MAP-LIST ) ;

<null-union> : () -> ( :UNION-LIST ) ;
<make-union> : ( :CLASS-ID, :IDENTIFIER, :COMPONENT-LIST, :FIELD-LIST, :MAP-LIST ) -> ( :UNION ) ;
<join-union> : ( :UNION, :UNION-LIST ) -> ( :UNION-LIST ) ;

<make-extra> : ( :TYPE ) -> () ;

<import-all> : ( :IDENTIFIER ) -> () ;
<import-one> : ( :IDENTIFIER, :IDENTIFIER ) -> () ;

<set-main> : ( :IDENTIFIER ) -> () ;
<set-version> : ( :NUMBER, :NUMBER ) -> () ;
<add-primitive> : ( :PRIMITIVE-LIST ) -> () ;
<add-identity> : ( :IDENTITY-LIST ) -> () ;
<add-enum> : ( :ENUM-LIST ) -> () ;
<add-structure> : ( :STRUCTURE-LIST ) -> () ;
<add-union> : ( :UNION-LIST ) -> () ;

<set-old-unit> : () -> () ;
<set-new-unit> : () -> () ;


/*
    CLASS IDENTIFIERS

    A class identifier consists of a pair of identifiers (the second of
    which is optional) qualified as above.
*/

class-id : () -> ( i : CLASS-ID ) = {
        {
                n = <zero> ;
            ||  hash ; n = <one> ;
            ||  colon ; n = <two> ;
            ||  hash ; colon ; n = <three> ;
        } ;
        c = identifier ;
        {
                a = <default-name> ( c ) ;
            ||  open-round ; a = identifier ; close-round ;
        } ;
        i = <make-class-id> ( c, a, n ) ;
} ;


/*
    TYPES

    The basic types are the named types defined in the algebra, plus
    those formed by the vector, pointer, list and vector-pointer type
    constructors.
*/

type : () -> ( t : TYPE ) = {
        i = identifier ; t = <find-type> ( i ) ;
    ||  list ; s = type ; t = <list-type> ( s ) ;
    ||  ptr ; s = type ; t = <ptr-type> ( s ) ;
    ||  stack ; s = type ; t = <stack-type> ( s ) ;
    ||  vec ; s = type ; t = <vec-type> ( s ) ;
    ||  vec-ptr ; s = type ; t = <vec-ptr-type> ( s ) ;
    ##  t = <error-type> ;
} ;


/*
    EXTENDED TYPES

    In some circumstances types may also be given by means of a quoted
    C type.
*/

extended-type : () -> ( t : TYPE ) = {
        t = type ;
    ||  s = string ; t = <quoted-type> ( s ) ;
    ##  t = <error-type> ;
} ;


/*
    PRIMITIVE DEFINITIONS

    Each primitive consists of a class identifier plus a string giving
    the C type corresponding to the primitive.
*/

primitive-defn : ( i : CLASS-ID ) -> ( p : PRIMITIVE ) = {
        s = string ; semicolon ;
        p = <make-primitive> ( i, s ) ;
} ;

primitive-list : () -> ( p : PRIMITIVE-LIST ) = {
        p = <null-primitive> ;
    ||
        i = class-id ; colon ; q = primitive-defn ( i ) ;
        r = primitive-list ;
        p = <join-primitive> ( q, r ) ;
} ;

primitive-single : () -> ( p : PRIMITIVE-LIST ) = {
        i = class-id ; equal ; q = primitive-defn ( i ) ;
        r = <null-primitive> ;
        p = <join-primitive> ( q, r ) ;
} ;


/*
    IDENTITY DEFINITIONS

    Each identity consists of a class identifier plus a type which forms
    the definition of the identity.
*/

identity-defn : ( i : CLASS-ID ) -> ( p : IDENTITY ) = {
        t = type ; semicolon ;
        p = <make-identity> ( i, t ) ;
} ;

identity-list : () -> ( p : IDENTITY-LIST ) = {
        p = <null-identity> ;
    ||
        i = class-id ; colon ; q = identity-defn ( i ) ;
        r = identity-list ;
        p = <join-identity> ( q, r ) ;
} ;

identity-single : () -> ( p : IDENTITY-LIST ) = {
        i = class-id ; equal ; q = identity-defn ( i ) ;
        r = <null-identity> ;
        p = <join-identity> ( q, r ) ;
} ;


/*
    ENUMERATOR VALUE

    These rules describe the ways of calculating the value of an enumerator.
*/

expression : () -> ( :NUMBER ) ;

primary-exp : () -> ( n : NUMBER ) = {
        n = number ;
    ||  e = identifier ; n = <exp-id> ( e ) ;
    ||  question ; n = <exp-crt> ;
    ||  open-round ; n = expression ; close-round ;
} ;

unary-exp : () -> ( n : NUMBER ) = {
        n = primary-exp ;
    ||  plus ; n = number ;
    ||  minus ; m = number ; n = <exp-neg> ( m ) ;
    ||  compl ; m = number ; n = <exp-compl> ( m ) ;
} ;

mult-exp : () -> ( n : NUMBER ) = {
        n = unary-exp ;
    ||  m = mult-exp ; star ; p = unary-exp ; n = <exp-mult> ( m, p ) ;
    ||  m = mult-exp ; div ; p = unary-exp ; n = <exp-div> ( m, p ) ;
    ||  m = mult-exp ; rem ; p = unary-exp ; n = <exp-rem> ( m, p ) ;
} ;

add-exp : () -> ( n : NUMBER ) = {
        n = mult-exp ;
    ||  m = add-exp ; plus ; p = mult-exp ; n = <exp-plus> ( m, p ) ;
    ||  m = add-exp ; minus ; p = mult-exp ; n = <exp-minus> ( m, p ) ;
} ;

shift-exp : () -> ( n : NUMBER ) = {
        n = add-exp ;
    ||  m = shift-exp ; lshift ; p = add-exp ; n = <exp-lshift> ( m, p ) ;
    ||  m = shift-exp ; rshift ; p = add-exp ; n = <exp-rshift> ( m, p ) ;
} ;

and-exp : () -> ( n : NUMBER ) = {
        n = shift-exp ;
    ||  m = and-exp ; and ; p = shift-exp ; n = <exp-and> ( m, p ) ;
} ;

xor-exp : () -> ( n : NUMBER ) = {
        n = and-exp ;
    ||  m = xor-exp ; xor ; p = and-exp ; n = <exp-xor> ( m, p ) ;
} ;

or-exp : () -> ( n : NUMBER ) = {
        n = xor-exp ;
    ||  m = or-exp ; or ; p = xor-exp ; n = <exp-or> ( m, p ) ;
} ;

expression : () -> ( n : NUMBER ) = {
        n = or-exp ;
} ;


/*
    ENUMERATOR LIST

    An enumerator is just an identifier.  A comma separated list of
    enumerators is used to define an enumeration.
*/

enumerator-list : () -> ( p : ECONST-LIST ) = {
        p = <null-econst> ;
    ||
        s = identifier ;
        {
                equal ; n = expression ; <set-econst> ( n ) ;
            ||  $ ;
        } ;
        q = <make-econst> ( s ) ;
        {
                r = <null-econst> ;
            ||  comma ; r = enumerator-list ;
        } ;
        p = <join-econst> ( q, r ) ;
} ;


/*
    ENUMERATION DEFINITIONS

    Each enumeration consists of a class identifier plus a list of
    enumerators which comprise the enumeration.
*/

enum-single : () -> ( p : ENUM-LIST ) = {
        enum ;
        {
                l = <one> ;
            ||  exclaim ; l = <zero> ;
        } ;
        i = class-id ; equal ;
        {
                j = identifier ; f = <get-enum> ( j ) ; plus ;
            ||  f = <null-econst> ;
        } ;
        open-brace ; e = enumerator-list ; close-brace ; semicolon ;
        q = <make-enum> ( i, l, f, e ) ;
        r = <null-enum> ;
        p = <join-enum> ( q, r ) ;
} ;


/*
    STRUCTURE COMPONENT DECLARATOR

    A structure component declarator consists of a comma separated list
    of identifiers, all of which are declared to have the given type t.
*/

component-decl : ( t : TYPE ) -> ( p : COMPONENT-LIST ) = {
        i = identifier ;
        {
                v = <null-string> ;
            ||  equal ; v = string ;
        } ;
        q = <make-component> ( i, t, v ) ;
        {
                r = <null-component> ;
            ||  comma ; r = component-decl ( t ) ;
        } ;
        p = <join-component> ( q, r ) ;
} ;


/*
    STRUCTURE COMPONENTS

    Each structure component consists of a component type plus a list
    of component declarators which are declared to be of that type.
*/

component-list : () -> ( p : COMPONENT-LIST ) = {
        p = <null-component> ;
    ||
        t = type ; q = component-decl ( t ) ; semicolon ;
        r = component-list ;
        p = <link-component> ( q, r ) ;
} ;


/*
    GROUP OF STRUCTURE COMPONENTS

    The definition of a structure consists of a list of structure components
    enclosed in braces.
*/

component-group : () -> ( p : COMPONENT-LIST ) = {
        open-brace ; p = component-list ; close-brace ;
} ;


/*
    STRUCTURE DEFINITIONS

    Each structure consists of a class identifier plus a list of the
    components comprising the structure.
*/

structure-defn : ( i : CLASS-ID, j : IDENTIFIER ) -> ( p : STRUCTURE ) = {
        c = component-group ; semicolon ;
        p = <make-structure> ( i, j, c ) ;
} ;

structure-list : () -> ( p : STRUCTURE-LIST ) = {
        p = <null-structure> ;
    ||
        i = class-id ; j = <null-identifier> ;
        q = structure-defn ( i, j ) ;
        r = structure-list ;
        p = <join-structure> ( q, r ) ;
} ;

structure-single : () -> ( p : STRUCTURE-LIST ) = {
        struct ; i = class-id ; equal ;
        {
                j = identifier ; plus ;
            ||  j = <null-identifier> ;
        } ;
        q = structure-defn ( i, j ) ;
        r = <null-structure> ;
        p = <join-structure> ( q, r ) ;
} ;


/*
    UNION FIELD DEFINITIONS

    Each union field component consists of a list of field identifiers
    (qualified by nought, one or two hash symbols) and a list of
    structure components.
*/

field-id-list : ( n : FLAG ) -> ( p : FIELD-LIST ) = {
        i = identifier ;
        c = <null-component> ;
        q = <make-field> ( i, c, n ) ;
        {
                r = <null-field> ;
            ||  comma ; r = field-id-list ( n ) ;
        } ;
        p = <join-field> ( q, r ) ;
} ;

field-list : () -> ( p : FIELD-LIST ) = {
        {
                n = <zero> ;
            ||  hash ; n = <one> ;
            ||  hash ; hash ; n = <two> ;
        } ;
        q = field-id-list ( n ) ; arrow ;
        {
                j = identifier ; plus ;
            ||  j = <null-identifier> ;
        } ;
        c = component-group ;
        <set-field-cmp> ( q, j, c ) ;
        {
                r = <null-field> ;
            ||  comma ; r = field-list ;
        } ;
        p = <link-field> ( q, r ) ;
} ;


/*
    MAP ARGUMENT DECLARATORS

    A map argument declarator consists of a list of identifiers, each of
    which is declared as a argument of the given type t.
*/

argument-decl : ( t : TYPE ) -> ( p : ARGUMENT-LIST ) = {
        i = identifier ;
        q = <make-argument> ( i, t ) ;
        {
                r = <null-argument> ;
            ||  comma ; r = argument-decl ( t ) ;
        } ;
        p = <join-argument> ( q, r ) ;
} ;


/*
    MAP ARGUMENT LISTS

    Each map argument consists of a type (which may be a quoted C type)
    followed by a list of argument declarators which declare arguments
    of that type.
*/

argument-list : () -> ( p : ARGUMENT-LIST ) = {
        t = extended-type ;
        q = argument-decl ( t ) ;
        {
                r = <null-argument> ;
            ||  semicolon ; r = argument-list ;
        } ;
        p = <link-argument> ( q, r ) ;
} ;


/*
    UNION MAP DEFINITIONS

    Each union map consists of a map return type, followed by the map
    identifier (which may be qualified by a hash symbol), and a list
    of map arguments.
*/

map-list : () -> ( p : MAP-LIST ) = {
        p = <null-map> ;
    ||
        t = extended-type ;
        {
                n = <zero> ;
            ||  hash ; n = <one> ;
        } ;
        i = identifier ;
        open-round ;
        {
                a = <null-argument> ;
            ||  a = argument-list ;
        } ;
        close-round ;
        q = <make-map> ( i, t, a, n ) ;
        r = map-list ;
        p = <join-map> ( q, r ) ;
} ;


/*
    OLD-STYLE UNION DEFINITION BODY

    Both old and new style union definitions give the same information.
    There is an optional list of structure components, which are common
    to all forms of the union.  This is followed by a list of union
    fields, describing the components which are particular to each form.
    Finally there is a list of union maps.
*/

union-defn-old : ( i : CLASS-ID ) -> ( p : UNION ) = {
        {
                c = <null-component> ;
            ||  c = component-group ;
        } ;
        {
                f = <null-field> ;
            ||  f = field-list ;
        } ;
        with ; maps ; open-square ; m = map-list ; close-square ;
        j = <null-identifier> ;
        p = <make-union> ( i, j, c, f, m ) ;
} ;


/*
    NEW-STYLE UNION DEFINITION BODY

    New-style union definitions convey the same information as the
    old-style, only differently punctuated.
*/

union-defn-new : ( i : CLASS-ID ) -> ( p : UNION ) = {
        equal ;
        {
                c = component-group ; j = <null-identifier> ;
            ||  c = <null-component> ; j = identifier ;
        } ;
        plus ; open-brace ; f = field-list ; close-brace ;
        {
                m = <null-map> ;
            ||  colon ; open-square ; m = map-list ; close-square ;
        } ;
        semicolon ;
        p = <make-union> ( i, j, c, f, m ) ;
} ;


/*
    UNION DEFINITIONS

    Each union consists of a class identifier plus a further section
    of information.  This information is expressed differently depending
    on whether the new-style or the old-style syntax is being used.
*/

union-list : () -> ( p : UNION-LIST ) = {
        p = <null-union> ;
    ||
        i = class-id ; q = union-defn-old ( i ) ;
        r = union-list ;
        p = <join-union> ( q, r ) ;
} ;

union-single : () -> ( p : UNION-LIST ) = {
        union ; i = class-id ; q = union-defn-new ( i ) ;
        r = <null-union> ;
        p = <join-union> ( q, r ) ;
} ;


/*
    EXTRA DEFINITIONS

    The extra components are just a list of types.
*/

extra-list : () -> () = {
        $ ;
    ||
        t = type ; semicolon ;
        <make-extra> ( t ) ;
        extra-list ;
} ;


/*
    IMPORT ITEM

    This rule gives the different type of import rules.
*/

import-item : () -> () = {
        a = identifier ;
        <import-all> ( a ) ;
    ||
        a = identifier ; colon-colon ; i = identifier ;
        <import-one> ( a, i ) ;
} ;


/*
    OLD UNIT DEFINITION

    This rule gives the old form of the syntax.  Each section has a fixed
    position, and the algebra is terminated by a final hash symbol.
*/

old-unit : () -> () = {
        m = identifier ; <set-main> ( m ) ; colon ;
        primitives ; colon ; p = primitive-list ; <add-primitive> ( p ) ;
        identities ; colon ; i = identity-list ; <add-identity> ( i ) ;
        structures ; colon ; s = structure-list ; <add-structure> ( s ) ;
        unions ; colon ; u = union-list ; <add-union> ( u ) ;
        extras ; colon ; extra-list ;
        hash ;
} ;


/*
    NEW UNIT DEFINITION

    This rule gives the new form of the syntax.  After the initial name
    section, the subsequent sections may appear in any order (and more
    than once).
*/

new-item-list : () -> () = {
        $ ;
    ||
        {
                p = primitive-single ; <add-primitive> ( p ) ;
            ||  i = identity-single ; <add-identity> ( i ) ;
            ||  e = enum-single ; <add-enum> ( e ) ;
            ||  s = structure-single ; <add-structure> ( s ) ;
            ||  u = union-single ; <add-union> ( u ) ;
            ||  import ; import-item ; semicolon ;
        } ;
        new-item-list ;
} ;

new-unit : () -> () = {
        algebra ; <set-new-unit> ; m = identifier ; <set-main> ( m ) ;
        {
                $ ;
            ||
                open-round ; a = number ; dot ; b = number ; close-round ;
                <set-version> ( a, b ) ;
        } ;
        colon ;
        new-item-list ;
} ;


/*
    UNIT DEFINITION

    This rule is the main entry point.  The input consists of either an
    old-style or a new-style unit.
*/

unit : () -> () = {
        <set-old-unit> ;
        {
                old-unit ;
            ||  new-unit ;
        } ;
        eof ;
    ##
        <syntax-error> ;
} ;


/*
    EXTRA UNIT DEFINITION

    This rule is the auxilliary entry point for extra types.
*/

extra-unit : () -> () = {
        extra-list ;
        eof ;
    ##
        <syntax-error> ;
} ;

%entry% unit, extra-unit ;