Subversion Repositories tendra.SVN

Rev

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

// -*- c -*-

%prefixes%

%maps%

AltP                    -> AltP;
BoolT                   -> BoolT;
EntryP                  -> EntryP;
ItemP                   -> ItemP;
RuleP                   -> RuleP;
StringT                 -> NStringT;
sid-parse-grammar       -> sid_parse_grammar;

%header% @{
/*
                 Crown Copyright (c) 1997
    
    This TenDRA(r) Computer Program is subject to Copyright
    owned by the United Kingdom Secretary of State for Defence
    acting through the Defence Evaluation and Research Agency
    (DERA).  It is made available to Recipients with a
    royalty-free licence for its use, reproduction, transfer
    to other parties and amendment for any purpose not excluding
    product development provided that any such use et cetera
    shall be deemed to be acceptance of the following conditions:-
    
        (1) Its Recipients shall ensure that this Notice is
        reproduced upon any copies or amended versions of it;
    
        (2) Any amended version of it shall be clearly marked to
        show both the nature of and the organisation responsible
        for the relevant amendment or amendments;
    
        (3) Its onward transfer from a recipient to another
        party shall be deemed to be that party's acceptance of
        these conditions;
    
        (4) DERA gives no warranty or assurance as to its
        quality or suitability for any purpose and DERA accepts
        no liability whatsoever in relation to any use to which
        it may be put.
*/


#include "parser.h"
#include "action.h"
#include "basic.h"
#include "bitvec.h"
#include "dalloc.h"
#include "dstring.h"
#include "gen-errors.h"
#include "grammar.h"
#include "lexer.h"
#include "non-local.h"
#include "rule.h"
#include "scope.h"
#include "table.h"
#include "types.h"

/*--------------------------------------------------------------------------*/

#define CURRENT_TERMINAL lexer_get_terminal (sid_current_stream)
#define ADVANCE_LEXER lexer_next_token (sid_current_stream)
#define SAVE_LEXER(x) (lexer_save_terminal (sid_current_stream, (LexerTokenT) (x)))
#define RESTORE_LEXER (lexer_restore_terminal (sid_current_stream))
#define ALT_LIMIT (UINT_MAX - 1)

/*--------------------------------------------------------------------------*/

LexerStreamP            sid_current_stream;
GrammarP                sid_current_grammar;

/*--------------------------------------------------------------------------*/

static TableP           sid_current_table;
static EntryListP       sid_current_entry_list;
static ScopeStackT      sid_scope_stack;
static ScopeStackT      sid_global_scope;
static ScopeStackP      sid_current_scope;
static EntryP           sid_current_entry;
static RuleP            sid_enclosing_rule;
static union {
    BasicP              basic;
    ActionP             action;
    RuleP               rule;
} sid_current;
static BoolT            sid_redefining_entry;
static NStringT         sid_maximum_scope;
static TypeTupleT       sid_saved_type;
static TypeTupleT       sid_current_type;
static EntryP           sid_saved_pred_id;
static EntryP           sid_current_pred_id;
static EntryP           sid_unique_pred_id = NIL (EntryP);
static EntryP           sid_predicate_type = NIL (EntryP);
static AltP             sid_current_alt;
static ItemP            sid_current_item;
static unsigned         sid_alternative;
static BoolT            sid_internal_rule;
static EntryP           sid_external_rule;
static unsigned         sid_num_alternatives = 0;
static NonLocalEntryP   sid_non_local;
static BoolT            sid_propagating_error = FALSE;
static BoolT            sid_finished_terminals = FALSE;
@}, @{
/*
                 Crown Copyright (c) 1997
    
    This TenDRA(r) Computer Program is subject to Copyright
    owned by the United Kingdom Secretary of State for Defence
    acting through the Defence Evaluation and Research Agency
    (DERA).  It is made available to Recipients with a
    royalty-free licence for its use, reproduction, transfer
    to other parties and amendment for any purpose not excluding
    product development provided that any such use et cetera
    shall be deemed to be acceptance of the following conditions:-
    
        (1) Its Recipients shall ensure that this Notice is
        reproduced upon any copies or amended versions of it;
    
        (2) Any amended version of it shall be clearly marked to
        show both the nature of and the organisation responsible
        for the relevant amendment or amendments;
    
        (3) Its onward transfer from a recipient to another
        party shall be deemed to be that party's acceptance of
        these conditions;
    
        (4) DERA gives no warranty or assurance as to its
        quality or suitability for any purpose and DERA accepts
        no liability whatsoever in relation to any use to which
        it may be put.
*/


@};

%assignments%

StringT: (a) -> (b) = @{
    nstring_assign (&@b, @&a);
@};

%parameter-assignments%

StringT: (a) -> (b) = @{
    nstring_assign (&@b, @a);
@};

%result-assignments%

StringT: (a) -> (b) = @{
    nstring_assign (@b, @&a);
@};

%terminals%

identifier: () -> (i) = @{
    nstring_assign (&@i, lexer_string_value (sid_current_stream));
@};

%actions%

<init> = @{
sid_current_table      = grammar_table (sid_current_grammar);
sid_current_entry_list = grammar_entry_list (sid_current_grammar);
scope_stack_init (&sid_scope_stack);
scope_stack_init (&sid_global_scope);
@};

// Type section actions:

<add-type>: (string) -> () = @{
    if (table_add_type (sid_current_table, &@=string) == NIL (EntryP)) {
        E_duplicate_type (@&string);
        nstring_destroy (&@=string);
    }
@};

// Terminals section actions:

<terminal>: (string) -> () = @{
    sid_current_entry = table_add_basic (sid_current_table, &@=string,
                                         sid_current_grammar, FALSE);
    if (sid_current_entry == NIL (EntryP)) {
        E_duplicate_basic (@&string);
        nstring_destroy (&@=string);
    } else {
        sid_current.basic = entry_get_basic (sid_current_entry);
    }
@};

<i-terminal>: (string) -> () = @{
    sid_current_entry = table_add_basic (sid_current_table, &@=string,
                                         sid_current_grammar, TRUE);
    if (sid_current_entry == NIL (EntryP)) {
        E_duplicate_basic (@&string);
        nstring_destroy (&@=string);
    } else {
        sid_current.basic = entry_get_basic (sid_current_entry);
    }
@};

<x-terminal> = @{
    if (sid_current_entry) {
        KeyP key = entry_key (sid_current_entry);

        if (types_contains_names (&sid_saved_type)) {
            E_basic_param_has_names (key, &sid_saved_type);
        }
        if (types_contains_names (&sid_current_type)) {
            E_basic_result_has_names (key, &sid_current_type);
        }
        if (types_contains_references (&sid_current_type)) {
            E_basic_result_has_refs (key, &sid_current_type);
        }
        if (!types_equal_zero_tuple (&sid_saved_type)) {
            E_basic_param_mismatch (key, &sid_saved_type);
        }
        types_assign (basic_result (sid_current.basic), &sid_current_type);
    } else {
        types_destroy (&sid_current_type);
    }
    types_destroy (&sid_saved_type);
@};

