#include #include #include #include #include #include #include using namespace boost::spirit; using namespace boost; using namespace std; struct error{ enum _error{ NONE, UNTERMINATED_QUOTE, MISSING_OPEN_BRACKET, MISSING_CLOSE_BRACKET, MISSING_RECORD_NAME, MISSING_EQUAL, MISSING_PROPERTY_VALUE }; static const char *message(_error e){ switch(e){ case NONE: return "None"; case UNTERMINATED_QUOTE: return "Missing end quote in string literal"; case MISSING_OPEN_BRACKET: return "Expected '{'"; case MISSING_CLOSE_BRACKET: return "Expected '}'"; case MISSING_RECORD_NAME: return "Expected a record name"; case MISSING_EQUAL: return "Expected '='"; case MISSING_PROPERTY_VALUE: return "Expected property value"; } } }; typedef error::_error error_t; typedef function2 grammar_cb; typedef function2 error_cb; struct record_grammar:public grammar{ record_grammar( grammar_cb &property_name, grammar_cb &property_value, grammar_cb &end_property, grammar_cb &record_type, grammar_cb &record_name, grammar_cb &end_record, error_cb &error): property_name(property_name), property_value(property_value), end_property(end_property), record_type(record_type), record_name(record_name), end_record(end_record), error(error){ } template struct definition{ rule identifier; rule string_literal; rule prop_decl; rule prop_list; rule record_list; rule record; struct handle_error{ handle_error(error_cb &cb):cb(cb){ }; error_status<> operator()(ScannerT const &scan, parser_error error) const{ cb(error.descriptor, error.where); return error_status<>(); } error_cb &cb; }; typedef assertion my_assertion_t; definition(const record_grammar &self){ my_assertion_t expect_quote(error::UNTERMINATED_QUOTE); my_assertion_t expect_open_bracket(error::MISSING_OPEN_BRACKET); my_assertion_t expect_close_bracket(error::MISSING_CLOSE_BRACKET); my_assertion_t expect_name(error::MISSING_RECORD_NAME); my_assertion_t expect_equal(error::MISSING_EQUAL); my_assertion_t expect_property_value(error::MISSING_PROPERTY_VALUE); guard my_guard; identifier = lexeme_d[ alpha_p >> *(alnum_p | ch_p('_') ) ]; string_literal = lexeme_d[ ch_p('"') >> *( (anychar_p - ch_p('"') ) | str_p("\\\"") ) >> expect_quote( ch_p('"') ) ]; prop_decl = ( identifier[self.property_name] >> expect_equal(ch_p('=')) >> expect_property_value(string_literal[self.property_value]) )[self.end_property]; prop_list = prop_decl >> *(ch_p(',') >> prop_decl); record_list = record >> *(ch_p(',') >> record); record = my_guard( ( identifier[self.record_type] >> expect_name(identifier[self.record_name]) >> expect_open_bracket(ch_p('{')) >> !( ( prop_list >> !(ch_p(',') >> record_list) ) | record_list ) >> expect_close_bracket(ch_p('}')) )[self.end_record] )[handle_error(self.error)]; }; rule const& start(){return record_list;} }; grammar_cb &property_name; grammar_cb &property_value; grammar_cb &end_property; grammar_cb &record_type; grammar_cb &record_name; grammar_cb &end_record; error_cb &error; }; struct property_info{ string name, value; }; struct record_info{ string type; string name; vector properties; vector sub_records; }; class document{ public: document(){ record_stack.push(record_info()); _error_code = error::NONE; _error_location = ""; } parse_info<> parse(const std::string &data){ grammar_cb property_name_f(bind(&document::property_name, this, _1,_2)); grammar_cb property_value_f(bind(&document::property_value, this, _1,_2)); grammar_cb end_property_f(bind(&document::end_property, this, _1,_2)); grammar_cb record_type_f(bind(&document::record_type, this, _1,_2)); grammar_cb record_name_f(bind(&document::record_name, this, _1,_2)); grammar_cb end_record_f(bind(&document::end_record, this, _1, _2)); error_cb error_f(bind(&document::error, this, _1, _2)); record_grammar g( property_name_f, property_value_f, end_property_f, record_type_f, record_name_f, end_record_f, error_f); parse_info<> info = boost::spirit::parse(data.c_str(), g >> eps_p, space_p); return info; } const record_info & result(){ return record_stack.top(); } error_t error_code() const{ return _error_code; } const char *error_location() const{ return _error_location; } void print(){ for(vector::const_iterator it = record_stack.top().sub_records.begin(); it != record_stack.top().sub_records.end(); it++){ print("", *it); } } private: void print(const string &prefix, const record_info &r){ cout << prefix << "." << r.name << endl; cout << "\ttype:" << r.type << endl; cout << "\tproperties(" << r.properties.size() << "):" << endl; for(vector::const_iterator it = r.properties.begin(); it != r.properties.end(); it++){ cout << "\t\t" << it->name << "=" << it->value << endl; } for(vector::const_iterator it = r.sub_records.begin(); it != r.sub_records.end(); it++){ print(prefix + "." + r.name, *it); } } void property_name(const char *start, const char *end){ current_property.name = string(start, end); } void property_value(const char *start, const char *end){ current_property.value = string(start, end); } void end_property(const char *start, const char *end){ record_stack.top().properties.push_back(current_property); } void record_type(const char *start, const char *end){ record_stack.push(record_info()); record_stack.top().type = string(start, end); } void record_name(const char *start, const char *end){ record_stack.top().name = string(start, end); } void end_record(const char *start, const char *end){ record_info top = record_stack.top(); record_stack.pop(); record_stack.top().sub_records.push_back(top); } void error(error_t code, const char *location){ _error_code = code; _error_location = location; } stack record_stack; property_info current_property; error_t _error_code; const char *_error_location; }; int main(){ string input; string temp; while(getline(cin, temp)){ input += temp; } document d; parse_info<> info = d.parse(input); if(d.error_code() != error::NONE){ cout << "Encountered error:" << error::message(d.error_code()) << endl; cout << "at location: " << d.error_location() << endl; return -1; } if(!info.full){ cout << "Error found at location: " << info.stop << endl; return -2; }else{ d.print(); } return 0; }