Subversion Repositories tendra.SVN

Rev

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

/*
                 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.
*/


/*
    PRAGMA SYNTAX

    This module gives the syntax for the '#pragma' directives recognised
    by the producer.
*/


/*
    TYPE DECLARATIONS

    The types BOOL, COUNT and LEX are natural types arising from the
    parser.  The remaining types directly correspond to types within the
    main program, or composite types formed from them.
*/

%types%

ACCESS ;
BOOL ;
BTYPE ;
CV ;
EXP ;
IDENTIFIER ;
LEX ;
LINKAGE ;
LIST-ID ;
NAMESPACE ;
NUMBER ;
STATE ;
TOKEN ;
TYPE ;
VALUE ;


/*
    LIST OF TERMINALS

    This list of terminals corresponds to that given in symbols.h and
    syntax.h.
*/

%terminals%

!unknown ;

/* Identifiers */
identifier : () -> ( :IDENTIFIER ) ;
type-name : () -> ( :IDENTIFIER ) ;
namespace-name : () -> ( :IDENTIFIER ) ;
statement-name : () -> ( :IDENTIFIER ) ;
!destructor-name : () -> ( :IDENTIFIER ) ;
!template-id : () -> ( :IDENTIFIER ) ;
!template-type : () -> ( :IDENTIFIER ) ;

/* Nested name specifiers */
!nested-name : () -> ( :NAMESPACE ) ;
!full-name : () -> ( :NAMESPACE ) ;
!nested-name-star : () -> ( :IDENTIFIER ) ;
!full-name-star : () -> ( :IDENTIFIER ) ;

/* Literals */
!char-lit ; !wchar-lit ; !string-lit ; !wstring-lit ; !integer-lit ;

/* Literal expressions */
char-exp : () -> ( :EXP ) ;
wchar-exp : () -> ( :EXP ) ;
string-exp : () -> ( :EXP ) ;
wstring-exp : () -> ( :EXP ) ;
integer-exp : () -> ( :EXP ) ;
!floating-exp : () -> ( :EXP ) ;

/* Token applications */
!complex-exp : () -> ( :EXP ) ;
!complex-stmt : () -> ( :EXP ) ;
!complex-type : () -> ( :TYPE ) ;

/* Target-dependent preprocessing directives */
!hash-if : () -> ( :EXP ) ;
!hash-elif : () -> ( :EXP ) ;
!hash-else ;
!hash-endif ;
!hash-pragma ;

/* End of file markers */
!newline ; !eof ;

/* Symbols */
!and-1 ; !and-eq-1 ; !arrow ; !assign ; !backslash ; close-brace-1 ;
close-round ; !close-square-1 ; colon ; comma ; !compl-1 ; div ; !div-eq ;
dot ; ellipsis ; eq ; !greater ; !greater-eq ; hash-1 ; !hash-hash-1 ;
!less ; !less-eq ; !logical-and-1 ; !logical-or-1 ; !lshift ; !lshift-eq ;
minus ; !minus-eq ; !minus-minus ; !not-1 ; !not-eq-1 ; open-brace-1 ;
open-round ; !open-square-1 ; or-1 ; !or-eq-1 ; plus ; !plus-eq ;
!plus-plus ; question ; !rem ; !rem-eq ; !rshift ; !rshift-eq ;
semicolon ; star ; !star-eq ; !xor-1 ; !xor-eq-1 ; !arrow-star ;
colon-colon ; !dot-star ; !abs ; !max ; !min ;

/* Digraphs */
!close-brace-2 ; !close-square-2 ; !hash-2 ; !hash-hash-2 ;
!open-brace-2 ; !open-square-2 ;

/* C keywords */
auto ; !break ; case ; !char ; const ; !continue ; !default ; !do ;
!double ; !else ; enum ; !extern ; !float ; for ; !goto ; !if ; int ;
long ; !register ; return ; !short ; signed ; !sizeof ; static ; struct ;
switch ; !typedef ; union ; unsigned ; void ; volatile ; !while ;

/* C++ keywords */
asm ; bool ; catch ; !class ; const-cast ; !delete ; !dynamic-cast ;
explicit ; export ; !false ; !friend ; inline ; !mutable ; namespace ;
!new ; operator ; private ; protected ; public ; reinterpret-cast ;
static-cast ; template ; this ; throw ; !true ; !try ; !typeid ;
!typename ; !using ; !virtual ; wchar-t ;

/* ISO keywords */
!and-2 ; !and-eq-2 ; !compl-2 ; !logical-and-2 ; !logical-or-2 ;
!not-2 ; !not-eq-2 ; !or-2 ; !or-eq-2 ; !xor-2 ; !xor-eq-2 ;

/* TenDRA keywords */
accept ; after ; !alignof ; all ; allow ; ambiguous ; analysis ;
argument ; arith-cap ; !array ; as ; assert ; assignment ; begin ;
bitfield ; block ; bottom ; cast ; character ; class-cap ; code ;
comment ; compatible ; complete ; compute ; conditional ; conversion ;
decimal ; decl ; define ; !define-cap ; !defined ; definition ; depth ;
directive ; directory ; disallow ; discard ; dollar ; either ; !elif ;
ellipsis-exp ; end ; !endif ; environment ; equality ; error ; escape ;
exhaustive ; exp-cap ; !explain ; !extend ; external ; extra ; fall ;
file ; float-cap ; forward ; func-cap ; function ; hexadecimal ; hiding ;
ident ; identif ; !ifdef ; !ifndef ; ignore ; !implement ; implicit ;
import ; !include ; includes ; include-next ; incompatible ; incomplete ;
indented ; initialization ; integer ; interface ; internal ; into ;
int-cap ; keyword ; limit ; !line ; linkage ; lit ; longlong ; lvalue ;
macro ; !main ; member ; member-cap ; name ; nat-cap ; nested ; nline ;
no ; no-def ; object ; octal ; of ; off ; on ; option ; overflow ;
overload ; pointer ; postpone ; pragma ; precedence ; preserve ; printf ;
proc-cap ; promote ; promoted ; prototype ; ptrdiff-t ; qualifier ;
quote ; reachable ; !reference ; reject ; representation ; reset ;
resolution ; rvalue ; scalar-cap ; scanf ; set ; size-t ; !size-t-2 ;
!sort ; std ; stmt-cap ; string ; struct-cap ; suspend ; tag ; tag-cap ;
!tendra ; text ; !this-name ; token ; type ; type-cap ; !typeof ;
un-known ; unassert ; undef ; unify ; union-cap ; unmatched ; unpostpone ;
unreachable ; !unused ; use ; value ; variable ; variety-cap ;
volatile-t ; !vtable ; warning ; weak ; writeable ; !zzzz ;

/* Miscellaneous symbols */
!array-op ; !builtin-file ; !builtin-line ; !close-template ; !cond-op ;
!delete-full ; !delete-array ; !delete-array-full ; !func-op ; !hash-op ;
!hash-hash-op ; !inset-start ; !inset-end ; !macro-arg ; !new-full ;
!new-array ; !new-array-full ; !open-init ; !open-template ; !zzzzzz ;


/*
    ALTERNATIVE REPRESENTATIONS

    The ISO keywords and digraphs will have been replaced by their primary
    representations by this stage.  These rules are effectively identities
    for these alternatives.  Don't try removing them - SID gets very
    confused.
*/

%productions%

close-brace =   { close-brace-1 ; } ;
open-brace =    { open-brace-1 ; } ;
hash =          { hash-1 ; } ;
or =            { or-1 ; } ;
ellipsis-aux =  { ellipsis ; || ellipsis-exp ; } ;


/*
    IDENTIFIERS

    The identifier terminal is exclusive - it does not include those
    identifiers which are actually type and namespace names.  This rule
    gives all identifiers and sets the appropriate identifier type.
*/

any-identifier : () -> ( id : IDENTIFIER ) = {
        id = identifier ;
    ||  id = type-name ;
    ||  id = namespace-name ;
    ||  id = statement-name ;
} ;