<x-terminals> = @{
    unsigned max_terminal = grammar_max_terminal (sid_current_grammar);

    bitvec_set_size (max_terminal);
    sid_finished_terminals = TRUE;
@};

// Tuple manipulation actions:

<save-tuple> = @{
    types_assign (&sid_saved_type, &sid_current_type);
    sid_saved_pred_id = sid_current_pred_id;
@};

<null-type> = @{
    types_init (&sid_saved_type);
    types_init (&sid_current_type);
    sid_saved_pred_id   = NIL (EntryP);
    sid_current_pred_id = NIL (EntryP);
@};

<init-tuple> = @{
    types_init (&sid_current_type);
    sid_current_pred_id = NIL (EntryP);
@};

<tuple-name>: (name, type) -> () = @{
    if (!types_add_typed_name (&sid_current_type, sid_current_table, &@=name,
                               @&type, FALSE)) {
        E_unknown_type (@&type);
    }
    nstring_destroy (&@=type);
@};

<tuple-ref-name>: (name, type) -> () = @{
    if (!types_add_typed_name (&sid_current_type, sid_current_table, &@=name,
                               @&type, TRUE)) {
        E_unknown_type (@&type);
    }
    nstring_destroy (&@=type);
@};

<tuple-type>: (type) -> () = @{
    if (!types_add_type (&sid_current_type, sid_current_table, @&type,
                         FALSE)) {
        E_unknown_type (@&type);
    }
    nstring_destroy (&@=type);
@};

<tuple-ref-type>: (type) -> () = @{
    if (!types_add_type (&sid_current_type, sid_current_table, @&type, TRUE)) {
        E_unknown_type (@&type);
    }
    nstring_destroy (&@=type);
@};

<add-name>: (name) -> () = @{
    NStringT scope;
    EntryP   non_local_entry = scope_stack_get_non_local (&sid_scope_stack,
                                                          sid_current_table,
                                                          @&name, &scope);
    EntryP   name_entry      = table_get_entry (sid_current_table, @&name);

    if (name_entry) {
        if ((sid_current_entry) && (sid_current_alt)) {
            if ((!types_contains (alt_names (sid_current_alt), name_entry)) &&
                (!types_contains (rule_param (sid_current.rule),
                                  name_entry))) {
                name_entry = NIL (EntryP);
            }
        } else {
            name_entry = NIL (EntryP);
        }
    }
    if (name_entry) {
        types_add_name_and_type (&sid_current_type, name_entry, NIL (EntryP),
                                 FALSE);
        if (non_local_entry) {
            nstring_destroy (&scope);
        }
        nstring_destroy (&@=name);
    } else if (non_local_entry) {
        types_add_name_and_type (&sid_current_type, non_local_entry,
                                 NIL (EntryP), FALSE);
        if (nstring_length (&scope) > nstring_length (&sid_maximum_scope)) {
            nstring_destroy (&sid_maximum_scope);
            nstring_assign (&sid_maximum_scope, &scope);
        } else {
            nstring_destroy (&scope);
        }
        nstring_destroy (&@=name);
    } else {
        types_add_name (&sid_current_type, sid_current_table, &@=name, FALSE);
    }
@};

<add-ref-name>: (name) -> () = @{
    NStringT scope;
    EntryP   non_local_entry = scope_stack_get_non_local (&sid_scope_stack,
                                                          sid_current_table,
                                                          @&name, &scope);
    EntryP   name_entry      = table_get_entry (sid_current_table, @&name);

    if (name_entry) {
        if ((sid_current_entry) && (sid_current_alt)) {
            if ((!types_contains (alt_names (sid_current_alt), name_entry)) &&
                (!types_contains (rule_param (sid_current.rule),
                                  name_entry))) {
                name_entry = NIL (EntryP);
            }
        } else {
            name_entry = NIL (EntryP);
        }
    }
    if (name_entry) {
        types_add_name_and_type (&sid_current_type, name_entry, NIL (EntryP),
                                 TRUE);
        if (non_local_entry) {
            nstring_destroy (&scope);
        }
        nstring_destroy (&@=name);
    } else if (non_local_entry) {
        types_add_name_and_type (&sid_current_type, non_local_entry,
                                 NIL (EntryP), TRUE);
        if (nstring_length (&scope) > nstring_length (&sid_maximum_scope)) {
            nstring_destroy (&sid_maximum_scope);
            nstring_assign (&sid_maximum_scope, &scope);
        } else {
            nstring_destroy (&scope);
        }
        nstring_destroy (&@=name);
    } else {
        types_add_name (&sid_current_type, sid_current_table, &@=name, TRUE);
    }
@};

<add-var>: (name) -> () = @{
    NStringT scope;
    EntryP   non_local_entry = scope_stack_get_non_local (&sid_scope_stack,
                                                          sid_current_table,
                                                          @&name, &scope);
    EntryP   name_entry      = table_get_entry (sid_current_table, @&name);

    if (name_entry) {
        if ((sid_current_entry) && (sid_current_alt)) {
            if ((!types_contains (alt_names (sid_current_alt), name_entry)) &&
                (!types_contains (rule_param (sid_current.rule),
                                  name_entry))) {
                name_entry = NIL (EntryP);
            }
        } else {
            name_entry = NIL (EntryP);
        }
    }
    if (name_entry) {
        types_add_name_and_type_var (&sid_current_type, name_entry,
                                     NIL (EntryP));
        if (non_local_entry) {
            nstring_destroy (&scope);
        }
        nstring_destroy (&@=name);
    } else if (non_local_entry) {
        types_add_name_and_type_var (&sid_current_type, non_local_entry,
                                     NIL (EntryP));
        if (nstring_length (&scope) > nstring_length (&sid_maximum_scope)) {
            nstring_destroy (&sid_maximum_scope);
            nstring_assign (&sid_maximum_scope, &scope);
        } else {
            nstring_destroy (&scope);
        }
        nstring_destroy (&@=name);
    } else {
        E_undefined_assignment (@&name);
        types_add_name (&sid_current_type, sid_current_table, &@=name, FALSE);
    }
@};

<add-pred> = @{
    if (sid_current_pred_id) {
        E_multi_predicate_return ();
    } else if (sid_unique_pred_id == NIL (EntryP)) {
        sid_unique_pred_id = grammar_get_predicate_id (sid_current_grammar);
    }
    sid_current_pred_id = sid_unique_pred_id;
    types_add_name_entry (&sid_current_type, sid_current_pred_id);
@};

