/*
  Copyright Dave Bone 1998 - 2014 
  All Rights Reserved. 
  No part of this document may be reproduced without written consent from the author.
	
FILE:		  terminals_phrase_th.lex
Dates:		  24 May 2004
Purpose:	  parse terminals phrase
              The keeps its own local symbol table: map and list.
              The terminal_def_phrase adds symbol to Yacco2's
              global symbol table.
Output:       terminals_phrase
*/
/@
@i "/usr/local/yacco2/copyright.w"
@** |terminals_phrase_th| thread.\fbreak
Parse terminals phrase. It goes thru the terminal definitions
and keeps its own local symbol table: map and list.
The |terminal_def_phrase| thread adds each symbol to \O2's
global symbol table.
It calls the common backend |term_def_ph| thread
extractor of symbol definition.

The only wrinkle is in the handling of pre / post amble directives 
|#terminal-refs| and |#terminals-sufx|.
These directives are outside the normal containment within a rule, subrule,
 or ``fsm'' entities.
They come before or after the terminal definitions.
Why the wrinkle? |cweb| introductory comments
for these directives come before the directive declaration:
just like syntax directed code directives.
They could stymie the grammar writer by applying 
this approach to introductory comments for rules which
is an error;
|cweb| introductory comments for a   
rule or terminals of all colours comes between
the key / name and just before their class constructs.\fbreak

 \fbreak
Example of a terminals vocabulary to parse:\fbreak
\listing{"/usr/local/yacco2/diagrams+etc/Tsym.txt"}
@/
fsm	
(fsm-id "terminals_phrase_th.lex"
,fsm-filename terminals_phrase_th
,fsm-namespace NS_terminals_phrase_th
,fsm-class Cterminals_phrase_th{
  user-prefix-declaration
#include "lint_balls.h"
#include "cweb_or_c_k.h"
#include "identifier.h"
#include "term_def_ph.h"
#include "c_string.h"
#include "o2_sdc.h"
  ***
  user-declaration
    public:
    T_terminals_phrase* terminals_phrase_;
  ***
  op
    if(terminals_phrase_ != 0){
      delete terminals_phrase_;
      terminals_phrase_ = 0;
    }
    terminals_phrase_ = new T_terminals_phrase;
    terminals_phrase_->set_rc(*parser__->start_token__,__FILE__,__LINE__);
    AST* t = new AST(*terminals_phrase_);
    terminals_phrase_->phrase_tree(t);
  ***
  constructor
    terminals_phrase_ = 0;
  ***
}
,fsm-version "1.0",fsm-date "22 mar 2004",fsm-debug "false"
,fsm-comments "Parse terminals vocabulary.")
parallel-parser	
(	
  parallel-thread-function
    TH_terminals_phrase_th
  ***
  parallel-la-boundary
    eolr
  ***
)
@"/usr/local/yacco2/compiler/grammars/yacco2_T_includes.T"