/*
    LITERAL EXPRESSIONS

    These rules describe the literal expressions.  These are the integer
    and floating point literals, the character and string literals, plus
    the boolean literals true and false.  Concatenation of adjacent string
    literals has already been performed.
*/

integer-literal : () -> ( e : EXP ) = {
        e = integer-exp ;
} ;

character-literal : () -> ( e : EXP ) = {
        e = char-exp ;
    ||  e = wchar-exp ;
} ;

string-literal : () -> ( e : EXP ) = {
        e = string-exp ;
    ||  e = wstring-exp ;
} ;


/*
    PROCEDURE TOKEN SYNTAX

    These rules describe the parameter syntax for procedure tokens.
*/

<parse_type> : () -> ( :TYPE ) ;
<parse_mem_type> : () -> ( :TYPE ) ;
<parse_func_type> : () -> ( :TYPE ) ;
<list_id_null> : () -> ( :LIST-ID ) ;
<list_id_cons> : ( :IDENTIFIER, :LIST-ID ) -> ( :LIST-ID ) ;
<token_param> : ( :TOKEN, :BOOL, :IDENTIFIER ) -> ( :IDENTIFIER ) ;
<token_exp_par> : ( :IDENTIFIER, :LIST-ID ) -> ( :IDENTIFIER ) ;
<token_stmt_par> : ( :IDENTIFIER, :LIST-ID ) -> ( :IDENTIFIER ) ;
<token_type_par> : ( :TYPE, :LIST-ID ) -> ( :IDENTIFIER ) ;
<token_member_par> : ( :TYPE, :IDENTIFIER, :LIST-ID ) -> ( :IDENTIFIER ) ;
<token_proc_par> : ( :IDENTIFIER, :LIST-ID ) -> ( :IDENTIFIER ) ;
<id_anon> : () -> ( :IDENTIFIER ) ;
<bool_true> : () -> ( :BOOL ) ;
<bool_false> : () -> ( :BOOL ) ;
<error_comma> : () -> () ;

token-introduction : () -> ( :TOKEN ) ;

tag-opt : () -> ( t : BOOL ) = {
        tag-cap ; t = <bool_true> ;
    ||  t = <bool_false> ;
} ;

bound-tok-param : () -> ( id : IDENTIFIER ) = {
        tok = token-introduction ;
        t = tag-opt ; tid = any-identifier ;
        id = <token_param> ( tok, t, tid ) ;
} ;

bound-tok-pars : () -> ( p : LIST-ID ) = {
        id = bound-tok-param ;
        {
                comma ; q = bound-tok-pars ;
            ||  comma ; <error_comma> ; q = <list_id_null> ;
            ||  q = <list_id_null> ;
        } ;
        p = <list_id_cons> ( id, q ) ;
} ;

prog-tok-param : ( r : LIST-ID ) -> ( id : IDENTIFIER ) = {
        exp-cap ; tid = any-identifier ;
        id = <token_exp_par> ( tid, r ) ;
    ||
        stmt-cap ; tid = any-identifier ;
        id = <token_stmt_par> ( tid, r ) ;
    ||
        type-cap ; t = <parse_type> ;
        id = <token_type_par> ( t, r ) ;
    ||
        member-cap ;
        t = <parse_type> ; colon ; tid = any-identifier ;
        id = <token_member_par> ( t, tid, r ) ;
    ||
        proc-cap ; tid = any-identifier ;
        id = <token_proc_par> ( tid, r ) ;
} ;

prog-tok-pars : ( r : LIST-ID ) -> ( p : LIST-ID ) = {
        a = prog-tok-param ( r ) ;
        {
                comma ; q = prog-tok-pars ( r ) ;
            ||  comma ; <error_comma> ; q = <list_id_null> ;
            ||  q = <list_id_null> ;
        } ;
        p = <list_id_cons> ( a, q ) ;
} ;

simple-tok-param : () -> ( id : IDENTIFIER ) = {
        tok = token-introduction ;
        t = tag-opt ;
        {
                tid = any-identifier ;
            ||  tid = <id_anon> ;
        } ;
        id = <token_param> ( tok, t, tid ) ;
} ;

simple-tok-pars : () -> ( p : LIST-ID ) = {
        id = simple-tok-param ;
        {
                comma ; q = simple-tok-pars ;
            ||  comma ; <error_comma> ; q = <list_id_null> ;
            ||  q = <list_id_null> ;
        } ;
        p = <list_id_cons> ( id, q ) ;
} ;


/*
    TOKEN SYNTAX

    These rules describe the '#pragma token' syntax.
*/

<rescan_id> : () -> () ;
<rescan_keyword> : () -> () ;
<rescan_tag_line> : () -> () ;
<token_nat> : () -> ( :TOKEN ) ;
<token_snat> : () -> ( :TOKEN ) ;
<token_stmt> : () -> ( :TOKEN ) ;
<token_type> : () -> ( :TOKEN ) ;
<token_variety> : () -> ( :TOKEN ) ;
<token_signed> : () -> ( :TOKEN ) ;
<token_unsigned> : () -> ( :TOKEN ) ;
<token_float> : () -> ( :TOKEN ) ;
<token_arith> : () -> ( :TOKEN ) ;
<token_class> : () -> ( :TOKEN ) ;
<token_scalar> : () -> ( :TOKEN ) ;
<token_struct> : () -> ( :TOKEN ) ;
<token_union> : () -> ( :TOKEN ) ;
<token_exp> : ( :BOOL, :BOOL, :TYPE ) -> ( :TOKEN ) ;
<token_member> : ( :ACCESS, :TYPE, :TYPE ) -> ( :TOKEN ) ;
<token_func> : ( :TYPE ) -> ( :TOKEN ) ;
<token_proc_begin> : () -> ( :TOKEN ) ;
<token_proc_simple> : ( :TOKEN, :LIST-ID ) -> ( :TOKEN ) ;
<token_proc_complex> : ( :TOKEN, :LIST-ID, :LIST-ID ) -> ( :TOKEN ) ;
<token_proc_end> : ( :TOKEN, :TOKEN ) -> ( :TOKEN ) ;
<token_decl> : ( :TOKEN, :BOOL, :IDENTIFIER, :IDENTIFIER ) -> () ;

<is_operator> : () -> ( :BOOL ) ;
<parse_operator> : () -> ( :IDENTIFIER ) ;

<access_private> : () -> ( :ACCESS ) ;
<access_protected> : () -> ( :ACCESS ) ;
<access_public> : () -> ( :ACCESS ) ;

exp-storage : () -> ( b : BOOL, c : BOOL ) = {
        lvalue ; b = <bool_true> ; c = <bool_false> ;
    ||  rvalue ; b = <bool_false> ; c = <bool_false> ;
    ||  const ; b = <bool_false> ; c = <bool_true> ;
    ||  b = <bool_false> ; c = <bool_false> ;
} ;

access-specifier-opt : () -> ( a : ACCESS ) = {
        private ; a = <access_private> ;
    ||  protected ; a = <access_protected> ;
    ||  public ; a = <access_public> ;
    ||  a = <access_public> ;
} ;