<add-void> = @{
    EntryP entry = table_add_generated_name (sid_current_table);

    types_add_name_entry (&sid_current_type, entry);
@};

// Productions section actions:

<use-global> = @{
    sid_current_scope = &sid_global_scope;
@};

<use-local> = @{
    sid_current_scope = &sid_scope_stack;
@};

<action>: (string) -> () = @{
    sid_current_entry = scope_stack_add_action (sid_current_scope,
                                                sid_current_table, &@=string,
                                                sid_enclosing_rule,
                                                &sid_redefining_entry);
    if (sid_current_entry) {
        sid_current.action = entry_get_action (sid_current_entry);
    } else {
        E_duplicate_action (@&string);
        nstring_destroy (&@=string);
    }
@};

<x-action> = @{
    if (sid_current_entry) {
        KeyP       key     = entry_key (sid_current_entry);
        TypeTupleP param   = action_param (sid_current.action);
        TypeTupleP result  = action_result (sid_current.action);
        BoolT      errored = FALSE;

        if (types_contains_names (&sid_saved_type)) {
            E_action_param_has_names (key, &sid_saved_type);
            errored = TRUE;
        }
        if (sid_redefining_entry) {
            if (!types_equal (param, &sid_saved_type)) {
                E_action_param_mismatch (key, param, &sid_saved_type);
                errored = TRUE;
            }
        }
        if (types_contains_names (&sid_current_type)) {
            E_action_result_has_names (key, &sid_current_type);
            errored = TRUE;
        }
        if (types_contains_references (&sid_current_type)) {
            E_action_result_has_refs (key, &sid_current_type);
            errored = TRUE;
        }
        if (sid_redefining_entry) {
            if (!types_equal (result, &sid_current_type)) {
                E_action_result_mismatch (key, result, &sid_current_type);
                errored = TRUE;
            }
        }
        if (errored || sid_redefining_entry) {
            types_destroy (&sid_saved_type);
            types_destroy (&sid_current_type);
        } else {
            types_assign (param, &sid_saved_type);
            types_assign (result, &sid_current_type);
        }
    } else {
        types_destroy (&sid_saved_type);
        types_destroy (&sid_current_type);
    }
@};

<non-local>: (id, type_id) -> () = @{
    sid_non_local = NIL (NonLocalEntryP);
    if ((sid_enclosing_rule == NIL (RuleP)) ||
        (sid_current_scope == &sid_global_scope)) {
        E_global_scope_non_local (@&id);
        nstring_destroy (&@=id);
    } else {
        EntryP type = table_get_type (sid_current_table, @&type_id);

        if (type == NIL (EntryP)) {
            E_unknown_type (@&type_id);
            nstring_destroy (&@=id);
        } else {
            EntryP name = scope_stack_add_non_local (sid_current_scope,
                                                     sid_current_table,
                                                     &@=id, type,
                                                     sid_enclosing_rule);

            if (name) {
                NonLocalListP non_locals = rule_non_locals (sid_enclosing_rule);
                sid_non_local = non_local_list_add (non_locals, name, type);
            } else {
                E_duplicate_non_local (@&id);
                nstring_destroy (&@=id);
            }
        }
    }
    nstring_destroy (&@=type_id);
@};

<non-local-init>: (action_id) -> () = @{
    EntryP entry = scope_stack_get_action (&sid_scope_stack, sid_current_table,
                                           @&action_id);

    if (entry == NIL (EntryP)) {
        E_unknown_action (@&action_id);
    } else if (sid_non_local) {
        EntryP     type   = non_local_entry_get_type (sid_non_local);
        KeyP       name   = entry_key (non_local_entry_get_name (sid_non_local));
        ActionP    action = entry_get_action (entry);
        TypeTupleP param  = action_param (action);
        TypeTupleP result = action_result (action);
        TypeTupleT tuple;
        TypeTupleT ref_tuple;

        types_init (&tuple);
        types_init (&ref_tuple);
        types_add_type_entry (&tuple, type, FALSE);
        types_add_type_entry (&ref_tuple, type, TRUE);
        if ((!types_equal (param, &tuple)) &&
            (!types_equal (param, &ref_tuple)) &&
            (!types_equal_zero_tuple (param))) {
            E_initialiser_param_mismatch (name, &tuple, &ref_tuple, param);
        }
        if (!types_equal (result, &tuple)) {
            E_initialiser_result_mismatch (name, &tuple, result);
        }
        types_destroy (&ref_tuple);
        types_destroy (&tuple);
        non_local_entry_set_initialiser (sid_non_local, entry);
    }
    nstring_destroy (&@=action_id);
@};

<rule>: (string) -> () = @{
    sid_current_entry = scope_stack_add_rule (sid_current_scope,
                                              sid_current_table, &@=string,
                                              sid_enclosing_rule,
                                              &sid_redefining_entry);
    if (sid_current_entry) {
        sid_current.rule = entry_get_rule (sid_current_entry);
    } else {
        E_duplicate_rule (@&string);
        nstring_destroy (&@=string);
    }
@};

<x-rule> = @{
    if (sid_current_entry) {
        KeyP       key     = entry_key (sid_current_entry);
        TypeTupleP param   = rule_param (sid_current.rule);
        TypeTupleP result  = rule_result (sid_current.rule);
        BoolT      errored = FALSE;

        if (types_contains_names (&sid_saved_type)) {
            E_rule_param_has_names (key, &sid_saved_type);
            errored = TRUE;
        }
        if (sid_redefining_entry) {
            if (!types_equal (param, &sid_saved_type)) {
                E_rule_param_mismatch (key, param, &sid_saved_type);
                errored = TRUE;
            }
        }
        if (types_contains_names (&sid_current_type)) {
            E_rule_result_has_names (key, &sid_current_type);
            errored = TRUE;
        }
        if (types_contains_references (&sid_current_type)) {
            E_rule_result_has_refs (key, &sid_current_type);
            errored = TRUE;
        }
        if (sid_redefining_entry) {
            if (!types_equal (result, &sid_current_type)) {
                E_rule_result_mismatch (key, result, &sid_current_type);
                errored = TRUE;
            }
        }
        if (errored || sid_redefining_entry) {
            types_destroy (&sid_saved_type);
            types_destroy (&sid_current_type);
        } else {
            types_assign (param, &sid_saved_type);
            types_assign (result, &sid_current_type);
        }
    } else {
        types_destroy (&sid_saved_type);
        types_destroy (&sid_current_type);
    }
@};

