// Copyright {Jagger Software Limited} 2003 #if !defined GRAMMAR_TOOLS_TREE_BUILDING_PARSEABLE_SOURCE_INCLUDED || \ defined GRAMMAR_TOOLS_TREE_BUILDING_PARSEABLE_SOURCE_TEMPLATE_INCLUDED #error "grammar_tools/tree_building_parseable_source-template.hpp" #included directly #endif #define GRAMMAR_TOOLS_TREE_BUILDING_PARSEABLE_SOURCE_TEMPLATE_INCLUDED #include "ast/scoped_symbol.hpp" #include "contract/invariant.hpp" #include "grammar/non_terminal_symbol_definition.hpp" #include "grammar/production_symbol_definition.hpp" #include "grammar/qualified_symbol_definition.hpp" namespace grammar_tools // tree_building_parseable_source - 'tor { template tree_building_parseable_source::tree_building_parseable_source(iterator start, iterator finish) : parseable_source(start, finish) , tree() , symbol_factory() { } } namespace grammar_tools // tree_building_parseable_source - raison d'etre { template const typename tree_building_parseable_source::symbol_type * tree_building_parseable_source::extract_tree() { return !tree.empty() ? tree_lop() : 0; } } namespace grammar_tools // lexical_parser - parsing { template bool tree_building_parseable_source::parse ( const ::grammar::production_symbol_definition & to_parse, ::grammar::visitor & visitor ) { tree_grow(symbol_factory.create_production(to_parse, position())); size_t at = 0; while (at != to_parse.size() && to_parse[at].accept(visitor)) { ++at; } return at == to_parse.size(); } template bool tree_building_parseable_source::parse ( const ::grammar::qualified_symbol_definition & to_parse, ::grammar::visitor & visitor ) { using ::grammar::bound; bound count = 0; const bound lower_bound = to_parse.multiplicity.lower_bound; while (count != lower_bound && to_parse.symbol_definition.accept(visitor)) { tree_graft(); ++count; } if (count == lower_bound) { const bound upper_bound = to_parse.multiplicity.upper_bound; while (count != upper_bound && to_parse.symbol_definition.accept(visitor)) { tree_graft(); ++count; } } static const bound zero = 0; if (lower_bound == zero && count == zero) { // Put an empty symbol-element into the tree to ensure // the number of branches always equals the number of // qualified symbols in the associated production. // This makes using the tree _much_ easier. tree_grow(symbol_factory.create_production(to_parse.symbol_definition, position())); tree_graft(); return true; } else if (count >= lower_bound) { return true; } else { symbol_factory.destroy_production(tree_lop()); // NOT exception safe return false; } } } namespace grammar_tools // tree_building_parseable_source - repositioning { template bool tree_building_parseable_source::reposition ( const ::grammar::symbol_definition & parsed, iterator end_position, iterator new_position ) { // The end_position does not necessarily equal the new_position. // In a syntactic parse, the end_position designates the next // lexical token whereas the new_position designates the next // syntactic token. This allows the syntactic parser to // skip "lexical" tokens such as whitespace, comments, newlines. INVARIANT(!tree.empty()); if (position() != end_position) // something has been read { tree_grow(symbol_factory.create_terminal(parsed, position(), end_position)); position(new_position); return true; } else { return false; } } } namespace grammar_tools // tree_building_parseable_source - tree primitives { template void tree_building_parseable_source::tree_grow(symbol_type * leaf) { ::ast::scoped_symbol branch(symbol_factory, leaf); tree.push(branch.get()); branch.release(); } template typename tree_building_parseable_source::symbol_type * tree_building_parseable_source::tree_lop() { INVARIANT(!tree.empty()); symbol_type * lopped = tree.top(); tree.pop(); return lopped; } template void tree_building_parseable_source::tree_graft() { ::ast::scoped_symbol branch(symbol_factory, tree_lop()); INVARIANT(!tree.empty()); tree.top()->push_back(branch.get()); branch.release(); } }