token-introduction : () -> ( tok : TOKEN ) = {
        nat-cap ;
        tok = <token_nat> ;
    ||
        int-cap ;
        tok = <token_snat> ;
    ||
        stmt-cap ;
        tok = <token_stmt> ;
    ||
        type-cap ;
        tok = <token_type> ;
    ||
        variety-cap ;
        tok = <token_variety> ;
    ||
        variety-cap ; signed ;
        tok = <token_signed> ;
    ||
        variety-cap ; unsigned ;
        tok = <token_unsigned> ;
    ||
        float-cap ;
        tok = <token_float> ;
    ||
        arith-cap ;
        tok = <token_arith> ;
    ||
        class-cap ;
        tok = <token_class> ;
    ||
        scalar-cap ;
        tok = <token_scalar> ;
    ||
        struct-cap ;
        tok = <token_struct> ;
    ||
        union-cap ;
        tok = <token_union> ;
    ||
        exp-cap ; ( b, c ) = exp-storage ; colon ;
        t = <parse_type> ; colon ;
        tok = <token_exp> ( b, c, t ) ;
    ||
        member-cap ; a = access-specifier-opt ;
        t = <parse_mem_type> ; colon ; s = <parse_type> ; colon ;
        tok = <token_member> ( a, t, s ) ;
    ||
        func-cap ; t = <parse_func_type> ; colon ;
        tok = <token_func> ( t ) ;
    ||
        proc-cap ; open-brace ;
        a = <token_proc_begin> ;
        {
                p0 = bound-tok-pars ;
            ||  p0 = <list_id_null> ;
        } ;
        p = p0 ;
        or ;
        {
                q0 = prog-tok-pars ( p ) ;
            ||  q0 = <list_id_null> ;
        } ;
        q = q0 ;
        close-brace ;
        b = <token_proc_complex> ( a, p, q ) ;
        r = token-introduction ;
        tok = <token_proc_end> ( b, r ) ;
    ||
        proc-cap ; open-round ;
        a = <token_proc_begin> ;
        {
                p = simple-tok-pars ;
            ||  p = <list_id_null> ;
        } ;
        close-round ;
        b = <token_proc_simple> ( a, p ) ;
        r = token-introduction ;
        tok = <token_proc_end> ( b, r ) ;
} ;

token-rule : () -> () = {
        token ; tok = token-introduction ;
        <rescan_tag_line> ;
        {
                t = tag-opt ; <rescan_id> ; a = any-identifier ;
            ||
                ? = <is_operator> ;
                a = <parse_operator> ; t = <bool_false> ;
        } ;
        hash ; <rescan_id> ;
        {
                b = any-identifier ;
            ||  minus ; b = <id_anon> ;
            ||  b = a ;
        } ;
        <token_decl> ( tok, t, a, b ) ;
} ;


/*
    TOKEN INTERFACE LISTS

    These rules are concerned with the '#pragma interface' statements.
*/

<token_name> : ( :IDENTIFIER ) -> ( :IDENTIFIER ) ;
<token_tag> : ( :IDENTIFIER ) -> ( :IDENTIFIER ) ;
<token_selector> : ( :IDENTIFIER, :IDENTIFIER ) -> ( :IDENTIFIER ) ;
<token_extern> : ( :IDENTIFIER ) -> ( :IDENTIFIER ) ;
<token_interface> : ( :IDENTIFIER, :LEX ) -> () ;
<interface_define> : () -> ( :LEX ) ;
<interface_no_def> : () -> ( :LEX ) ;
<interface_ignore> : () -> ( :LEX ) ;
<interface_crt> : () -> ( :LEX ) ;
<interface_undef> : () -> ( :LEX ) ;

token-id : () -> ( id : IDENTIFIER ) = {
        nm = any-identifier ;
        id = <token_name> ( nm ) ;
    ||
        tag-cap ; <rescan_id> ; nm = any-identifier ;
        id = <token_tag> ( nm ) ;
    ||
        ? = <is_operator> ;
        nm = <parse_operator> ;
        id = <token_name> ( nm ) ;
    ||
        nm = token-id ; dot ; <rescan_id> ; mem = any-identifier ;
        id = <token_selector> ( nm, mem ) ;
    ||
        hash ; <rescan_id> ; nm = any-identifier ;
        id = <token_extern> ( nm ) ;
} ;

token-id-list : ( i : LEX ) -> () = {
        id = token-id ;
        <token_interface> ( id, i ) ;
        <rescan_tag_line> ;
        {
                token-id-list ( i ) ;
            ||  $ ;
        } ;
} ;

interface-command : () -> ( i : LEX ) = {
        define ; i = <interface_define> ;
    ||  no-def ; i = <interface_no_def> ;
    ||  reject ; i = <interface_ignore> ;
    ||  interface ; i = <interface_crt> ;
    ||  undef ; token ; i = <interface_undef> ;
} ;

interface-rule : () -> () = {
        i = interface-command ;
        <rescan_tag_line> ;
        {
                token-id-list ( i ) ;
            ||  $ ;
        } ;
} ;


/*
    TOKEN DEFINITION PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    concerned with token definitions.
*/

<tokdef_start> : () -> () ;
<tokdef_end> : () -> () ;
<token_member_def> : ( :TYPE, :IDENTIFIER ) -> () ;

tokdef-rule : () -> () = {
        <tokdef_start> ;
        member ; definition ;
        t = <parse_type> ; colon ; id = any-identifier ;
        <tokdef_end> ;
        <token_member_def> ( t, id ) ;
} ;


/*
    IDENTIFIER PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    concerned with special identifiers.
*/

<rescan_line> : () -> () ;
<rescan_allow_line> : () -> () ;
<rescan_as_line> : () -> () ;
<id_conv> : ( :IDENTIFIER ) -> () ;
<id_init> : ( :IDENTIFIER ) -> () ;
<id_postpone> : ( :IDENTIFIER, :LEX ) -> () ;
<id_preserve> : ( :IDENTIFIER ) -> () ;
<id_preserve_all> : () -> () ;
<id_susp> : ( :IDENTIFIER ) -> () ;
<lex_postpone> : () -> ( :LEX ) ;
<lex_unpostpone> : () -> ( :LEX ) ;

conversion-list : () -> () = {
        id = any-identifier ;
        <id_conv> ( id ) ;
        conversion-list ;
    ||
        $ ;
} ;

postpone-list : ( a : LEX ) -> () = {
        id = any-identifier ;
        <id_postpone> ( id, a ) ;
        postpone-list ( a ) ;
    ||
        $ ;
} ;

preserve-list : () -> () = {
        id = any-identifier ;
        <id_preserve> ( id ) ;
        preserve-list ;
    ||
        $ ;
} ;

suspend-list : () -> () = {
        id = any-identifier ;
        <id_susp> ( id ) ;
        suspend-list ;
    ||
        $ ;
} ;

identifier-rule : () -> () = {
        accept ; conversion ; <rescan_line> ; conversion-list ;
    ||
        conversion ; <rescan_allow_line> ; conversion-list ; allow ;
    ||
        initialization ; <rescan_id> ; id = any-identifier ; allow ;
        <id_init> ( id ) ;
    ||
        postpone ; <rescan_line> ;
        a = <lex_postpone> ; postpone-list ( a ) ;
    ||
        preserve ; <rescan_line> ; preserve-list ;
    ||
        preserve ; star ;
        <id_preserve_all> ;
    ||
        suspend ; static ; <rescan_line> ; suspend-list ;
    ||
        unpostpone ; <rescan_line> ;
        a = <lex_unpostpone> ; postpone-list ( a ) ;
} ;


/*
    ERROR STATES

    These give the various error states which may be associated with an
    option.
*/

<error_on> : () -> ( :STATE ) ;
<error_off> : () -> ( :STATE ) ;
<error_warning> : () -> ( :STATE ) ;
<opt_on> : () -> ( :NUMBER ) ;
<opt_off> : () -> ( :NUMBER ) ;
<opt_warning> : () -> ( :NUMBER ) ;

error-state : () -> ( e : STATE ) = {
        on ; e = <error_on> ;
    ||  off ; e = <error_off> ;
    ||  warning ; e = <error_warning> ;
} ;

allow-state : () -> ( e : STATE ) = {
        allow ; e = <error_off> ;
    ||  disallow ; e = <error_on> ;
    ||  warning ; e = <error_warning> ;
} ;

option-state : () -> ( e : STATE ) = {
        on ; e = <error_on> ;
    ||  off ; e = <error_off> ;
    ||  allow ; e = <error_off> ;
    ||  disallow ; e = <error_on> ;
    ||  warning ; e = <error_warning> ;
} ;

warning-opt : () -> ( e : STATE ) = {
        warning ; e = <error_warning> ;
    ||  e = <error_on> ;
} ;