<prod> = @{
    if (sid_current_entry) {
        KeyP key = entry_key (sid_current_entry);

        if (rule_is_defined (sid_current.rule)) {
            E_rule_already_defined (key);
            sid_current_entry = NIL (EntryP);
            types_destroy (&sid_saved_type);
            types_destroy (&sid_current_type);
        } else {
            TypeTupleP param   = rule_param (sid_current.rule);
            TypeTupleP result  = rule_result (sid_current.rule);
            BoolT      errored = FALSE;

            rule_defined (sid_current.rule);
            if (!types_disjoint_names (&sid_saved_type)) {
                E_rule_param_clash (key, &sid_saved_type);
                errored = TRUE;
            }
            if (types_check_shadowing (&sid_saved_type, &sid_scope_stack,
                                       sid_current.rule)) {
                errored = TRUE;
            }
            if (sid_redefining_entry) {
                if (!types_fillin_names (param, &sid_saved_type)) {
                    E_rule_param_mismatch (key, param, &sid_saved_type);
                    errored = TRUE;
                }
                types_destroy (&sid_saved_type);
            } else {
                types_assign (param, &sid_saved_type);
            }
            if (!types_disjoint_names (&sid_current_type)) {
                E_rule_result_clash (key, &sid_current_type);
                errored = TRUE;
            }
            if (types_check_shadowing (&sid_current_type, &sid_scope_stack,
                                       sid_current.rule)) {
                errored = TRUE;
            }
            if (types_contains_references (&sid_current_type)) {
                E_rule_result_has_refs (key, &sid_current_type);
                errored = TRUE;
            }
            if (sid_redefining_entry) {
                if (!types_fillin_names (result, &sid_current_type)) {
                    E_rule_result_mismatch (key, result, &sid_current_type);
                    errored = TRUE;
                }
                types_destroy (&sid_current_type);
            } else {
                types_assign (result, &sid_current_type);
            }
            if (errored) {
                sid_current_entry = NIL (EntryP);
            } else {
                if (types_intersect (param, result)) {
                    E_rule_formal_clash (key, param, result);
                    sid_current_entry = NIL (EntryP);
                }
            }
        }
    } else {
        types_destroy (&sid_saved_type);
        types_destroy (&sid_current_type);
    }
    sid_alternative   = 0;
    sid_internal_rule = FALSE;
    sid_external_rule = sid_current_entry;
    nstring_init (&sid_maximum_scope);
@};

<x-prod> = @{
    if (sid_current_entry) {
        nstring_assign (rule_maximum_scope (sid_current.rule),
                        &sid_maximum_scope);
    } else {
        nstring_destroy (&sid_maximum_scope);
    }
@};

<push-scope> = @{
    if (sid_current_entry) {
        KeyP     key   = entry_key (sid_current_entry);
        NStringP scope = key_get_string (key);

        scope_stack_push (&sid_scope_stack, scope);
    }
@};

<pop-scope> = @{
    if (sid_current_entry) {
        scope_stack_pop (&sid_scope_stack);
    }
@};

<save-scope>: () -> (saved_entry, saved_rule) = @{
    @saved_entry       = sid_current_entry;
    @saved_rule        = sid_enclosing_rule;

    sid_enclosing_rule = sid_current.rule;
@};

<restore-scope>: (saved_entry, saved_rule) -> () = @{
    sid_current_entry  = @saved_entry;
    sid_current.rule   = sid_enclosing_rule;
    sid_enclosing_rule = @saved_rule;
    sid_alternative    = 0;
    sid_internal_rule  = FALSE;
    sid_external_rule  = sid_current_entry;
    nstring_init (&sid_maximum_scope);
@};

<empty-alt> = @{
    if ((++ sid_num_alternatives) == ALT_LIMIT) {
        E_too_many_alternatives ();
        UNREACHED;
    }
    if (!sid_internal_rule) {
        sid_alternative ++;
    }
    if (sid_current_entry) {
        if (rule_has_empty_alt (sid_current.rule)) {
            E_multiple_empty_alts (entry_key (sid_external_rule));
        } else if (!types_equal_zero_tuple (rule_result (sid_current.rule))) {
            E_alt_result_mismatch (entry_key (sid_external_rule),
                                   sid_alternative);
        } else {
            rule_add_empty_alt (sid_current.rule);
        }
    }
@};

<non-empty-alt> = @{
    if ((++ sid_num_alternatives) == ALT_LIMIT) {
        E_too_many_alternatives ();
        UNREACHED;
    }
    if (!sid_internal_rule) {
        sid_alternative ++;
    }
    if (sid_current_entry) {
        sid_current_alt = alt_create ();
    }
@};

<x-non-empty-alt> = @{
    if ((sid_current_entry) && (sid_current_alt)) {
        if (types_check_names (rule_result (sid_current.rule),
                               alt_names (sid_current_alt))) {
            TypeTupleT used;

            types_copy (&used, rule_result (sid_current.rule));
            item_compute_minimal_dataflow (alt_item_head (sid_current_alt),
                                           &used);
            types_destroy (&used);
            rule_add_alt (sid_current.rule, sid_current_alt);
        } else {
            (void) alt_deallocate (sid_current_alt);
            E_alt_result_mismatch (entry_key (sid_external_rule),
                                   sid_alternative);
        }
    }
@};

<handler> = @{
    if (sid_current_entry) {
        sid_current_alt = alt_create ();
    }
@};

<x-handler> = @{
    if ((sid_current_entry) && (sid_current_alt)) {
        if (types_check_names (rule_result (sid_current.rule),
                               alt_names (sid_current_alt))) {
            TypeTupleT used;

            types_copy (&used, rule_result (sid_current.rule));
            item_compute_minimal_dataflow (alt_item_head (sid_current_alt),
                                           &used);
            types_destroy (&used);
            rule_set_handler (sid_current.rule, sid_current_alt);
        } else {
            (void) alt_deallocate (sid_current_alt);
            E_handler_result_mismatch (entry_key (sid_external_rule));
        }
    }
@};

<save>: () -> (saved_entry, saved_rule, saved_alt, saved_internal, item) = @{
    @saved_entry      = sid_current_entry;
    @saved_rule       = sid_current.rule;
    @saved_alt        = sid_current_alt;
    @saved_internal   = sid_internal_rule;
    @item             = NIL (ItemP);
    sid_internal_rule = TRUE;
    if ((sid_current_entry) && (sid_current_alt)) {
        sid_current_entry = table_add_generated_rule (sid_current_table,
                                                      FALSE);
        sid_current.rule  = entry_get_rule (sid_current_entry);
        @item             = item_create (sid_current_entry);
        rule_defined (sid_current.rule);
        item_inlinable (@item);
        types_copy (item_param (@item), rule_param (@saved_rule));
        types_append_copy (item_param (@item), alt_names (@saved_alt));
        types_copy (rule_param (sid_current.rule), item_param (@item));
        types_make_references (rule_param (sid_current.rule),
                               item_param (@item));
        alt_add_item (@saved_alt, @item);
    } else {
        sid_current_entry = NIL (EntryP);
    }
@};

