The Gaudi Framework  v33r1 (b1225454)
Parser.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 // ============================================================================
12 // STD:
13 // ============================================================================
14 #include <fstream>
15 // ============================================================================
16 // BOOST:
17 // ============================================================================
18 #include <boost/filesystem.hpp>
19 #include <boost/format.hpp>
20 // ============================================================================
21 #include "Grammar.h"
22 #include "IncludedFiles.h"
23 #include "Iterator.h"
24 #include "Messages.h"
25 #include "Node.h"
26 #include "Parser.h"
27 #include "Utils.h"
28 // ============================================================================
29 // Gaudi:
30 // ============================================================================
32 // ============================================================================
33 namespace classic = boost::spirit::classic;
34 namespace bf = boost::filesystem;
35 namespace gp = Gaudi::Parsers;
36 namespace gpu = Gaudi::Parsers::Utils;
37 namespace qi = boost::spirit::qi;
38 // ============================================================================
39 namespace {
40  // ============================================================================
41  void GetLastLineAndColumn( std::ifstream& ifs, int& line, int& column ) {
42  int n = 0;
43  std::string str;
44  while ( !ifs.eof() ) {
45  getline( ifs, str );
46  ++n;
47  }
48  line = n;
49  column = str.length() + 1;
50  ifs.clear();
51  ifs.seekg( 0, ifs.beg );
52  }
53 
54  template <typename Grammar>
55  bool ParseStream( std::ifstream& stream, const std::string& stream_name, gp::Messages* messages, gp::Node* root ) {
56 
57  int last_line, last_column;
58 
59  GetLastLineAndColumn( stream, last_line, last_column );
60 
62 
63  BaseIterator in_begin( input.begin() );
64  // convert input iterator to forward iterator, usable by spirit parser
65  ForwardIterator fwd_begin = boost::spirit::make_default_multi_pass( in_begin );
66  ForwardIterator fwd_end;
67 
68  // wrap forward iterator with position iterator, to record the position
69 
70  Iterator position_begin( fwd_begin, fwd_end, stream_name );
71  Iterator position_end;
72 
73  Grammar gr;
74  gp::SkipperGrammar<Iterator> skipper;
75 
76  root->value = stream_name;
77  bool result = qi::phrase_parse( position_begin, position_end, gr, skipper, *root );
78 
79  const IteratorPosition& pos = position_begin.get_position();
80  if ( result && ( pos.line == last_line ) && ( pos.column == last_column ) ) { return true; }
81 
82  messages->AddError( gp::Position( stream_name, pos.line, pos.column ), "parse error" );
83  return false;
84  }
85 
86  // ============================================================================
87  template <typename Grammar>
88  bool ParseFile( const gp::Position& from, const std::string& filename, const std::string& search_path,
89  gp::IncludedFiles* included, gp::Messages* messages, gp::Node* root ) {
90  std::string search_path_with_current_dir = gpu::replaceEnvironments( search_path );
91  if ( !from.filename().empty() ) { // Add current file directory to search_path
92  bf::path file_path( from.filename() );
93  search_path_with_current_dir =
94  file_path.parent_path().string() +
95  ( search_path_with_current_dir.empty() ? "" : ( "," + search_path_with_current_dir ) );
96  }
97  std::string absolute_path =
99 
100  if ( absolute_path.empty() ) {
101  messages->AddError( from, "Couldn't find a file " + filename + " in search path '" +
102  search_path_with_current_dir + "'" );
103  return false;
104  }
105  const gp::Position* included_from;
106  if ( !included->GetPosition( absolute_path, &included_from ) ) {
107  included->AddFile( absolute_path, from );
108  std::ifstream file{absolute_path};
109  if ( !file.is_open() ) {
110  messages->AddError( from, "Couldn't open a file " + filename );
111  return false;
112  }
113  return ParseStream<Grammar>( file, absolute_path, messages, root );
114  } else {
115  assert( included_from != NULL );
116  messages->AddWarning( from, str( boost::format( "File %1% already included from %2%" ) % absolute_path %
117  included_from->ToString() ) );
118  return true;
119  }
120  }
121  // ============================================================================
122 } // namespace
123 // ============================================================================
124 bool gp::Parse( const std::string& filename, const std::string& search_path, IncludedFiles* included,
125  Messages* messages, Node* root ) {
126  return Parse( Position(), filename, search_path, included, messages, root );
127 }
128 // ============================================================================
129 bool gp::Parse( const Position& from, const std::string& filename, const std::string& search_path,
130  IncludedFiles* included, Messages* messages, Node* root ) {
132  return ParseFile<Grammar>( from, filename, search_path, included, messages, root );
133 }
134 
135 // ============================================================================
136 bool gp::ParseUnits( const Position& from, const std::string& filename, const std::string& search_path,
137  IncludedFiles* included, Messages* messages, Node* root ) {
139  return ParseFile<Grammar>( from, filename, search_path, included, messages, root );
140 }
141 // ============================================================================
T empty(T... args)
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
bool ParseUnits(const Position &from, const std::string &filename, const std::string &search_path, IncludedFiles *included, Messages *messages, Node *root)
Definition: Parser.cpp:136
static std::string find_file_from_list(const std::string &logical_file_name, const std::string &search_list, SearchType search_type=LocalSearch)
T getline(T... args)
std::string::const_iterator BaseIterator
Definition: Iterator.h:26
std::string replaceEnvironments(const std::string &input)
Definition: Utils.cpp:28
T seekg(T... args)
boost::spirit::multi_pass< BaseIterator > ForwardIterator
Definition: Iterator.h:27
STL class.
T eof(T... args)
bool Parse(const std::string &filename, const std::string &search_path, IncludedFiles *included, Messages *messages, Node *root)
Definition: Parser.cpp:124
T clear(T... args)
T length(T... args)
boost::spirit::classic::position_iterator2< ForwardIterator > Iterator
Definition: Iterator.h:28
boost::spirit::classic::file_position_base< std::string > IteratorPosition
Definition: Iterator.h:29
STL class.