error-severity : () -> ( e : NUMBER ) = {
        on ; e = <opt_on> ;
    ||  off ; e = <opt_off> ;
    ||  allow ; e = <opt_off> ;
    ||  disallow ; e = <opt_on> ;
    ||  warning ; e = <opt_warning> ;
} ;


/*
    INTEGER LITERAL PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to specify integer literal types.
*/

<base_octal> : () -> ( :NUMBER ) ;
<base_decimal> : () -> ( :NUMBER ) ;
<base_hexadecimal> : () -> ( :NUMBER ) ;
<suffix_none> : () -> ( :NUMBER ) ;
<suffix_u> : () -> ( :NUMBER ) ;
<suffix_l> : () -> ( :NUMBER ) ;
<suffix_ul> : () -> ( :NUMBER ) ;
<suffix_ll> : () -> ( :NUMBER ) ;
<suffix_ull> : () -> ( :NUMBER ) ;
<literal_set> : () -> () ;
<literal_begin> : ( :NUMBER, :NUMBER ) -> () ;
<literal_type> : ( :TYPE ) -> () ;
<literal_token> : ( :IDENTIFIER, :STATE ) -> () ;
<literal_star> : ( :STATE ) -> () ;
<literal_infinity> : () -> () ;
<literal_integer> : ( :EXP ) -> () ;
<literal_range> : () -> () ;

literal-base : () -> ( b : NUMBER ) = {
        octal ; b = <base_octal> ;
    ||  decimal ; b = <base_decimal> ;
    ||  hexadecimal ; b = <base_hexadecimal> ;
} ;

literal-suffix : () -> ( s : NUMBER ) = {
        s = <suffix_none> ;
    ||  unsigned ; s = <suffix_u> ;
    ||  long ; s = <suffix_l> ;
    ||  unsigned ; long ; s = <suffix_ul> ;
    ||  long ; long ; s = <suffix_ll> ;
    ||  unsigned ; long ; long ; s = <suffix_ull> ;
} ;

literal-item : () -> () = {
        colon ; t = <parse_type> ;
        <literal_type> ( t ) ;
    ||
        star ; <rescan_keyword> ;
        {
                a = allow-state ;
            ||  a = <error_off> ;
        } ;
        colon ; <rescan_id> ; id = any-identifier ;
        <literal_token> ( id, a ) ;
    ||
        star ; star ; <rescan_keyword> ;
        {
                a = allow-state ;
            ||  a = <error_on> ;
        } ;
        colon ;
        <literal_star> ( a ) ;
} ;

literal-item-list : () -> () = {
        e = integer-literal ; <literal_integer> ( e ) ;
        literal-item ; or ; literal-item-list ;
    ||
        question ; <literal_range> ;
        literal-item ; or ; literal-item-list ;
    ||
        star ; <literal_infinity> ;
        literal-item ;
} ;

literal-rule : () -> () = {
        integer ; lit ;
        <literal_set> ;
        b = literal-base ; s = literal-suffix ;
        <literal_begin> ( b, s ) ;
        <rescan_line> ;
        literal-item-list ;
} ;


/*
    KEYWORD PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to introduce new keywords.
*/

<lex_asm> : () -> ( :LEX ) ;
<lex_discard> : () -> ( :LEX ) ;
<lex_exhaustive> : () -> ( :LEX ) ;
<lex_fall> : () -> ( :LEX ) ;
<lex_inline> : () -> ( :LEX ) ;
<lex_reachable> : () -> ( :LEX ) ;
<lex_representation> : () -> ( :LEX ) ;
<lex_set> : () -> ( :LEX ) ;
<lex_unreachable> : () -> ( :LEX ) ;
<lex_unused> : () -> ( :LEX ) ;
<lex_weak> : () -> ( :LEX ) ;
<lex_symbol> : () -> ( :LEX ) ;
<keyword_spec> : ( :IDENTIFIER ) -> ( :LEX ) ;
<keyword_define> : ( :IDENTIFIER, :LEX ) -> () ;
<keyword_undef> : ( :IDENTIFIER ) -> () ;

keyword-id : () -> ( id : IDENTIFIER ) = {
        keyword ; <rescan_id> ; id = any-identifier ;
} ;

keyword-spec : () -> ( t : LEX ) = {
        asm ; t = <lex_asm> ;
    ||  discard ; value ; t = <lex_discard> ;
    ||  discard ; variable ; t = <lex_unused> ;
    ||  exhaustive ; t = <lex_exhaustive> ;
    ||  fall ; into ; case ; t = <lex_fall> ;
    ||  inline ; t = <lex_inline> ;
    ||  set ; t = <lex_set> ;
    ||  set ; reachable ; t = <lex_reachable> ;
    ||  set ; unreachable ; t = <lex_unreachable> ;
    ||  type ; representation ; t = <lex_representation> ;
    ||  weak ; t = <lex_weak> ;
    ||  id = keyword-id ; t = <keyword_spec> ( id ) ;
    ||  operator ; t = <lex_symbol> ; plus ;
} ;

keyword-rule : () -> () = {
        id = keyword-id ; for ; t = keyword-spec ;
        <keyword_define> ( id, t ) ;
    ||
        undef ; id = keyword-id ;
        <keyword_undef> ( id ) ;
} ;


/*
    TYPE PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to introduce special types.
*/

<type_argument> : ( :TYPE, :TYPE ) -> () ;
<type_ellipsis> : ( :TYPE ) -> () ;
<type_char_sign> : ( :BTYPE ) -> () ;
<type_char_lit> : ( :TYPE ) -> () ;
<type_long_long> : ( :BOOL ) -> () ;
<type_string_lit> : ( :CV ) -> () ;
<type_compatible> : ( :TYPE, :TYPE, :STATE ) -> () ;
<type_compute> : ( :IDENTIFIER ) -> () ;
<type_promote> : ( :TYPE, :TYPE ) -> () ;
<type_builtin> : ( :BTYPE, :TYPE ) -> () ;
<type_special> : ( :IDENTIFIER, :TYPE ) -> () ;
<type_bottom> : () -> ( :TYPE ) ;
<type_printf> : () -> ( :TYPE ) ;
<type_scanf> : () -> ( :TYPE ) ;
<type_wprintf> : () -> ( :TYPE ) ;
<type_wscanf> : () -> ( :TYPE ) ;
<type_ptrdiff_t> : () -> ( :TYPE ) ;
<type_size_t> : () -> ( :TYPE ) ;
<type_wchar_t> : () -> ( :TYPE ) ;
<nspace_std> : ( :IDENTIFIER ) -> () ;

<id_none> : () -> ( :IDENTIFIER ) ;
<declarator_start> : () -> () ;

<btype_none> : () -> ( :BTYPE ) ;
<btype_signed> : () -> ( :BTYPE ) ;
<btype_unsigned> : () -> ( :BTYPE ) ;
<btype_ptrdiff_t> : () -> ( :BTYPE ) ;
<btype_size_t> : () -> ( :BTYPE ) ;
<btype_wchar_t> : () -> ( :BTYPE ) ;

<cv_none> : () -> ( :CV ) ;
<cv_const> : () -> ( :CV ) ;