<restore>:
    (saved_entry, saved_rule, saved_alt, saved_internal, item) -> () = @{
    if ((@saved_entry) && (@saved_alt)) {
        rule_compute_result_intersect (sid_current.rule);
        types_copy (item_result (@item), rule_result (sid_current.rule));
        types_add_new_names (alt_names (@saved_alt), item_result (@item),
                             sid_unique_pred_id);
    }
    sid_internal_rule = @saved_internal;
    sid_current_alt   = @saved_alt;
    sid_current.rule  = @saved_rule;
    sid_current_entry = @saved_entry;
@};

<prod-action>: (string) -> () = @{
    if ((sid_current_entry) && (sid_current_alt)) {
        EntryP entry = scope_stack_get_action (&sid_scope_stack,
                                               sid_current_table, @&string);

        if (entry) {
            sid_current_item = item_create (entry);
        } else {
            E_unknown_action (@&string);
            sid_current_item = NIL (ItemP);
            (void) alt_deallocate (sid_current_alt);
            sid_current_alt  = NIL (AltP);
        }
    } else {
        sid_current_item = NIL (ItemP);
    }
    nstring_destroy (&@=string);
@};

<x-prod-action> = @{
    if (sid_current_item) {
        BoolT   errored = FALSE;
        EntryP  entry   = item_entry (sid_current_item);
        ActionP action  = entry_get_action (entry);

        if (types_resolve (&sid_current_type, rule_param (sid_current.rule),
                           alt_names (sid_current_alt), E_undefined_name,
                           entry_key (sid_external_rule), sid_alternative)) {
            if (types_equal (&sid_current_type, action_param (action))) {
                item_add_param (sid_current_item, &sid_current_type);
            } else {
                E_action_param_call_mismatch (entry_key (entry),
                                              action_param (action),
                                              &sid_current_type);
                types_destroy (&sid_current_type);
                errored = TRUE;
            }
        } else {
            types_destroy (&sid_current_type);
            errored = TRUE;
        }
        if (types_disjoint_names (&sid_saved_type)) {
            if (types_check_undefined (&sid_saved_type,
                                       rule_param (sid_current.rule),
                                       alt_names (sid_current_alt),
                                       E_redefined_name,
                                       entry_key (sid_external_rule),
                                       sid_alternative)) {
                if (types_fillin_types (&sid_saved_type,
                                        action_result (action))) {
                    types_add_new_names (alt_names (sid_current_alt),
                                         &sid_saved_type, sid_unique_pred_id);
                    if (sid_saved_pred_id) {
                        BoolT  reference;
                        EntryP type = types_find_name_type (&sid_saved_type,
                                                            sid_saved_pred_id,
                                                            &reference);

                        ASSERT ((type != NIL (EntryP)) && (!reference));
                        if (sid_predicate_type) {
                            if (type != sid_predicate_type) {
                                E_predicate_type (sid_predicate_type, type);
                            }
                        } else {
                            grammar_set_predicate_type (sid_current_grammar,
                                                        type);
                            sid_predicate_type = type;
                        }
                        item_to_predicate (sid_current_item);
                    }
                    item_add_result (sid_current_item, &sid_saved_type);
                } else {
                    E_action_result_call_mismatch (entry_key (entry),
                                                   action_result (action),
                                                   &sid_saved_type);
                    types_destroy (&sid_saved_type);
                    errored = TRUE;
                }
            } else {
                types_destroy (&sid_saved_type);
                errored = TRUE;
            }
        } else {
            E_action_result_call_clash (entry_key (entry), &sid_saved_type);
            types_destroy (&sid_saved_type);
            errored = TRUE;
        }
        if (errored) {
            (void) item_deallocate (sid_current_item);
            sid_current_item = NIL (ItemP);
            (void) alt_deallocate (sid_current_alt);
            sid_current_alt  = NIL (AltP);
        } else {
            alt_add_item (sid_current_alt, sid_current_item);
        }
    } else {
        types_destroy (&sid_saved_type);
        types_destroy (&sid_current_type);
    }
@};

<x-identity> = @{
    if ((sid_current_entry) && (sid_current_alt)) {
        EntryP entry = table_add_rename (sid_current_table);

        if (types_resolve (&sid_current_type, rule_param (sid_current.rule),
                           alt_names (sid_current_alt), E_undefined_name,
                           entry_key (sid_external_rule), sid_alternative)) {
            if (types_contains_references (&sid_current_type)) {
                E_identity_param_has_refs (&sid_current_type,
                                           entry_key (sid_external_rule),
                                           sid_alternative);
                types_destroy (&sid_current_type);
                sid_current_item = NIL (ItemP);
            } else {
                sid_current_item = item_create (entry);
                item_add_param (sid_current_item, &sid_current_type);
            }
        } else {
            types_destroy (&sid_current_type);
            sid_current_item = NIL (ItemP);
        }
        if (types_disjoint_names (&sid_saved_type)) {
            if (types_check_undefined (&sid_saved_type,
                                       rule_param (sid_current.rule),
                                       alt_names (sid_current_alt),
                                       E_redefined_name,
                                       entry_key (sid_external_rule),
                                       sid_alternative)) {
                if (sid_current_item) {
                    if (types_fillin_types (&sid_saved_type,
                                            item_param (sid_current_item))) {
                        types_add_new_names (alt_names (sid_current_alt),
                                             &sid_saved_type,
                                             sid_unique_pred_id);
                        if (sid_saved_pred_id) {
                            E_predicate ();
                        }
                        item_add_result (sid_current_item, &sid_saved_type);
                        alt_add_item (sid_current_alt, sid_current_item);
                    } else {
                        E_identity_mismatch (item_param (sid_current_item),
                                             &sid_saved_type);
                        types_destroy (&sid_saved_type);
                        (void) item_deallocate (sid_current_item);
                        sid_current_item = NIL (ItemP);
                    }
                }
            } else {
                types_destroy (&sid_saved_type);
                if (sid_current_item) {
                    (void) item_deallocate (sid_current_item);
                    sid_current_item = NIL (ItemP);
                }
            }
        } else {
            E_identity_result_clash (&sid_saved_type);
            types_destroy (&sid_saved_type);
            if (sid_current_item) {
                (void) item_deallocate (sid_current_item);
                sid_current_item = NIL (ItemP);
            }
        }
        if (sid_current_item == NIL (ItemP)) {
            (void) alt_deallocate (sid_current_alt);
            sid_current_alt = NIL (AltP);
        }
    } else {
        types_destroy (&sid_saved_type);
        types_destroy (&sid_current_type);
    }
@};

