Subversion Repositories tendra.SVN

Rev

Blame | 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 ;