type-spec : () -> () = {
        argument ; <rescan_as_line> ;
        t = <parse_type> ; as ; s = <parse_type> ;
        <type_argument> ( t, s ) ;
    ||
        argument ; <rescan_as_line> ;
        t = <parse_type> ; as ; ellipsis-aux ;
        <type_ellipsis> ( t ) ;
    ||
        bottom ; <rescan_id> ;
        <declarator_start> ;
        id = any-identifier ;
        t = <type_bottom> ;
        <type_special> ( id, t ) ;
    ||
        character ;
        {
                signed ; bt = <btype_signed> ;
            ||  unsigned ; bt = <btype_unsigned> ;
            ||  either ; bt = <btype_none> ;
        } ;
        <type_char_sign> ( bt ) ;
    ||
        compatible ; type ; colon ; <rescan_line> ;
        t = <parse_type> ; eq ; s = <parse_type> ; colon ;
        <rescan_keyword> ; e = allow-state ;
        <type_compatible> ( t, s, e ) ;
    ||
        compute ; promote ; <rescan_id> ;
        id = any-identifier ;
        <type_compute> ( id ) ;
    ||
        promoted ; <rescan_line> ;
        t = <parse_type> ; colon ; s = <parse_type> ;
        <type_promote> ( t, s ) ;
    ||
        set ;
        {
                ptrdiff-t ; bt = <btype_ptrdiff_t> ;
            ||  size-t ; bt = <btype_size_t> ;
            ||  wchar-t ; bt = <btype_wchar_t> ;
        } ;
        colon ; <rescan_line> ; t = <parse_type> ;
        <type_builtin> ( bt, t ) ;
    ||
        set ; character ; lit ;
        colon ; <rescan_line> ; t = <parse_type> ;
        <type_char_lit> ( t ) ;
    ||
        set ; longlong ; type ; colon ; long ;
        {
                long ; b = <bool_true> ;
            ||  b = <bool_false> ;
        } ;
        <type_long_long> ( b ) ;
    ||
        set ; string ; lit ; colon ;
        {
                cv = <cv_const> ;
            ||  no ; cv = <cv_none> ;
        } ;
        const ;
        <type_string_lit> ( cv ) ;
    ||
        set ; std ; namespace ; colon ; <rescan_id> ;
        {
                id = any-identifier ;
            ||  colon-colon ; id = <id_none> ;
        } ;
        <nspace_std> ( id ) ;
    ||
        type ; <rescan_id> ;
        <declarator_start> ;
        id = any-identifier ; for ;
        {
                bottom ; t = <type_bottom> ;
            ||  ellipsis-aux ; printf ; t = <type_printf> ;
            ||  ellipsis-aux ; scanf ; t = <type_scanf> ;
            ||  ellipsis-aux ; wchar-t ; printf ; t = <type_wprintf> ;
            ||  ellipsis-aux ; wchar-t ; scanf ; t = <type_wscanf> ;
            ||  ptrdiff-t ; t = <type_ptrdiff_t> ;
            ||  size-t ; t = <type_size_t> ;
            ||  wchar-t ; t = <type_wchar_t> ;
        } ;
        <type_special> ( id, t ) ;
} ;


/*
    OPTION DECLARATIONS

    Each option is associated with a numerical value.  These actions
    gives this mapping.
*/

<opt_bitf_overflow> : () -> ( :NUMBER ) ;
<opt_bitf_type> : () -> ( :NUMBER ) ;
<opt_bool_assign> : () -> ( :NUMBER ) ;
<opt_case_fall> : () -> ( :NUMBER ) ;
<opt_cast_explicit> : () -> ( :NUMBER ) ;
<opt_comma_extra> : () -> ( :NUMBER ) ;
<opt_complete_struct> : () -> ( :NUMBER ) ;
<opt_concat_string> : () -> ( :NUMBER ) ;
<opt_cond_lvalue> : () -> ( :NUMBER ) ;
<opt_const_cond> : () -> ( :NUMBER ) ;
<opt_const_internal> : () -> ( :NUMBER ) ;
<opt_const_string> : () -> ( :NUMBER ) ;
<opt_conv> : () -> ( :NUMBER ) ;
<opt_conv_int_enum> : () -> ( :NUMBER ) ;
<opt_conv_int_int> : () -> ( :NUMBER ) ;
<opt_conv_int_int_expl> : () -> ( :NUMBER ) ;
<opt_conv_int_int_impl> : () -> ( :NUMBER ) ;
<opt_conv_int_ptr> : () -> ( :NUMBER ) ;
<opt_conv_int_ptr_expl> : () -> ( :NUMBER ) ;
<opt_conv_int_ptr_impl> : () -> ( :NUMBER ) ;
<opt_conv_ptr_func> : () -> ( :NUMBER ) ;
<opt_conv_ptr_ptr> : () -> ( :NUMBER ) ;
<opt_conv_ptr_ptr_expl> : () -> ( :NUMBER ) ;
<opt_conv_ptr_ptr_impl> : () -> ( :NUMBER ) ;
<opt_conv_ptr_ptr_void> : () -> ( :NUMBER ) ;
<opt_conv_ptr_void_ptr> : () -> ( :NUMBER ) ;
<opt_decl_cond> : () -> ( :NUMBER ) ;
<opt_decl_hide> : () -> ( :NUMBER ) ;
<opt_decl_none> : () -> ( :NUMBER ) ;
<opt_decl_struct_anon> : () -> ( :NUMBER ) ;
<opt_decl_unify> : () -> ( :NUMBER ) ;
<opt_decl_volatile> : () -> ( :NUMBER ) ;
<opt_discard> : () -> ( :NUMBER ) ;
<opt_discard_func> : () -> ( :NUMBER ) ;
<opt_discard_static> : () -> ( :NUMBER ) ;
<opt_discard_value> : () -> ( :NUMBER ) ;
<opt_dollar_ident> : () -> ( :NUMBER ) ;
<opt_dspec_none> : () -> ( :NUMBER ) ;
<opt_dspec_none_func> : () -> ( :NUMBER ) ;
<opt_ellipsis_extra> : () -> ( :NUMBER ) ;
<opt_ellipsis_ident> : () -> ( :NUMBER ) ;
<opt_empty_body> : () -> ( :NUMBER ) ;
<opt_enum_decl> : () -> ( :NUMBER ) ;
<opt_enum_switch> : () -> ( :NUMBER ) ;
<opt_eof_nline> : () -> ( :NUMBER ) ;
<opt_escape_overflow> : () -> ( :NUMBER ) ;
<opt_escape_unknown> : () -> ( :NUMBER ) ;
<opt_for_scope> : () -> ( :NUMBER ) ;
<opt_func_block> : () -> ( :NUMBER ) ;
<opt_func_impl> : () -> ( :NUMBER ) ;
<opt_func_incompat> : () -> ( :NUMBER ) ;
<opt_func_linkage> : () -> ( :NUMBER ) ;
<opt_func_proto> : () -> ( :NUMBER ) ;
<opt_func_ret_void> : () -> ( :NUMBER ) ;
<opt_func_token_undef> : () -> ( :NUMBER ) ;
<opt_func_weak> : () -> ( :NUMBER ) ;
<opt_hash_ident> : () -> ( :NUMBER ) ;
<opt_include_full> : () -> ( :NUMBER ) ;
<opt_infer_int> : () -> ( :NUMBER ) ;
<opt_infer_int_cv> : () -> ( :NUMBER ) ;
<opt_init_aggregate> : () -> ( :NUMBER ) ;
<opt_init_dynamic> : () -> ( :NUMBER ) ;
<opt_init_struct> : () -> ( :NUMBER ) ;
<opt_inline_internal> : () -> ( :NUMBER ) ;
<opt_interf_incompat> : () -> ( :NUMBER ) ;
<opt_int_operator> : () -> ( :NUMBER ) ;
<opt_int_overflow> : () -> ( :NUMBER ) ;
<opt_link_incompat> : () -> ( :NUMBER ) ;
<opt_link_internal> : () -> ( :NUMBER ) ;
<opt_link_resolve> : () -> ( :NUMBER ) ;
<opt_longlong> : () -> ( :NUMBER ) ;
<opt_macro_arg_dir> : () -> ( :NUMBER ) ;
<opt_macro_redef> : () -> ( :NUMBER ) ;
<opt_macro_weak> : () -> ( :NUMBER ) ;
<opt_member_incompat> : () -> ( :NUMBER ) ;
<opt_name_limit> : () -> ( :NUMBER ) ;
<opt_nest_comment> : () -> ( :NUMBER ) ;
<opt_overload_ambig> : () -> ( :NUMBER ) ;
<opt_overload_dep> : () -> ( :NUMBER ) ;
<opt_overload_res> : () -> ( :NUMBER ) ;
<opt_overload_strict> : () -> ( :NUMBER ) ;
<opt_param_impl> : () -> ( :NUMBER ) ;
<opt_paren> : () -> ( :NUMBER ) ;
<opt_ppdir_assert> : () -> ( :NUMBER, :NUMBER ) ;
<opt_ppdir_file> : () -> ( :NUMBER, :NUMBER ) ;
<opt_ppdir_id> : () -> ( :NUMBER ) ;
<opt_ppdir_ident> : () -> ( :NUMBER, :NUMBER ) ;
<opt_ppdir_import> : () -> ( :NUMBER, :NUMBER ) ;
<opt_ppdir_indent> : () -> ( :NUMBER ) ;
<opt_ppdir_indent_dir> : () -> ( :NUMBER ) ;
<opt_ppdir_text> : () -> ( :NUMBER ) ;
<opt_ppdir_unassert> : () -> ( :NUMBER, :NUMBER ) ;
<opt_ppdir_unknown> : () -> ( :NUMBER ) ;
<opt_ppdir_warning> : () -> ( :NUMBER, :NUMBER ) ;
<opt_ppdir_weak> : () -> ( :NUMBER, :NUMBER ) ;
<opt_pragma_unknown> : () -> ( :NUMBER ) ;
<opt_ptr_operator> : () -> ( :NUMBER ) ;
<opt_reached> : () -> ( :NUMBER ) ;
<opt_semicolon_extra> : () -> ( :NUMBER ) ;
<opt_templ_export> : () -> ( :NUMBER ) ;
<opt_this_lvalue> : () -> ( :NUMBER ) ;
<opt_throw_bad> : () -> ( :NUMBER ) ;
<opt_token_const> : () -> ( :NUMBER ) ;
<opt_token_redef> : () -> ( :NUMBER ) ;
<opt_token_undef> : () -> ( :NUMBER ) ;
<opt_type_obj_incompl> : () -> ( :NUMBER ) ;
<opt_type_qual_incompat> : () -> ( :NUMBER ) ;
<opt_type_redef> : () -> ( :NUMBER ) ;
<opt_type_tag_ignore> : () -> ( :NUMBER ) ;
<opt_unmatched> : () -> ( :NUMBER ) ;
<opt_variable> : () -> ( :NUMBER ) ;
<opt_wall> : () -> ( :NUMBER ) ;
<opt_weak> : () -> ( :NUMBER ) ;