<x-prod-rule>: (string) -> () = @{
    TypeTupleP param  = NIL (TypeTupleP);
    TypeTupleP result = NIL (TypeTupleP);
    EntryP     entry  = NIL (EntryP);
    RuleP      rule;
    BasicP     basic;

    if ((sid_current_entry) && (sid_current_alt)) {
        entry = scope_stack_get_rule (&sid_scope_stack, sid_current_table,
                                      @&string);
        if (entry) {
            sid_current_item = item_create (entry);
            rule             = entry_get_rule (entry);
            param            = rule_param (rule);
            result           = rule_result (rule);
        } else {
            entry = table_get_basic (sid_current_table, @&string);
            if (entry) {
                sid_current_item = item_create (entry);
                basic            = entry_get_basic (entry);
                param            = NIL (TypeTupleP);
                result           = basic_result (basic);
                if (basic_get_ignored (basic)) {
                    E_ignored_basic_call (@&string);
                }
            } else {
                E_unknown_rule_or_basic (@&string);
                sid_current_item = NIL (ItemP);
            }
        }
    } else {
        sid_current_item = NIL (ItemP);
    }
    nstring_destroy (&@=string);
    if (sid_current_item) {
        BoolT errored = FALSE;
        KeyP  key     = entry_key (entry);

        if (types_resolve (&sid_current_type, rule_param (sid_current.rule),
                           alt_names (sid_current_alt), E_undefined_name,
                           entry_key (sid_external_rule), sid_alternative)) {
            if (param) {
                if (types_equal (&sid_current_type, param)) {
                    item_add_param (sid_current_item, &sid_current_type);
                } else {
                    E_rule_param_call_mismatch (key, param, &sid_current_type);
                    types_destroy (&sid_current_type);
                    errored = TRUE;
                }
            } else {
                if (!types_equal_zero_tuple (&sid_current_type)) {
                    E_basic_param_call_mismatch (key, &sid_current_type);
                    types_destroy (&sid_current_type);
                    errored = TRUE;
                }
            }
        } else {
            types_destroy (&sid_current_type);
            errored = TRUE;
        }
        if (types_disjoint_names (&sid_saved_type)) {
            if (types_check_undefined (&sid_saved_type,
                                       rule_param (sid_current.rule),
                                       alt_names (sid_current_alt),
                                       E_redefined_name,
                                       entry_key (sid_external_rule),
                                       sid_alternative)) {
                if (types_fillin_types (&sid_saved_type, result)) {
                    types_add_new_names (alt_names (sid_current_alt),
                                         &sid_saved_type, sid_unique_pred_id);
                    if (sid_saved_pred_id) {
                        E_predicate ();
                    }
                    item_add_result (sid_current_item, &sid_saved_type);
                } else {
                    if (param) {
                        E_rule_result_call_mismatch (key, result,
                                                     &sid_saved_type);
                    } else {
                        E_basic_result_call_mismatch (key, result,
                                                      &sid_saved_type);
                    }
                    types_destroy (&sid_saved_type);
                    errored = TRUE;
                }
            } else {
                types_destroy (&sid_saved_type);
                errored = TRUE;
            }
        } else {
            if (param) {
                E_rule_result_call_clash (key, &sid_saved_type);
            } else {
                E_basic_result_call_clash (key, &sid_saved_type);
            }
            types_destroy (&sid_saved_type);
            errored = TRUE;
        }
        if (errored) {
            (void) item_deallocate (sid_current_item);
            sid_current_item = NIL (ItemP);
            (void) alt_deallocate (sid_current_alt);
            sid_current_alt  = NIL (AltP);
        } else {
            alt_add_item (sid_current_alt, sid_current_item);
        }
    } else {
        if (sid_current_alt) {
            (void) alt_deallocate (sid_current_alt);
            sid_current_alt = NIL (AltP);
        }
        types_destroy (&sid_saved_type);
        types_destroy (&sid_current_type);
    }
@};