rules{
Rterminals_phrase  (){
  -> Rlint 
     Ropen_par 
       Rparameters  
     Rclose_par
     Rlint 
	Ropen_brace
		 Rt_refs_phrase
		 Rsym_defs_phrase
		 Rt_sufx_phrase
		Rlint
	 Rclose_brace  
     {
    op
      Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
      RSVP(fsm->terminals_phrase_);
      fsm->terminals_phrase_ = 0;
    ***
    }	
}

Ropen_par  (){
  ->  |?| { 
      op
        CAbs_lr1_sym* sym = new Err_no_open_parenthesis;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
  ->  "("
}

Rclose_par  (){
  ->  |?| { 
      op
        CAbs_lr1_sym* sym = new Err_no_close_parenthesis;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
  ->  ")"
}

Rparameters  (){
  -> Rlint
     Rfilename_phrase Rlint
     Rnamespace_phrase Rlint
}

Rfilename_phrase  (){
  -> Rfilename Rlint Rfilename_id 
}

Rfilename  (){
  ->  ||| "#file-name" NS_identifier::TH_identifier
  ->  ||| |?| NULL {
    op
      sf->p2__->set_auto_delete(true);
        CAbs_lr1_sym* sym = new Err_no_filename_present;
        sym->set_rc(*sf->p2__,__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
    ***
    }
  ->  |?| {
      op
        CAbs_lr1_sym* sym = new Err_no_filename_present;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
}

Rfilename_id  (){
  ->  ||| identifier NS_identifier::TH_identifier {
      op
        Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
        fsm->terminals_phrase_->filename_id(sf->p2__);
      ***
      } 
  ->  ||| |?| NULL {
    op
      sf->p2__->set_auto_delete(true);
        CAbs_lr1_sym* sym = new Err_no_filename_id_present;
        sym->set_rc(*sf->p2__,__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
    ***
    }
  ->  |?| {
      op
        CAbs_lr1_sym* sym = new Err_no_filename_id_present;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
}

Rnamespace_phrase  (){
  -> "," Rlint Rnamespace Rlint Rnamespace_id 
  ->   {
      op
        CAbs_lr1_sym* sym = new Err_no_comma_present;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
}

Rnamespace  (){
  ->  ||| "#name-space" NS_identifier::TH_identifier 
  ->  ||| |?| NULL {
    op
      sf->p2__->set_auto_delete(true);
        CAbs_lr1_sym* sym = new Err_no_namespace_present;
        sym->set_rc(*sf->p2__,__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
    ***
    }
  ->  |?| {
      op
        CAbs_lr1_sym* sym = new Err_no_namespace_present;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
}

Rnamespace_id  (){
  ->  ||| identifier NS_identifier::TH_identifier {
      op
        Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
        fsm->terminals_phrase_->namespace_id(sf->p2__);
      ***
      } 
  ->  ||| |?| NULL {
    op
      sf->p2__->set_auto_delete(true);
        CAbs_lr1_sym* sym = new Err_no_namespace_id_present;
        sym->set_rc(*sf->p2__,__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
    ***
    }
  ->  |?| {
      op
        CAbs_lr1_sym* sym = new Err_no_namespace_id_present;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
}

Rt_refs_phrase  (){
  -> Rlint Rcweb_k Rlint Rt_refs_kw_must Rt_refs_code {
  op
    Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
	  fsm->terminals_phrase_->terminals_refs_code()
	  ->add_cweb_marker(sf->p2__->cweb_t_);		
  ***
  } 
  -> Rlint Rt_refs_kw_code
}

Rt_refs_kw_code  (){
  -> Rt_refs_kw Rt_refs_code 
  -> 
}

Rt_refs_kw  
/@
Drop the keyword as it is not needed. So delete at pop time.
Mark the directive as seen just in case it is repeated and
so it's an error situation.
@/
(){
  -> ||| "#terminals-refs" NS_identifier::TH_identifier {
      op
          sf->p2__->set_auto_delete(true);
      ***
      }
}

Rt_refs_kw_must  
/@
Drop the keyword as it is not needed. So delete at pop time.
Mark the directive as seen just in case it is repeated and
so it's an error situation.
@/
(){
  -> ||| "#terminals-refs" NS_identifier::TH_identifier {
      op
          sf->p2__->set_auto_delete(true);
      ***
      }
  ->  ||| |?| NULL {
      op
          CAbs_lr1_sym* sym = new Err_missing_terminals_refs_kw;
          sym->set_rc(*sf->p2__,__FILE__,__LINE__);
          RSVP(sym);
          sf->p2__->set_auto_delete(true);
          rule_info__.parser__->set_stop_parse(true);
      ***
      }
  -> |?| {
     op
          CAbs_lr1_sym* sym = new Err_missing_terminals_refs_kw;
          sym->set_rc(*sf->p1__,__FILE__,__LINE__);
          RSVP(sym);
          rule_info__.parser__->set_stop_parse(true);
     *** 
  }
}

Rt_refs_code  (){
  ->  ||| "syntax-code" NS_o2_sdc::TH_o2_sdc {
      op
        Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
        fsm->terminals_phrase_->terminals_refs_code(sf->p2__);
      ***
      }
  ->  ||| |?| NULL {
      op
          CAbs_lr1_sym* sym = new Err_no_syntax_code_present;
          sym->set_rc(*sf->p2__,__FILE__,__LINE__);
          RSVP(sym);
          sf->p2__->set_auto_delete(true);
          rule_info__.parser__->set_stop_parse(true);
      ***
      }
  ->  |?| {
      op
          CAbs_lr1_sym* sym = new Err_no_syntax_code_present;
          sym->set_rc(*rule_info__.parser__->start_token__,__FILE__,__LINE__);
          RSVP(sym);
          rule_info__.parser__->set_stop_parse(true);
      ***
      }
}

Rsym_defs_phrase  (){
  -> Rlint Rsym_def Rlint Rsym_def1s
}

Rsym_def  (){
  ->  ||| "terminal-def" NS_term_def_ph::TH_term_def_ph {
    op
      Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
      sf->p2__->classification(T_terminal_def::t);
      CAbs_lr1_sym* r = 
	    fsm->terminals_phrase_->add_t_to_alphabet(sf->p2__,rule_info__.parser__);
      if(r == 0) return;
      RSVP(r);
      rule_info__.parser__->set_stop_parse(true);
    ***
    }
  ->  ||| |?| NULL {
      op
        sf->p2__->set_auto_delete(true);
        CAbs_lr1_sym* sym = new Err_no_sym_defs_present;
        sym->set_rc(*sf->p2__,__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
  ->  |?| {
    op
        CAbs_lr1_sym* sym = new Err_no_sym_defs_present;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
    ***
    }
}

Rsym_def1s  (){
  ->  Rsym_def1 Rlint
  ->  Rsym_def1s Rsym_def1 Rlint
  -> 
}

Rsym_def1  (
//lhs,
parallel-control-monitor{
/@
    Note how the arbitration is done: list check.
    In this grammar, at most 2 terminals can be returned.
    When 2 terminals are returned, one is in error and the other is
    a result from the terminals-sufx. This is either the
    syntax-code or an error: eg no code present.
@/
   arbitrator-code
   using namespace NS_yacco2_T_enum;
      for(i=1;i<=ie;++i){
	     if(Caller_pp->pp_accept_queue__[i].accept_token__->enumerated_id__ 
                != NS_yacco2_T_enum::T_Enum::T_Err_no_terminal_key_present_){
	        goto arbitrated_parameter;
             }
     }
  ***
  }
){
  ->  ||| "terminal-def" NS_term_def_ph::TH_term_def_ph {
    op
      Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
	  sf->p2__->classification(T_terminal_def::t);
      CAbs_lr1_sym* r = fsm->terminals_phrase_->add_t_to_alphabet(sf->p2__,rule_info__.parser__);
      if(r != 0){
        RSVP(r);
        rule_info__.parser__->set_stop_parse(true);
        return;
      }
    ***
    }
  ->  ||| "no key-value present in definition" NULL {
      op
        Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
        RSVP(fsm->terminals_phrase_);
        fsm->terminals_phrase_ = 0;
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
  ->  ||| |?| NULL {
      op
      using namespace NS_yacco2_T_enum;
       int id = sf->p2__->enumerated_id__;
       if(id >= T_Enum::start_ERR && id <= T_Enum::end_ERR){
         RSVP(sf->p2__);
         rule_info__.parser__->set_stop_parse(true);
       }else{
        CAbs_lr1_sym* sym = new Err_not_a_terminal_definition;
        sym->set_rc(*sf->p2__,__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
       }
      ***
      }
}

Rt_sufx_phrase  (){
  -> Rlint Rcweb_k Rt_sufx_kw_must Rt_sufx_code {
  op
    Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
	  fsm->terminals_phrase_->terminals_sufx_code()
	  ->add_cweb_marker(sf->p2__->cweb_t_);		
  ***
  } 
  -> Rlint Rt_sufx_kw_code
}

Rt_sufx_kw_code  
/@
If a |cweb| comment is seen, deposit it in the 
directive's syntax directed code.
@/
(){
  -> Rt_sufx_kw Rt_sufx_code 
  -> 
}

Rt_sufx_kw  
/@
Drop keyword as it's presence is indicated elsewhere.
So pop the cork and let the good times roll.
@/

(){
  -> ||| "#terminals-sufx" NS_identifier::TH_identifier {
      op
         sf->p2__->set_auto_delete(true);
      ***
      }
}

Rt_sufx_kw_must  
/@
Drop keyword as it's presence is indicated elsewhere.
So pop the cork and let the good times roll.
@/

(){
  -> ||| "#terminals-sufx" NS_identifier::TH_identifier {
      op
         sf->p2__->set_auto_delete(true);
      ***
      }
  ->  ||| |?| NULL {
      op
          CAbs_lr1_sym* sym = new Err_missing_terminals_sufx_kw;
          sym->set_rc(*sf->p2__,__FILE__,__LINE__);
          RSVP(sym);
          sf->p2__->set_auto_delete(true);
          rule_info__.parser__->set_stop_parse(true);
      ***
      }
  -> |?| {
     op
          CAbs_lr1_sym* sym = new Err_missing_terminals_sufx_kw;
          sym->set_rc(*sf->p1__,__FILE__,__LINE__);
          RSVP(sym);
          rule_info__.parser__->set_stop_parse(true);
          return;
     ***
     }
}

Rt_sufx_code  (){
  ->  ||| "syntax-code" NS_o2_sdc::TH_o2_sdc {
      op
        Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
        fsm->terminals_phrase_->terminals_sufx_code(sf->p2__);
      ***
      }
  ->  ||| |?| NULL {
      op
          CAbs_lr1_sym* sym = new Err_no_syntax_code_present;
          sym->set_rc(*sf->p2__,__FILE__,__LINE__);
          RSVP(sym);
          sf->p2__->set_auto_delete(true);
          rule_info__.parser__->set_stop_parse(true);
      ***
      }
  ->  |?| {
      op
          CAbs_lr1_sym* sym = new Err_no_syntax_code_present;
          sym->set_rc(*rule_info__.parser__->start_token(),__FILE__,__LINE__);
          RSVP(sym);
          rule_info__.parser__->set_stop_parse(true);
      ***
      }
}

Ropen_brace  (){
  ->  |?| { 
      op
        CAbs_lr1_sym* sym = new Err_no_open_brace;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
  ->  "{"
}

Rclose_brace  (){
  ->  |?| { 
      op
        CAbs_lr1_sym* sym = new Err_no_close_brace;
        sym->set_rc(*rule_info__.parser__->current_token(),__FILE__,__LINE__);
        RSVP(sym);
        rule_info__.parser__->set_stop_parse(true);
      ***
      }
  ->  "}"
}

Rlint  (){
  ->  ||| lint NS_lint_balls::TH_lint_balls
  -> 
}

Rcweb_k  (
lhs {
	user-declaration
	  AST* cweb_t_;
	***
	constructor
	  cweb_t_ = 0;
	***
	}
){

  ->  ||| "cweb-comment" NS_cweb_or_c_k::TH_cweb_or_c_k {
  op
       Cterminals_phrase_th* fsm = (Cterminals_phrase_th*)rule_info__.parser__->fsm_tbl__;
      T_cweb_comment* k = sf->p2__;
      AST* cwebk_t_ = new AST(*k);
      cweb_t_ = new AST();
      T_cweb_marker* cw = new T_cweb_marker(cweb_t_);
      cw->set_rc(*k,__FILE__,__LINE__);
        cweb_t_ = cw->ast();
      AST::set_content(*cweb_t_,*cw);
        AST::join_pts(*cweb_t_,*cwebk_t_);
  ***
  }
  ->  ||| |?| NULL {
      op 
		RSVP(sf->p2__);
		rule_info__.parser__->set_stop_parse(true); 
      ***
      }     
}
}// end of rules
