// Copyright {Jagger Software Limited} 2003 #include "grammar/non_terminal_symbol_definition.hpp" #include "container/for_all.hpp" #include "grammar/out_of_range_exception.hpp" #include "grammar/production_symbol_definition.hpp" #include "ownership/deleter.hpp" #include "grammar/visitor.hpp" #include #include using namespace ::container; using namespace ::ownership; using namespace ::std; namespace grammar // non_terminal_symbol_definition - 'tors { // When a tree symbol is generated from a production-symbol-definition or a // terminal-symbol it refers to their symbol-definitions which naturally have // unique keys. However, a tree-building-parser might need to grow an "empty" // tree symbol for an optional symbol that was _not_ matched (this ensures // the number of branches always equals the number of qualified-symbols // in the associated production and makes trees _much_ easier to use). // Hence, (yes I'll stop soon) an empty tree symbol might need to refer to the // non-terminal rather than to one of its productions. // And so, non_terminal_symbol_definitions need keys too. non_terminal_symbol_definition::non_terminal_symbol_definition ( const key_type & key, const char * name, size_t fixed_capacity ) : symbol_definition(key, name) , productions(fixed_capacity) { } non_terminal_symbol_definition::~non_terminal_symbol_definition() { for_all(productions, deleter()); } } namespace grammar // non_terminal_symbol_definition - building { void non_terminal_symbol_definition::push_back ( key_type key, const qualified_symbol_definition * begin, const qualified_symbol_definition * end ) { typedef production_symbol_definition resource_type; auto_ptr production(new resource_type(key, *this, begin, end)); productions.push_back(production.get()); production.release(); } } namespace grammar // non_terminal_symbol_definition - subscripting { size_t non_terminal_symbol_definition::size() const { return productions.size(); } const production_symbol_definition & non_terminal_symbol_definition::operator[](size_t at) const { range_check(at); return *productions[at]; } } namespace grammar // non_terminal_symbol_definition - validating { void non_terminal_symbol_definition::range_check(size_t at) const { if (at >= size()) { throw out_of_range_exception(typeid(*this), name, at, size()); } } } namespace grammar // non_terminal_symbol_definition - visiting { bool non_terminal_symbol_definition::accept(::grammar::visitor & visitor) const { return visitor.visit(*this); } } namespace grammar // non_terminal_symbol_definition - streaming { void non_terminal_symbol_definition::write(ostream & out) const { out << name << ':' << endl; for (size_t at = 0; at != size(); ++at) { out << (*this)[at] << '\n'; } } }