<x-prod-rule-or-identity>: (string) -> () = @{
    EntryP     name_entry = table_get_entry (sid_current_table, @&string);
    EntryP     entry      = NIL (EntryP);
    TypeTupleP param      = NIL (TypeTupleP);
    TypeTupleP result     = NIL (TypeTupleP);
    RuleP      rule;
    BasicP     basic;

    if ((sid_current_entry) && (sid_current_alt)) {
        if ((name_entry != NIL (EntryP)) &&
            (!types_contains (alt_names (sid_current_alt), name_entry)) &&
            (!types_contains (rule_param (sid_current.rule), name_entry))) {
            name_entry = NIL (EntryP);
        }
        entry = scope_stack_get_rule (&sid_scope_stack, sid_current_table,
                                      @&string);
        if (entry) {
            sid_current_item = item_create (entry);
            rule             = entry_get_rule (entry);
            param            = rule_param (rule);
            result           = rule_result (rule);
        } else {
            entry = table_get_basic (sid_current_table, @&string);
            if (entry) {
                sid_current_item = item_create (entry);
                basic            = entry_get_basic (entry);
                param            = NIL (TypeTupleP);
                result           = basic_result (basic);
                if ((name_entry == NIL (EntryP)) &&
                    basic_get_ignored (basic)) {
                    E_ignored_basic_call (@&string);
                }
            }
        }
        if ((entry == NIL (EntryP)) && (name_entry == NIL (EntryP))) {
            NStringT scope;

            name_entry = scope_stack_get_non_local (&sid_scope_stack,
                                                    sid_current_table,
                                                    @&string, &scope);
            if (name_entry) {
                if (nstring_length (&scope) >
                    nstring_length (&sid_maximum_scope)) {
                    nstring_destroy (&sid_maximum_scope);
                    nstring_assign (&sid_maximum_scope, &scope);
                } else {
                    nstring_destroy (&scope);
                }
            } else {
                E_unknown_rule_or_basic (@&string);
            }
        } else if ((entry != NIL (EntryP)) && (name_entry != NIL (EntryP))) {
            E_ambiguous_call (@&string);
            entry      = NIL (EntryP);
            name_entry = NIL (EntryP);
        }
    } else {
        name_entry = NIL (EntryP);
    }
    nstring_destroy (&@=string);
    if (entry) {
        BoolT errored = FALSE;
        KeyP  key     = entry_key (entry);

        if (types_resolve (&sid_current_type, rule_param (sid_current.rule),
                           alt_names (sid_current_alt), E_undefined_name,
                           entry_key (sid_external_rule), sid_alternative)) {
            if (param) {
                if (types_equal (&sid_current_type, param)) {
                    item_add_param (sid_current_item, &sid_current_type);
                } else {
                    E_rule_param_call_mismatch (key, param, &sid_current_type);
                    types_destroy (&sid_current_type);
                    errored = TRUE;
                }
            } else {
                if (!types_equal_zero_tuple (&sid_current_type)) {
                    E_basic_param_call_mismatch (key, &sid_current_type);
                    types_destroy (&sid_current_type);
                    errored = TRUE;
                }
            }
        } else {
            types_destroy (&sid_current_type);
            errored = TRUE;
        }
        if (types_disjoint_names (&sid_saved_type)) {
            if (types_check_undefined (&sid_saved_type,
                                       rule_param (sid_current.rule),
                                       alt_names (sid_current_alt),
                                       E_redefined_name,
                                       entry_key (sid_external_rule),
                                       sid_alternative)) {
                if (types_fillin_types (&sid_saved_type, result)) {
                    types_add_new_names (alt_names (sid_current_alt),
                                         &sid_saved_type, sid_unique_pred_id);
                    if (sid_saved_pred_id) {
                        E_predicate ();
                    }
                    item_add_result (sid_current_item, &sid_saved_type);
                } else {
                    if (param) {
                        E_rule_result_call_mismatch (key, result,
                                                     &sid_saved_type);
                    } else {
                        E_basic_result_call_mismatch (key, result,
                                                      &sid_saved_type);
                    }
                    types_destroy (&sid_saved_type);
                    errored = TRUE;
                }
            } else {
                types_destroy (&sid_saved_type);
                errored = TRUE;
            }
        } else {
            if (param) {
                E_rule_result_call_clash (key, &sid_saved_type);
            } else {
                E_basic_result_call_clash (key, &sid_saved_type);
            }
            types_destroy (&sid_saved_type);
            errored = TRUE;
        }
        if (errored) {
            (void) item_deallocate (sid_current_item);
            sid_current_item = NIL (ItemP);
            (void) alt_deallocate (sid_current_alt);
            sid_current_alt  = NIL (AltP);
        } else {
            alt_add_item (sid_current_alt, sid_current_item);
        }
    } else if (name_entry) {
        types_add_name_entry (&sid_current_type, name_entry);
        entry = table_add_rename (sid_current_table);
        if (types_resolve (&sid_current_type, rule_param (sid_current.rule),
                           alt_names (sid_current_alt), E_undefined_name,
                           entry_key (sid_external_rule), sid_alternative)) {
            if (types_contains_references (&sid_current_type)) {
                E_identity_param_has_refs (&sid_current_type,
                                           entry_key (sid_external_rule),
                                           sid_alternative);
                types_destroy (&sid_current_type);
                sid_current_item = NIL (ItemP);
            } else {
                sid_current_item = item_create (entry);
                item_add_param (sid_current_item, &sid_current_type);
            }
        } else {
            types_destroy (&sid_current_type);
            sid_current_item = NIL (ItemP);
        }
        if (types_disjoint_names (&sid_saved_type)) {
            if (types_check_undefined (&sid_saved_type,
                                       rule_param (sid_current.rule),
                                       alt_names (sid_current_alt),
                                       E_redefined_name,
                                       entry_key (sid_external_rule),
                                       sid_alternative)) {
                if (sid_current_item) {
                    if (types_fillin_types (&sid_saved_type,
                                            item_param (sid_current_item))) {
                        types_add_new_names (alt_names (sid_current_alt),
                                             &sid_saved_type,
                                             sid_unique_pred_id);
                        if (sid_saved_pred_id) {
                            E_predicate ();
                        }
                        item_add_result (sid_current_item, &sid_saved_type);
                        alt_add_item (sid_current_alt, sid_current_item);
                    } else {
                        E_identity_mismatch (item_param (sid_current_item),
                                             &sid_saved_type);
                        types_destroy (&sid_saved_type);
                        (void) item_deallocate (sid_current_item);
                        sid_current_item = NIL (ItemP);
                    }
                }
            } else {
                types_destroy (&sid_saved_type);
                if (sid_current_item) {
                    (void) item_deallocate (sid_current_item);
                    sid_current_item = NIL (ItemP);
                }
            }
        } else {
            E_identity_result_clash (&sid_saved_type);
            types_destroy (&sid_saved_type);
            if (sid_current_item) {
                (void) item_deallocate (sid_current_item);
                sid_current_item = NIL (ItemP);
            }
        }
        if (sid_current_item == NIL (ItemP)) {
            (void) alt_deallocate (sid_current_alt);
            sid_current_alt = NIL (AltP);
        }
    } else {
        if (sid_current_alt) {
            (void) alt_deallocate (sid_current_alt);
            sid_current_alt = NIL (AltP);
        }
        types_destroy (&sid_saved_type);
        types_destroy (&sid_current_type);
    }
@};

<add-entry>: (string) -> () = @{
    EntryP entry = table_get_rule (sid_current_table, @&string);

    if (entry) {
        if (entry_list_contains (sid_current_entry_list, entry)) {
            E_mult_entry (entry_key (entry));
        } else {
            entry_list_add (sid_current_entry_list, entry);
            rule_required (entry_get_rule (entry));
        }
    } else {
        E_unknown_rule (@&string);
    }
    nstring_destroy (&@=string);
@};

// Error recovery stuff:

<unhandled-syntax-error> = @{
    UNREACHED;
@};

<expected-typemark> = @{
    if (!sid_propagating_error) {
        E_expected_typemark ();
    }
@};

<expected-identifier> = @{
    if (!sid_propagating_error) {
        E_expected_identifier ();
    }
@};

<expected-tuple-defn> = @{
    if (!sid_propagating_error) {
        E_expected_tuple_defn ();
    }
@};

<expected-terminal-decn> = @{
    if (!sid_propagating_error) {
        E_expected_terminal_decn ();
    }
@};

<expected-separator> = @{
    if (!sid_propagating_error) {
        E_expected_separator ();
    }
@};

<expected-open-tuple> = @{
    if (!sid_propagating_error) {
        E_expected_open_tuple ();
    }
@};

<expected-close-tuple> = @{
    if (!sid_propagating_error) {
        E_expected_close_tuple ();
    }
@};

<expected-arrow> = @{
    if (!sid_propagating_error) {
        E_expected_arrow ();
    }
@};

<expected-terminator> = @{
    if (!sid_propagating_error) {
        E_expected_terminator ();
    }
@};

<expected-lhs-name> = @{
    if (!sid_propagating_error) {
        E_expected_lhs_name ();
    }
@};

<expected-rhs-name> = @{
    if (!sid_propagating_error) {
        E_expected_rhs_name ();
    }
@};

<expected-begin-action> = @{
    if (!sid_propagating_error) {
        E_expected_begin_action ();
    }
@};

<expected-end-action> = @{
    if (!sid_propagating_error) {
        E_expected_end_action ();
    }
@};

<expected-end-scope> = @{
    if (!sid_propagating_error) {
        E_expected_end_scope ();
    }
@};

<expected-tuple-or-terminator> = @{
    if (!sid_propagating_error) {
        E_expected_tuple_or_term ();
    }
@};