<opt_val_cast_explicit> : () -> ( :NUMBER ) ;
<opt_val_include_depth> : () -> ( :NUMBER ) ;
<opt_val_maximum_error> : () -> ( :NUMBER ) ;
<opt_val_name_limit> : () -> ( :NUMBER ) ;


/*
    ANALYSIS PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to set analysis options.
*/

conversion-spec : () -> ( n : NUMBER ) = {
        n = <opt_conv> ;
    ||
        open-round ; int ; minus ; int ; close-round ;
        n = <opt_conv_int_int> ;
    ||
        open-round ; int ; minus ; int ; explicit ; close-round ;
        n = <opt_conv_int_int_expl> ;
    ||
        open-round ; int ; minus ; int ; implicit ; close-round ;
        n = <opt_conv_int_int_impl> ;
    ||
        open-round ; int ; minus ; enum ; implicit ; close-round ;
        n = <opt_conv_int_enum> ;
    ||
        open-round ; int ; minus ; pointer ; close-round ;
        n = <opt_conv_int_ptr> ;
    ||
        open-round ; int ; minus ; pointer ; explicit ; close-round ;
        n = <opt_conv_int_ptr_expl> ;
    ||
        open-round ; int ; minus ; pointer ; implicit ; close-round ;
        n = <opt_conv_int_ptr_impl> ;
    ||
        open-round ; pointer ; minus ; int ; close-round ;
        n = <opt_conv_int_ptr> ;
    ||
        open-round ; pointer ; minus ; int ; explicit ; close-round ;
        n = <opt_conv_int_ptr_expl> ;
    ||
        open-round ; pointer ; minus ; int ; implicit ; close-round ;
        n = <opt_conv_int_ptr_impl> ;
    ||
        open-round ; pointer ; minus ; pointer ; close-round ;
        n = <opt_conv_ptr_ptr> ;
    ||
        open-round ; pointer ; minus ; pointer ; explicit ; close-round ;
        n = <opt_conv_ptr_ptr_expl> ;
    ||
        open-round ; pointer ; minus ; pointer ; implicit ; close-round ;
        n = <opt_conv_ptr_ptr_impl> ;
    ||
        open-round ; void ; star ; minus ; pointer ; implicit ; close-round ;
        n = <opt_conv_ptr_void_ptr> ;
    ||
        open-round ; pointer ; minus ; void ; star ; implicit ; close-round ;
        n = <opt_conv_ptr_ptr_void> ;
} ;

discard-spec : () -> ( n : NUMBER ) = {
        n = <opt_discard> ;
    ||
        open-round ; function ; return ; close-round ;
        n = <opt_discard_func> ;
    ||
        open-round ; static ; close-round ;
        n = <opt_discard_static> ;
    ||
        open-round ; value ; close-round ;
        n = <opt_discard_value> ;
} ;

analysis-spec : () -> ( n : NUMBER ) = {
        complete ; initialization ; analysis ;
        n = <opt_init_aggregate> ;
    ||
        complete ; struct ; div ; union ; analysis ;
        n = <opt_complete_struct> ;
    ||
        conversion ; analysis ;
        n = conversion-spec ;
    ||
        discard ; analysis ;
        n = discard-spec ;
    ||
        enum ; switch ; analysis ;
        n = <opt_enum_switch> ;
    ||
        external ; function ; linkage ;
        n = <opt_func_linkage> ;
    ||
        for ; initialization ; block ;
        n = <opt_for_scope> ;
    ||
        ignore ; struct ; div ; union ; div ; enum ; tag ;
        n = <opt_type_tag_ignore> ;
    ||
        implicit ; export ; template ;
        n = <opt_templ_export> ;
    ||
        implicit ; function ; decl ;
        n = <opt_func_impl> ;
    ||
        integer ; operator ; analysis ;
        n = <opt_int_operator> ;
    ||
        integer ; overflow ; analysis ;
        n = <opt_int_overflow> ;
    ||
        nested ; comment ; analysis ;
        n = <opt_nest_comment> ;
    ||
        operator ; precedence ; analysis ;
        n = <opt_paren> ;
    ||
        pointer ; operator ; analysis ;
        n = <opt_ptr_operator> ;
    ||
        throw ; analysis ;
        n = <opt_throw_bad> ;
    ||
        unify ; external ; linkage ;
        n = <opt_decl_unify> ;
    ||
        variable ; analysis ;
        n = <opt_variable> ;
    ||
        variable ; hiding ; analysis ;
        n = <opt_decl_hide> ;
    ||
        weak ; prototype ; analysis ;
        n = <opt_weak> ;
} ;


/*
    IMPLICIT INT PRAGMAS

    This rule is concerned with those '#pragma' statements which are
    used to set the treatment of implicit integral types.
*/

implicit-spec : () -> ( n : NUMBER ) = {
        for ; external ; decl ;
        n = <opt_dspec_none> ;
    ||
        for ; function ; argument ;
        n = <opt_param_impl> ;
    ||
        for ; function ; return ;
        n = <opt_dspec_none_func> ;
    ||
        for ; const ; div ; volatile ;
        n = <opt_infer_int_cv> ;
    ||
        n = <opt_infer_int> ;
} ;


/*
    CHECKING PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to set checking options.
*/

