@q file: fsm.w@> @q% Copyright Dave Bone 1998 - 2015@> @q% /*@> @q% This Source Code Form is subject to the terms of the Mozilla Public@> @q% License, v. 2.0. If a copy of the MPL was not distributed with this@> @q% file, You can obtain one at http://mozilla.org/MPL/2.0/.@> @q% */@> @** Finite state machine definition. @*2 |CAbs_fsm|.\fbreak It provides the basis for all grammar `fsm' definitions. Yacco2 generates a specific `fsm' per grammar derived from |CAbs_fsm|. The first 5 parameters are the grammar attributes extracted from the `fsm' construct of the grammar. Parameters |Gened_date| thru to |Start_state| are specifics from the compiling of the grammar. For-your-information, the date and time as to when the grammar was compiled is passed by |Gened_date|. |Start_state| parameter is the object address. |Start_state| is the ``S'' in your formal finite automaton definition. @+= class CAbs_fsm{ public:@/ virtual void op()=0; virtual bool failed()=0; yacco2::KCHARP id(); yacco2::KCHARP version(); yacco2::KCHARP date(); bool debug(); yacco2::KCHARP comments(); yacco2::KCHARP gened_date(); yacco2::State* start_state(); virtual ~CAbs_fsm(); virtual void reduce_rhs_of_rule@/ (yacco2::UINT Sub_rule_no,yacco2::Rule_s_reuse_entry** Recycled_rule)=0;@/ yacco2::Parser* parser(); void parser(yacco2::Parser& A); void find_a_recycled_rule (Per_rule_s_reuse_table* Reuse_rule_table ,Rule_s_reuse_entry** Reuse_rule_entry); void recycle_rule(Rule_s_reuse_entry* Rule_to_recycle); protected:@/ CAbs_fsm(yacco2::KCHARP Id@/ ,yacco2::KCHARP Version@/ ,yacco2::KCHARP Date@/ ,bool Debug@/ ,yacco2::KCHARP Comments@/ ,yacco2::KCHARP Gened_date@/ ,yacco2::State& Start_state@/ );@/ public:@/ yacco2::KCHARP id__;@/ yacco2::KCHARP version__;@/ yacco2::KCHARP date__;@/ bool debug__;@/ yacco2::KCHARP comments__;@/ yacco2::KCHARP gened_date__;@/ yacco2::State* start_state__;@/ yacco2::Parser* parser__;@/ };@/ @*3 Trapping of Premature Parsing Failures --- failed directive.\fbreak The ``failed'' directive within the ``fsm'' construct allows one to deal with premature aborts within a grammar. It makes it reeeeeeeal easy to trap errors instead of specifically trying to program within the grammar each potential abort position per T shift. It's a ``catch-all'' last chance to provide an error response back from a threaded grammar to their calling grammars, or to place an error within the error queue of a monolithic grammar. A failed example:\fbreak \fbreak \let\setuplistinghook = \linenumberedlisting \listing{"/usr/local/yacco2/diagrams/fsm_failed.txt"} \fbreak \fbreak @** Finite state machine implementation. @*2 |CAbs_fsm| and |~CAbs_fsm|.\fbreak Constructor and destructor of the finite state class. @= yacco2:: CAbs_fsm:: CAbs_fsm@/ (yacco2::KCHARP Id@/ ,yacco2::KCHARP Version@/ ,yacco2::KCHARP Date@/ ,bool Debug@/ ,yacco2::KCHARP Comments@/ ,yacco2::KCHARP Gened_date@/ ,yacco2::State& Start_state)@/ :id__(Id) ,version__(Version) ,date__(Date) ,gened_date__(Gened_date) ,debug__(Debug) ,comments__(Comments) ,start_state__(&Start_state) ,parser__(0) {} yacco2:: CAbs_fsm:: ~CAbs_fsm(){} @*2 Fsm implementation. @= yacco2::State* yacco2:: CAbs_fsm:: start_state(){ return start_state__; } yacco2::Parser* yacco2:: CAbs_fsm:: parser(){ return parser__; } void yacco2:: CAbs_fsm:: parser(yacco2::Parser& A){ parser__ = &A; } yacco2::KCHARP yacco2:: CAbs_fsm:: gened_date(){ return gened_date__; } yacco2::KCHARP yacco2:: CAbs_fsm:: id(){ return id__; } yacco2::KCHARP yacco2:: CAbs_fsm:: version(){ return version__; } yacco2::KCHARP yacco2:: CAbs_fsm:: date(){ return date__; } bool yacco2:: CAbs_fsm:: debug(){ return debug__; } yacco2::KCHARP yacco2:: CAbs_fsm:: comments(){ return comments__; }@/ @*2 |find_a_recycled_rule| and |recycle_rule|.\fbreak Each |fsm| is virtual and the concrete grammar's |fsm| gets gened up with its specific |reduce_rhs_of_rule|. It is here that the fetching of recycled rules are done. The popping of the parse stack by cleanup or a reduce operation recycles the rules. For the love of speed and environment, Recycle baby recycle! @= void CAbs_fsm::find_a_recycled_rule (Per_rule_s_reuse_table* Reuse_rule_table ,Rule_s_reuse_entry** Reuse_rule_entry){ reuse_rule_list* rrl(0); if(Reuse_rule_table->for_use_list_!= 0){ rrl = Reuse_rule_table->for_use_list_; (*Reuse_rule_entry) = rrl->reuse_rule_entry_; Reuse_rule_table->for_use_list_ = rrl->older_; }else{ (*Reuse_rule_entry) = new Rule_s_reuse_entry(); rrl = &(*Reuse_rule_entry)->its_linked_list_; rrl->reuse_rule_entry_= (*Reuse_rule_entry); rrl->per_rule_tbl_ptr_ = Reuse_rule_table; } fnd_rrl: rrl->older_ = 0; rrl->younger_ = 0; if(Reuse_rule_table->in_use_list_ != 0) { Reuse_rule_table->in_use_list_->younger_ = rrl; rrl->older_ = Reuse_rule_table->in_use_list_; Reuse_rule_table->in_use_list_ = rrl; }else{ Reuse_rule_table->in_use_list_ = rrl; } } void CAbs_fsm::recycle_rule(Rule_s_reuse_entry* Rule_to_recycle){ Per_rule_s_reuse_table* reuse_tbl = Rule_to_recycle->its_linked_list_.per_rule_tbl_ptr_; reuse_rule_list* iul = reuse_tbl->in_use_list_; reuse_rule_list* ful = reuse_tbl->for_use_list_; reuse_rule_list* rrl = &Rule_to_recycle->its_linked_list_; reuse_rule_list* older_rrl = rrl->older_; reuse_rule_list* younger_rrl = rrl->younger_; // break bonds from ``in use'' and reattach to ``for use'' rrl->younger_ = 0; rrl->older_ = reuse_tbl->for_use_list_; reuse_tbl->for_use_list_ = rrl; if(rrl == iul){// removal was end of iu list reuse_tbl->in_use_list_ = older_rrl; if(older_rrl != 0){ older_rrl->younger_ = 0; } return; } if(older_rrl == 0){// rechain the iu list younger_rrl->older_ = 0; return; } younger_rrl->older_ = older_rrl; older_rrl->younger_ = younger_rrl; }