/* Copyright Dave Bone 1998 - 2014 All Rights Reserved. No part of this document may be reproduced without written consent from the author. FILE: rules_use_cnt.lex Dates: 23 Sept. 2005 Purpose: used to optimize the recycled rules table use. */ /@ @i "/usr/local/yacco2/copyright.w" @** |rules_use_cnt| grammar.\fbreak Determine each rule's use count for generating recycled rules tables. It answers the question: What is the maximum number of rules needed in each recycled rules table?. If the rule has recursion then indicate in rule's definition. The heart of the algorithm is to determine the maximum rule's use count against all rules rhs. The grammar tree is walked in top-down fashion: prefix using a filter for only rule-def, subrule-def, and referenced-rules. \fbreak \fbreak Stage 1: Build per rule its rule use skeleton. This is done upon entry into the grammar using the ``op directive'' before the grammar parses. Removeal of all the T vocabulary from the rhs leave its bones. If the resultant rhs is empty then it does not partake in the analysis as there are no rule used. The rule's skeleton is deposited within its ``rule-def'' for the balance of the stages.\fbreak \fbreak Stage 2: Determine rule's use count per skeleton.\fbreak The max use count is posted in the rule's definition to generate the space requirement for the rule's recycling table. \fbreak \fbreak Remarks:\fbreak The walked skeleton checks the use count of indirect rule's in use. For example:\fbreak \settabs\+\indent&1in\qquad&\qquad&\qquad&\cr \+&\it Rule&&{\it subrule's symbols}\cr \+&Rs &$\rightarrow$ &Ra Rxx Ra Rxxx $\bot$\cr \+&Ra &$\rightarrow$ &a \cr \+&&$\rightarrow$ &Ra a\cr \+&Rxx&$\rightarrow$ &x Ra x Ra b\cr \+&Rxxx&$\rightarrow$ &x Ra x Ra x Ra\cr \fbreak What is the maximum use count of Ra in the above grammar? It is 6 caused by the 1st rule. Why? Here is an example to support my statement.\fbreak \settabs\+\indent&a a x a x a b a x a x a x a a\&\qquad&a a x a x a b a x a x a x a a a&Comments\cr \+&{\it Parse Stack}&{\it input string to parse}&Comments\cr \+& & a a x a x a b a x a x a x a a\cr \+&a & a x a x a b a x a x a x a a\cr \+&Ra & a x a x a b a x a x a x a a\cr \+&Ra a & x a x a b a x a x a x a a& recursion: 2 Ra --- lhs and stacked rhs\cr \+&Ra & x a x a b a x a x a x a a& Ra lhs, popped rhs Ra recycled \cr \+&Ra x & a x a b a x a x a x a a\cr \+&Ra x a & x a b a x a x a x a a\cr \+&Ra x Ra & x a b a x a x a x a a\cr \+&Ra x Ra x & a b a x a x a x a a\cr \+&Ra x Ra x a & b a x a x a x a a\cr \+&Ra x Ra x Ra & b a x a x a x a a\cr \+&Ra x Ra x Ra b & a x a x a x a a\cr \+&Ra Rxx & a x a x a x a a\cr \+&Ra Rxx a & x a x a x a a\cr \+&Ra Rxx Ra & x a x a x a a\cr \+&Ra Rxx Ra x & a x a x a a\cr \+&Ra Rxx Ra x a & x a x a a\cr \+&Ra Rxx Ra x Ra & x a x a a\cr \+&Ra Rxx Ra x Ra x & a x a a\cr \+&Ra Rxx Ra x Ra x a& x a a\cr \+&Ra Rxx Ra x Ra x Ra& x a a\cr \+&Ra Rxx Ra x Ra x Ra x& a a\cr \+&Ra Rxx Ra x Ra x Ra x a& a\cr \+&Ra Rxx Ra x Ra x Ra x Ra& a\cr \+&Ra Rxx Ra x Ra x Ra x Ra a& note: extra Ra for lhs/rhs from recursion\cr \+&Ra Rxx Ra x Ra x Ra x Ra& though 5 Ra on stack, above lhs/rhs requires 6\cr \+&Ra Rxx Ra Rxxx& where Rxxx's rhs needs 4 before it reduces\cr \fbreak There are 2 direct Ra used and 4 indirect Ra from Rxxx's rhs before it is reduced: 3 direct Ra used + 1 Ra for the recursion on its last recognized Ra before Rxxx's rhs is completely recognized. Recursion of Ra demands 2 Ra: lhs / rhs. The first ``a'' recognized creates a Ra that is pushed onto the stack. The following ``a'' get recognized by the Ra left recursion rule. The first Ra sits on the parse stack whilst the second Ra representing the lhs gets ready for the reduce to take place. With each recurse reduction the rhs's popped Ra is freed up for recycling. After the Rxxx reduction, its 3 Ra also get recycled for use. On the parse stack there still remains 2 active Ra of Rs's rhs that remains to be recognized. If Rxxx was not present in the grammar, the Ra maximum use count would be 5: 2 direct and 2+1 indirect counts from Rxx.\fbreak @/ fsm (fsm-id "rules_use_cnt.lex" ,fsm-filename rules_use_cnt ,fsm-namespace NS_rules_use_cnt ,fsm-class Crules_use_cnt{ user-prefix-declaration #include "o2_externs.h" extern int MAX_USE_CNT_RxR (NS_yacco2_terminals::rule_def* Rule_use ,NS_yacco2_terminals::rule_def* Against_rule); *** user-declaration public: std::list rules_list_for_use_cnt_; NS_yacco2_terminals::rule_def* rule_def_; NS_yacco2_terminals::T_subrule_def* subrule_def_; void mark_recursion_rule_use(NS_yacco2_terminals::refered_rule* Refered_rule); yacco2::AST* bld_rule_s_use_skeleton(yacco2::AST* Rule_t); *** user-implementation void Crules_use_cnt::mark_recursion_rule_use (NS_yacco2_terminals::refered_rule* Refered_rule){ using namespace NS_yacco2_terminals; rule_in_stbl* rule_in_tbl = Refered_rule->Rule_in_stbl(); rule_def* rd = rule_in_tbl->r_def(); if(rd == rule_def_){ rd->recursive(YES); rd->lhs_use_cnt(1); } } /@ @*3 |bld_rule_s_use_skeleton|. @/ AST* Crules_use_cnt::bld_rule_s_use_skeleton(AST* Rule_t){ using namespace NS_yacco2_T_enum; set rules_use_cnt_filter; rules_use_cnt_filter.insert(T_Enum::T_T_subrule_def_); rules_use_cnt_filter.insert(T_Enum::T_rule_def_); rules_use_cnt_filter.insert(T_Enum::T_refered_rule_); tok_can_ast_functor rules_use_walk_functr; ast_postfix rules_use_walk(*Rule_t,&rules_use_walk_functr ,&rules_use_cnt_filter,ACCEPT_FILTER); tok_can rules_use_can(rules_use_walk); int x(0); CAbs_lr1_sym* sym = rules_use_can[x]; rule_def* rd(0); AST* lk_rr_t(0); AST* rr_t(0); AST* sr_t(0); AST* lk_sr_t(0); AST* r_t(0); for(;sym->enumerated_id() != LR1_Eog;++x,sym=rules_use_can[x]){ switch(sym->enumerated_id()){ case T_Enum::T_rule_def_:{ if(sr_t == 0) return 0;// no rhs with refered rules r_t = new AST(*sym); AST::join_pts(*r_t,*sr_t); return r_t; } case T_Enum::T_T_subrule_def_:{ if(rr_t == 0) break;// no refered rules AST* srt = new AST(*sym); AST::join_pts(*srt,*rr_t); lk_rr_t = 0; rr_t = 0; if(sr_t == 0){ sr_t = srt; lk_sr_t = srt; }else{ AST::join_sts(*lk_sr_t,*srt); lk_sr_t = srt; } break; } case T_Enum::T_refered_rule_:{ AST* rrt = new AST(*sym); if(rr_t == 0){ rr_t = rrt; lk_rr_t = rrt; }else{ AST::join_sts(*lk_rr_t,*rrt); lk_rr_t = rrt; } break; } }//switch }//for return 0; } *** /@ Build use skeletons per rule definition. As the container is of tree type, the first token is the ``start'' rule. I can get its tree node and breadth walk it for its brothers. The rules list for ``use count'' assessment is built: Rules vocabulary - ``start'' rule. The ``start'' rule is removed as it never appears within a rhs as per a grammar's definition. @/ op tok_can* can = (tok_can*)parser()->token_supplier(); AST* start_rule_t = can->ast(0); AST* t = start_rule_t; for(;t != 0;t=AST::get_younger_sibling(*t,1)){ rule_def* rd = (rule_def*)AST::content(*t); AST* use_skeleton_t = bld_rule_s_use_skeleton(t); if(use_skeleton_t != 0) rd->rule_use_skeleton(use_skeleton_t); if(t != start_rule_t) rules_list_for_use_cnt_.push_back(rd); } rule_def_ = 0; subrule_def_ = 0; *** } ,fsm-version "1.0",fsm-date "6 July 2007",fsm-debug "false" ,fsm-comments "Optimization: Count ``rules used'' \n to lower new / delete rule cycles while parsing.") @"/usr/local/yacco2/compiler/grammars/yacco2_T_includes.T" rules{ Rrules_use_cnt (){ -> Rrules eog } Rrules (){ -> Rrule -> Rrules Rrule } Rrule (){ -> Rrule_def Rsubrules } Rrule_def (){ -> "rule-def" { /@ Post the rule's used cnt within its definition to be used in generating the recycle tables. Remember the current rule is assessing its indirect rule usage. It is the rule usage definition that gets updated for its recycle table requirements and not the current rule. @/ op Crules_use_cnt* fsm = (Crules_use_cnt*)rule_info__.parser__->fsm_tbl__; fsm->rule_def_ = sf->p1__; std::list::iterator i = fsm->rules_list_for_use_cnt_.begin(); std::list::iterator ie = fsm->rules_list_for_use_cnt_.end(); for(;i != ie;++i){ rule_def* for_rule = *i; int use_cnt = MAX_USE_CNT_RxR(for_rule,fsm->rule_def_); if(for_rule->rhs_use_cnt() < use_cnt){ for_rule->rhs_use_cnt(use_cnt); } } *** } } Rsubrules (){ -> Rsubrule Rsubrule_s_used_rules_epi -> Rsubrules Rsubrule Rsubrule_s_used_rules_epi } Rsubrule (){ -> Rsubrule_def } Rsubrule_def (){ -> "subrule-def" { op Crules_use_cnt* fsm = (Crules_use_cnt*)rule_info__.parser__->fsm_tbl__; fsm->subrule_def_ = sf->p1__; *** } } Rsubrule_s_used_rules_epi (){ -> -> Rsubrule_s_used_rules } Rsubrule_s_used_rules (){ -> "refered-rule" { op Crules_use_cnt* fsm = (Crules_use_cnt*)rule_info__.parser__->fsm_tbl__; fsm->mark_recursion_rule_use(sf->p1__); *** } -> Rsubrule_s_used_rules "refered-rule" { op Crules_use_cnt* fsm = (Crules_use_cnt*)rule_info__.parser__->fsm_tbl__; fsm->mark_recursion_rule_use(sf->p2__); *** } } }// end of rules