check-spec : () -> ( n : NUMBER ) = {
        ambiguous ; overload ; resolution ;
        n = <opt_overload_ambig> ;
    ||
        assignment ; as ; bool ;
        n = <opt_bool_assign> ;
    ||
        bitfield ; overflow ;
        n = <opt_bitf_overflow> ;
    ||
        block ; function ; static ;
        n = <opt_func_block> ;
    ||
        catch ; all ;
        n = <opt_wall> ;
    ||
        character ; escape ; overflow ;
        n = <opt_escape_overflow> ;
    ||
        compatible ; token ;
        n = <opt_token_redef> ;
    ||
        complete ; file ; includes ;
        n = <opt_include_full> ;
    ||
        conditional ; decl ;
        n = <opt_decl_cond> ;
    ||
        conditional ; lvalue ;
        n = <opt_cond_lvalue> ;
    ||
        const ; conditional ;
        n = <opt_const_cond> ;
    ||
        directive ; as ; macro ; argument ;
        n = <opt_macro_arg_dir> ;
    ||
        dollar ; as ; ident ;
        n = <opt_dollar_ident> ;
    ||
        extra ; comma ;
        n = <opt_comma_extra> ;
    ||
        extra ; ellipsis-aux ;
        n = <opt_ellipsis_extra> ;
    ||
        extra ; semicolon ;
        n = <opt_semicolon_extra> ;
    ||
        extra ; semicolon ; after ; conditional ;
        n = <opt_empty_body> ;
    ||
        extra ; bitfield ; int ; type ;
        n = <opt_bitf_type> ;
    ||
        extra ; macro ; definition ;
        n = <opt_macro_redef> ;
    ||
        extra ; type ; definition ;
        n = <opt_type_redef> ;
    ||
        fall ; into ; case ;
        n = <opt_case_fall> ;
    ||
        forward ; enum ; decl ;
        n = <opt_enum_decl> ;
    ||
        function ; pointer ; as ; pointer ;
        n = <opt_conv_ptr_func> ;
    ||
        ident ; ellipsis-aux ;
        n = <opt_ellipsis_ident> ;
    ||
        ident ; as ; ellipsis-aux ;
        n = <opt_ellipsis_ident> ;
    ||
        implicit ; int ; type ;
        n = implicit-spec ;
    ||
        implicit ; token ; definition ;
        n = <opt_func_token_undef> ;
    ||
        incompatible ; interface ; decl ;
        n = <opt_interf_incompat> ;
    ||
        incompatible ; linkage ;
        n = <opt_link_incompat> ;
    ||
        incompatible ; member ; decl ;
        n = <opt_member_incompat> ;
    ||
        incompatible ; promoted ; function ; argument ;
        n = <opt_func_incompat> ;
    ||
        incompatible ; type ; qualifier ;
        n = <opt_type_qual_incompat> ;
    ||
        incompatible ; void ; return ;
        n = <opt_func_ret_void> ;
    ||
        incomplete ; type ; as ; object ; type ;
        n = <opt_type_obj_incompl> ;
    ||
        indented ; hash ; directive ;
        n = <opt_ppdir_indent> ;
    ||
        indented ; directive ; after ; hash ;
        n = <opt_ppdir_indent_dir> ;
    ||
        initialization ; of ; struct ; div ; union ;
        open-round ; auto ; close-round ;
        n = <opt_init_struct> ;
    ||
        longlong ; type ;
        n = <opt_longlong> ;
    ||
        no ; directive ; div ; nline ; after ; ident ;
        n = <opt_ppdir_id> ;
    ||
        no ; external ; decl ;
        n = <opt_decl_none> ;
    ||
        no ; ident ; after ; hash ;
        n = <opt_hash_ident> ;
    ||
        no ; nline ; after ; file ; end ;
        n = <opt_eof_nline> ;
    ||
        no ; token ; definition ;
        n = <opt_token_undef> ;
    ||
        overload ; resolution ;
        n = <opt_overload_res> ;
    ||
        prototype ;
        n = <opt_func_proto> ;
    ||
        prototype ; open-round ; weak ; close-round ;
        n = <opt_func_weak> ;
    ||
        rvalue ; token ; as ; const ;
        n = <opt_token_const> ;
    ||
        text ; after ; directive ;
        n = <opt_ppdir_text> ;
    ||
        this ; lvalue ;
        n = <opt_this_lvalue> ;
    ||
        unify ; incompatible ; string ; lit ;
        n = <opt_concat_string> ;
    ||
        un-known ; directive ;
        n = <opt_ppdir_unknown> ;
    ||
        un-known ; escape ;
        n = <opt_escape_unknown> ;
    ||
        un-known ; pragma ;
        n = <opt_pragma_unknown> ;
    ||
        un-known ; struct ; div ; union ;
        n = <opt_decl_struct_anon> ;
    ||
        unmatched ; quote ;
        n = <opt_unmatched> ;
    ||
        unreachable ; code ;
        n = <opt_reached> ;
    ||
        variable ; initialization ;
        n = <opt_init_dynamic> ;
    ||
        weak ; macro ; equality ;
        n = <opt_macro_weak> ;
    ||
        writeable ; string ; lit ;
        n = <opt_const_string> ;
} ;


/*
    DIRECTIVE PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to switch preprocessing directives on and off.
*/

directive-spec : () -> ( n : NUMBER, m : NUMBER ) = {
        assert ; ( n, m ) = <opt_ppdir_assert> ;
    ||  file ; ( n, m ) = <opt_ppdir_file> ;
    ||  ident ; ( n, m ) = <opt_ppdir_ident> ;
    ||  import ; ( n, m ) = <opt_ppdir_import> ;
    ||  include-next ; ( n, m ) = <opt_ppdir_import> ;
    ||  unassert ; ( n, m ) = <opt_ppdir_unassert> ;
    ||  warning ; ( n, m ) = <opt_ppdir_warning> ;
    ||  weak ; ( n, m ) = <opt_ppdir_weak> ;
} ;

directive-state : () -> ( e : STATE, i : STATE ) = {
        disallow ;
        e = <error_on> ;
        i = <error_on> ;
    ||
        {
                open-round ; ignore ; close-round ; a = <error_on> ;
            ||  a = <error_off> ;
        } ;
        {
                allow ; b = <error_off> ;
            ||  warning ; b = <error_warning> ;
        } ;
        e = b ;
        i = a ;
} ;


/*
    LINKAGE PRAGMAS

    This rule is concerned with the '#pragma' statement used to determine
    the linkage resolution to be used.
*/

linkage-descr : () -> ( i : STATE ) = {
        internal ; i = <error_on> ;
    ||  external ; i = <error_off> ;
} ;

linkage-state : () -> ( e : STATE, i : STATE ) = {
        off ;
        e = <error_off> ;
        i = <error_off> ;
    ||
        open-round ;
        i = linkage-descr ;
        close-round ;
        {
                on ; b = <error_off> ;
            ||  warning ; b = <error_warning> ;
        } ;
        e = b ;
} ;


/*
    COMPLETE STATE PRAGMAS

    This rule is concerned with those '#pragma' statements which give
    the option between complete and incomplete analysis.
*/

complete-state : () -> ( i : STATE ) = {
        i = <error_on> ;
    ||  open-round ; complete ; close-round ; i = <error_on> ;
    ||  open-round ; incomplete ; close-round ; i = <error_off> ;
} ;


/*
    EXPLICIT CAST PRAGMAS

    These rules gives the various interpretations of explicit cast
    expressions.
*/

<cast_static> : () -> ( :VALUE ) ;
<cast_reinterp> : () -> ( :VALUE ) ;
<cast_const> : () -> ( :VALUE ) ;
<cast_explicit> : () -> ( :VALUE ) ;
<cast_join> : ( :VALUE, :VALUE ) -> ( :VALUE ) ;

cast-command : () -> ( c : VALUE ) = {
        static-cast ; c = <cast_static> ;
    ||  reinterpret-cast ; c = <cast_reinterp> ;
    ||  const-cast ; c = <cast_const> ;
} ;

cast-state : () -> ( c : VALUE ) = {
        c = cast-command ;
    ||
        a = cast-command ; or ; b = cast-state ;
        c = <cast_join> ( a, b ) ;
} ;


/*
    OPTION PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to set option values.
*/

