#include <boost/spirit.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <stack>

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<void, const char *, const char *> grammar_cb;
typedef function2<void, error_t, const char *> error_cb;
struct record_grammar:public grammar<record_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<class ScannerT>
  struct definition{
    rule<ScannerT> identifier;
    rule<ScannerT> string_literal;
    rule<ScannerT> prop_decl;
    rule<ScannerT> prop_list;
    rule<ScannerT> record_list;
    rule<ScannerT> record;

    struct handle_error{
      handle_error(error_cb &cb):cb(cb){
      };

      error_status<> operator()(ScannerT const &scan, parser_error<error_t, const char*> error) const{
        cb(error.descriptor, error.where);
        return error_status<>();
      }
      error_cb &cb;
   };


    typedef assertion<error_t> 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<error_t> 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<ScannerT> 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<property_info> properties;
  vector<record_info> 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<record_info>::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<property_info>::const_iterator it = r.properties.begin();
      it != r.properties.end(); it++){
      cout << "\t\t" << it->name << "=" << it->value << endl;
    }
    for(vector<record_info>::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_info> 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;
}
