void sooty::lexing::detail::fold_impl(std::set<base_lexer_ptr> visited_nodes, const base_lexer_ptr& lhs, const base_lexer_ptr& rhs) { if (!lhs || !rhs) return; if (visited_nodes.find(lhs) != visited_nodes.end()) return; visited_nodes.insert(lhs); if (lhs->type == base_lexer::lexer_type::marker) { fold_impl(visited_nodes, lhs->on_success, rhs); } else if (rhs->type == base_lexer::lexer_type::marker) { base_lexer_ptr saved_lhs = clone_tree(lhs); *lhs = *rhs; fold_impl(visited_nodes, lhs->on_success, saved_lhs); } // if lhs is partially equivalent to rhs, then we need to try rhs // if it fails, but try the one /after/ rhs if it succeeds else if ( partially_equivalent(lhs, rhs) ) { if (lhs->on_failure) append_failure(lhs->on_failure, rhs); else lhs->on_failure = rhs; if (lhs->on_success) fold_impl(visited_nodes, lhs->on_success, rhs->on_success); else lhs->on_success = rhs->on_success; } // rhs is partially equivalent to lhs, which means that we have to // test rhs first, *then* lhs. else if ( partially_equivalent(rhs, lhs) ) { base_lexer_ptr lhs_copy = clone_tree(lhs); *lhs = *rhs; visited_nodes.erase(lhs); fold_impl(visited_nodes, lhs, lhs_copy); } else if ( equivalent(lhs, rhs) ) { if (lhs->on_success) fold_impl(visited_nodes, lhs->on_success, rhs->on_success); else { lhs->on_success = rhs->on_success; if (lhs->on_failure) { append_failure(lhs->on_success, lhs->on_failure); lhs->on_failure = base_lexer_ptr(); } } } else { if (lhs->on_failure) fold_impl(visited_nodes, lhs->on_failure, rhs); else lhs->on_failure = rhs; } }
parse_node_t *clone_tree( parse_node_t *tokens ){ parse_node_t *ret = NULL; if ( tokens ){ ret = malloc( sizeof( *tokens )); *ret = *tokens; ret->down = clone_tree( ret->down ); ret->next = clone_tree( ret->next ); if ( ret->data ) ret->data = strdup( ret->data ); } return ret; }
lexer operator [](semantic_action action) const { static char _ = 0; detail::base_lexer_ptr marker(new detail::base_lexer(detail::base_lexer::lexer_type::marker, _, _)); detail::base_lexer_ptr actor(new detail::base_lexer(detail::base_lexer::lexer_type::actor, _, _)); actor->action = action; ++_; append_success(marker, clone_tree(this->base_lexer)); append_success(marker, actor); return lexer(marker); }
lexer operator * () const { detail::base_lexer_ptr new_lhs = clone_tree(this->base_lexer); detail::zero_or_more(new_lhs); return lexer(new_lhs); }