<option_number> : ( :EXP ) -> ( :NUMBER ) ;
<linkage_string> : ( :EXP ) -> ( :LINKAGE ) ;
<analysis_exp> : ( :NUMBER, :EXP ) -> () ;
<analysis_state> : ( :NUMBER, :STATE ) -> () ;
<analysis_value> : ( :NUMBER, :VALUE ) -> () ;
<analysis_linkage> : ( :LINKAGE ) -> () ;

option-number : () -> ( n : NUMBER ) = {
        option ; s = string-literal ;
        n = <option_number> ( s ) ;
} ;

option-rule : () -> () = {
        n = option-number ; e = option-state ;
        <analysis_state> ( n, e ) ;
    ||
        n = analysis-spec ; e = error-state ;
        <analysis_state> ( n, e ) ;
    ||
        n = check-spec ; e = allow-state ;
        <analysis_state> ( n, e ) ;
    ||
        conditional ; overload ; resolution ;
        i = complete-state ; e = allow-state ;
        n = <opt_overload_dep> ;
        m = <opt_overload_strict> ;
        <analysis_state> ( n, e ) ;
        <analysis_state> ( m, i ) ;
    ||
        directive ; ( n, m ) = directive-spec ; ( e, i ) = directive-state ;
        <analysis_state> ( n, e ) ;
        <analysis_state> ( m, i ) ;
    ||
        explicit ; cast ;
        {
                as ; c = cast-state ;
            ||  c = <cast_explicit> ;
        } ;
        e = allow-state ;
        n = <opt_cast_explicit> ;
        m = <opt_val_cast_explicit> ;
        <analysis_state> ( n, e ) ;
        <analysis_value> ( m, c ) ;
    ||
        set ; name ; limit ;
        e = integer-literal ;
        i = warning-opt ;
        n = <opt_val_name_limit> ;
        m = <opt_name_limit> ;
        <analysis_exp> ( n, e ) ;
        <analysis_state> ( m, i ) ;
    ||
        linkage ; resolution ; colon ; ( e, i ) = linkage-state ;
        n = <opt_link_resolve> ;
        m = <opt_link_internal> ;
        <analysis_state> ( n, e ) ;
        <analysis_state> ( m, i ) ;
    ||
        external ; linkage ; e = string-literal ;
        a = <linkage_string> ( e ) ;
        <analysis_linkage> ( a ) ;
    ||
        external ;
        {
                volatile ;
            ||  volatile-t ;
        } ;
        n = <opt_decl_volatile> ;
        e = <error_on> ;
        <analysis_state> ( n, e ) ;
    ||
        inline ; linkage ; e = linkage-descr ;
        n = <opt_inline_internal> ;
        <analysis_state> ( n, e ) ;
    ||
        const ; linkage ; e = linkage-descr ;
        n = <opt_const_internal> ;
        <analysis_state> ( n, e ) ;
    ||
        accept ; ellipsis-aux ; identif ;
        n = <opt_ellipsis_ident> ;
        e = <error_off> ;
        <analysis_state> ( n, e ) ;
} ;


/*
    VALUE PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to set compiler values.
*/

<option_value_number> : ( :EXP ) -> ( :NUMBER ) ;

option-value-number : () -> ( n : NUMBER ) = {
        option ; value ; s = string-literal ;
        n = <option_value_number> ( s ) ;
} ;

value-spec : () -> ( n : NUMBER ) = {
        includes ; depth ;
        n = <opt_val_include_depth> ;
    ||
        set ; error ; limit ;
        n = <opt_val_maximum_error> ;
} ;

value-rule : () -> () = {
        n = option-value-number ; e = integer-literal ;
        <analysis_exp> ( n, e ) ;
    ||
        n = value-spec ; e = integer-literal ;
        <analysis_exp> ( n, e ) ;
} ;


/*
    CHARACTER PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to define character set information.
*/

<char_set> : ( :EXP, :EXP ) -> () ;
<escape_set> : ( :EXP, :EXP ) -> () ;
<exp_none> : () -> ( :EXP ) ;

character-rule : () -> () = {
        character ;
        {
                a = character-literal ;
            ||  a = string-literal ;
        } ;
        {
                as ; b = character-literal ;
                <char_set> ( a, b ) ;
                allow ;
            ||
                disallow ; b = <exp_none> ;
                <char_set> ( a, b ) ;
        } ;
    ||
        escape ; a = character-literal ;
        {
                as ; b = character-literal ; allow ;
            ||  disallow ; b = <exp_none> ;
        } ;
        <escape_set> ( a, b ) ;
} ;


/*
    ERROR PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to define error messages.
*/

<error_number> : ( :EXP ) -> ( :NUMBER ) ;
<error_state> : ( :NUMBER, :NUMBER ) -> () ;
<error_use> : ( :NUMBER ) -> () ;

error-number : () -> ( n : NUMBER ) = {
        error ; s = string-literal ;
        n = <error_number> ( s ) ;
} ;

error-rule : () -> () = {
        n = error-number ; e = error-severity ;
        <error_state> ( n, e ) ;
    ||
        n = error-number ; as ; e = option-number ;
        <error_state> ( n, e ) ;
    ||
        use ; n = error-number ;
        <error_use> ( n ) ;
} ;



/*
    SCOPE PRAGMAS

    These rules are concerned with those '#pragma' statements which are
    used to define checking and declaration scopes.
*/

<check_begin> : ( :IDENTIFIER ) -> () ;
<check_end> : () -> () ;
<check_directory> : ( :IDENTIFIER, :IDENTIFIER ) -> () ;
<check_use> : ( :IDENTIFIER, :STATE ) -> () ;
<decl_block_begin> : ( :IDENTIFIER ) -> () ;
<decl_block_end> : () -> () ;

scope-rule : () -> () = {
        begin ; id = <id_none> ;
        <check_begin> ( id ) ;
    ||
        begin ; name ; environment ; <rescan_id> ; id = any-identifier ;
        <check_begin> ( id ) ;
    ||
        directory ; <rescan_id> ; dir = any-identifier ;
        use ; environment ; <rescan_id> ; id = any-identifier ;
        <check_directory> ( dir, id ) ;
    ||
        use ; environment ; <rescan_id> ; id = any-identifier ;
        {
                reset ; e = allow-state ;
            ||  e = <error_on> ;
        } ;
        <check_use> ( id, e ) ;
    ||
        end ;
        <check_end> ;
    ||
        decl ; block ; <rescan_id> ; id = any-identifier ; begin ;
        <decl_block_begin> ( id ) ;
    ||
        decl ; block ; end ;
        <decl_block_end> ;
} ;


/*
    PRAGMA TENDRA DIRECTIVES

    These rules describe the '#pragma TenDRA' directives.
*/

<lex_none> : () -> ( :LEX ) ;
<lex_pragma> : () -> ( :LEX ) ;
<error_syntax> : () -> () ;

pragma-rule : () -> () = {
        scope-rule ;
    ||  error-rule ;
    ||  keyword-rule ;
    ||  option-rule ;
    ||  value-rule ;
    ||  character-rule ;
    ||  semicolon ;
} ;

pragma-tendra-rule : () -> () = {
        token-rule ;
    ||  interface-rule ;
    ||  tokdef-rule ;
    ||  literal-rule ;
    ||  identifier-rule ;
    ||  pragma-rule ;
    ||  type-spec ;
} ;

pragma-tendra : () -> ( t : LEX ) = {
        pragma-tendra-rule ;
        t = <lex_pragma> ;
    ||
        exhaustive ;
        t = <lex_exhaustive> ;
    ||
        discard ;
        t = <lex_unused> ;
    ||
        set ;
        t = <lex_set> ;
    ##
        <error_syntax> ;
        t = <lex_pragma> ;
} ;

pragma-preproc : () -> ( t : LEX ) = {
        pragma-rule ;
        t = <lex_none> ;
    ##
        t = <lex_pragma> ;
} ;


/*
    ENTRY POINTS

    There are two entry points into the grammar, pragma-tendra, which is
    the normal entry point, and pragma-preproc, which is used during
    preprocessing.
*/

%entry% pragma-tendra, pragma-preproc ;