<expected-item-rhs> = @{
    if (!sid_propagating_error) {
        E_expected_item_rhs ();
    }
@};

<expected-define> = @{
    if (!sid_propagating_error) {
        E_expected_define ();
    }
@};

<expected-tuple-or-define-or-terminator> = @{
    if (!sid_propagating_error) {
        E_expected_tuple_def_or_term ();
    }
@};

<expected-begin-rule> = @{
    if (!sid_propagating_error) {
        E_expected_begin_rule ();
    }
@};

<expected-end-rule> = @{
    if (!sid_propagating_error) {
        E_expected_end_rule ();
    }
@};

<expected-item> = @{
    if (!sid_propagating_error) {
        E_expected_item ();
    }
@};

<expected-alternative> = @{
    if (!sid_propagating_error) {
        E_expected_alternative ();
    }
@};

<expected-other-defn> = @{
    if (!sid_propagating_error) {
        E_expected_other_defn ();
    }
@};

<expected-production-defn> = @{
    if (!sid_propagating_error) {
        E_expected_production_defn ();
    }
@};

<expected-blt-types> = @{
    if (!sid_propagating_error) {
        E_expected_blt_types ();
    }
@};

<expected-blt-terminals> = @{
    if (!sid_propagating_error) {
        E_expected_blt_terminals ();
    }
@};

<expected-blt-productions> = @{
    if (!sid_propagating_error) {
        E_expected_blt_productions ();
    }
@};

<expected-blt-entry> = @{
    if (!sid_propagating_error) {
        E_expected_blt_entry ();
    }
@};

<expected-eof> = @{
    if (!sid_propagating_error) {
        E_expected_eof ();
    }
@};

<expected-terminator-or-define> = @{
    if (!sid_propagating_error) {
        E_expected_terminator_or_define ();
    }
@};

<destroy-string>: (string) -> () = @{
    nstring_destroy (&@=string);
@};

<skip-to-end-of-tuple-defn> = @{
    if (sid_finished_terminals) {
        while ((@. != LEXER_TOK_EOF) &&
               (@. != LEXER_TOK_DEFINE) &&
               (@. != LEXER_TOK_BEGIN_SCOPE) &&
               (@. != LEXER_TOK_BEGIN_RULE) &&
               (@. != LEXER_TOK_SEPARATOR) &&
               (@. != LEXER_TOK_CLOSE_TUPLE) &&
               (@. != LEXER_TOK_TERMINATOR) &&
               (@. != LEXER_TOK_BLT_ENTRY)) {
            if (@. == LEXER_TOK_IDENTIFIER) {
                nstring_destroy (lexer_string_value (sid_current_stream));
            }
            @>;
        }
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        if (@. != LEXER_TOK_EOF) {
            @>;
        }
    } else {
        while ((@. != LEXER_TOK_EOF) &&
               (@. != LEXER_TOK_SEPARATOR) &&
               (@. != LEXER_TOK_CLOSE_TUPLE) &&
               (@. != LEXER_TOK_TERMINATOR) &&
               (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
               (@. != LEXER_TOK_BLT_ENTRY)) {
            if (@. == LEXER_TOK_IDENTIFIER) {
                nstring_destroy (lexer_string_value (sid_current_stream));
            }
            @>;
        }
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        if (@. != LEXER_TOK_EOF) {
            @>;
        }
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-terminal-decn> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_TERMINATOR) &&
           (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
           (@. != LEXER_TOK_BLT_ENTRY)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-lhs-name> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_TERMINATOR) &&
           (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
           (@. != LEXER_TOK_BLT_ENTRY)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-rhs-name> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_TERMINATOR) &&
           (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
           (@. != LEXER_TOK_BLT_ENTRY)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-action-decn> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_TERMINATOR) &&
           (@. != LEXER_TOK_END_SCOPE) &&
           (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
           (@. != LEXER_TOK_BLT_ENTRY)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-item> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_TERMINATOR) &&
           (@. != LEXER_TOK_ALT_SEP) &&
           (@. != LEXER_TOK_HANDLER_SEP) &&
           (@. != LEXER_TOK_BEGIN_RULE) &&
           (@. != LEXER_TOK_END_RULE) &&
           (@. != LEXER_TOK_END_SCOPE) &&
           (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
           (@. != LEXER_TOK_BLT_ENTRY)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-alternative> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_ALT_SEP) &&
           (@. != LEXER_TOK_HANDLER_SEP) &&
           (@. != LEXER_TOK_END_RULE) &&
           (@. != LEXER_TOK_END_SCOPE) &&
           (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
           (@. != LEXER_TOK_BLT_ENTRY)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-other-defn> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_TERMINATOR) &&
           (@. != LEXER_TOK_END_SCOPE) &&
           (@. != LEXER_TOK_END_RULE) &&
           (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
           (@. != LEXER_TOK_BLT_ENTRY)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-production-defn> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_TERMINATOR) &&
           (@. != LEXER_TOK_END_SCOPE) &&
           (@. != LEXER_TOK_END_RULE) &&
           (@. != LEXER_TOK_BLT_PRODUCTIONS) &&
           (@. != LEXER_TOK_BLT_ENTRY)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-to-end-of-entry-list> = @{
    while ((@. != LEXER_TOK_EOF) &&
           (@. != LEXER_TOK_TERMINATOR) &&
           (@. != LEXER_TOK_SEPARATOR)) {
        if (@. == LEXER_TOK_IDENTIFIER) {
            nstring_destroy (lexer_string_value (sid_current_stream));
        }
        @>;
    }
    if (@. == LEXER_TOK_IDENTIFIER) {
        nstring_destroy (lexer_string_value (sid_current_stream));
    }
    if (@. != LEXER_TOK_EOF) {
        @>;
    }
    sid_propagating_error = TRUE;
@};

<skip-recover> = @{
    sid_propagating_error = FALSE;
@};

<is-blt-entry-or-end-scope-or-eof>: () -> (predicate) = @{
    @predicate = ((@. == LEXER_TOK_EOF) ||
                  (@. == LEXER_TOK_END_SCOPE) ||
                  (@. == LEXER_TOK_BLT_ENTRY));
@};

<is-close-tuple-or-skipped-or-eof>: () -> (predicate) = @{
    @predicate = ((@. == LEXER_TOK_CLOSE_TUPLE) ||
                  (@. == LEXER_TOK_EOF) ||
                  (sid_propagating_error));
@};

<is-terminator>: () -> (predicate) = @{
    @predicate = (@. == LEXER_TOK_TERMINATOR);
@};

<is-not-separator>: () -> (predicate) = @{
    @predicate = (@. != LEXER_TOK_SEPARATOR);
@};

%trailer% @{
@}, @{
@};