A toolkit for working with phylogenetic data.
v0.18.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
parser.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_IO_PARSER_H_
2 #define GENESIS_UTILS_IO_PARSER_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2017 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@h-its.org>
23  Exelixis Lab, Heidelberg Institute for Theoretical Studies
24  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
25 */
26 
35 
36 #include <assert.h>
37 #include <cctype>
38 #include <limits>
39 #include <stdexcept>
40 
41 namespace genesis {
42 namespace utils {
43 
44 // =================================================================================================
45 // Integer
46 // =================================================================================================
47 
55 template<class T>
57 {
58  T x = 0;
59 
60  if( ! source || ! isdigit( *source ) ) {
61  throw std::runtime_error(
62  "Expecting digit in " + source.source_name() + " at " + source.at() + "."
63  );
64  }
65 
66  while( source && isdigit( *source )) {
67  T y = *source - '0';
68 
69  if( x > ( std::numeric_limits<T>::max() - y ) / 10 ) {
70  throw std::overflow_error(
71  "Numerical overflow in " + source.source_name() + " at " + source.at() + "."
72  );
73  }
74 
75  x = 10 * x + y;
76  ++source;
77  }
78  return x;
79 }
80 
90 template<class T>
92 {
93  if( !source ) {
94  throw std::runtime_error(
95  "Expecting number in " + source.source_name() + " at " + source.at() + "."
96  );
97  }
98 
99  if( *source == '-' ) {
100  ++source;
101 
102  if( ! source || ! isdigit( *source ) ) {
103  throw std::runtime_error(
104  "Expecting digit in " + source.source_name() + " at " + source.at() + "."
105  );
106  }
107 
108  T x = 0;
109  while( source && isdigit( *source )) {
110  T y = *source - '0';
111 
112  if( x < ( std::numeric_limits<T>::min() + y ) / 10 ) {
113  throw std::underflow_error(
114  "Numerical underflow in " + source.source_name() + " at " + source.at() + "."
115  );
116  }
117 
118  x = 10 * x - y;
119  ++source;
120  }
121  return x;
122  }
123 
124  if( *source == '+' ) {
125  ++source;
126  }
127  return parse_unsigned_integer<T>(source);
128 }
129 
133 template<class T>
135 {
136  return parse_signed_integer<T>(source);
137 }
138 
139 // =================================================================================================
140 // Float
141 // =================================================================================================
142 
154 template<class T>
156 {
157  T x = 0.0;
158 
159  if( !source ) {
160  throw std::runtime_error(
161  "Expecting float number in " + source.source_name() + " at " + source.at() + "."
162  );
163  }
164 
165  // Sign
166  bool is_neg = false;
167  if( *source == '-' ){
168  is_neg = true;
169  ++source;
170  } else if( *source == '+' ) {
171  ++source;
172  }
173 
174  // Integer Part
175  bool found_mantisse = false;
176  while( source && isdigit( *source )) {
177  int y = *source - '0';
178  x *= 10;
179  x += y;
180  ++source;
181  found_mantisse = true;
182  }
183 
184  // Decimal part
185  if( source && *source == '.' ) {
186  ++source;
187 
188  if( ! source || ! isdigit( *source ) ) {
189  throw std::runtime_error(
190  "Invalid float number in " + source.source_name() + " at " + source.at() + "."
191  );
192  }
193 
194  T pos = 1.0;
195  while( source && isdigit( *source )) {
196  pos /= 10.0;
197  int y = *source - '0';
198  x += y * pos;
199  ++source;
200  found_mantisse = true;
201  }
202  }
203 
204  // We need to have some digits before the exponential part.
205  if( ! found_mantisse ) {
206  throw std::runtime_error(
207  "Invalid float number in " + source.source_name() + " at " + source.at() + "."
208  );
209  }
210 
211  // Exponential part
212  if( source && tolower(*source) == 'e' ) {
213  ++source;
214 
215  // Read the exp. If there are no digits, this throws.
216  int e = parse_signed_integer<int>( source );
217 
218  if( e != 0 ) {
219  T base;
220  if( e < 0 ) {
221  base = 0.1;
222  e = -e;
223  } else {
224  base = 10;
225  }
226 
227  while( e != 1 ) {
228  if( ( e & 1 ) == 0 ) {
229  base = base * base;
230  e >>= 1;
231  } else {
232  x *= base;
233  --e;
234  }
235  }
236  x *= base;
237  }
238  }
239 
240  // Sign
241  if (is_neg) {
242  x = -x;
243  }
244 
245  return x;
246 }
247 
248 // =================================================================================================
249 // General Number String
250 // =================================================================================================
251 
262 std::string parse_number_string(
263  utils::InputStream& source
264 );
265 
266 // =================================================================================================
267 // String
268 // =================================================================================================
269 
295 std::string parse_quoted_string(
296  utils::InputStream& source,
297  bool use_escapes = true,
298  bool use_twin_quotes = false,
299  bool include_qmarks = false
300 );
301 
302 } // namespace utils
303 } // namespace genesis
304 
305 #endif // include guard
std::string parse_quoted_string(utils::InputStream &source, bool use_escapes, bool use_twin_quotes, bool include_qmarks)
Read a string in quotation marks from a stream and return it.
Definition: parser.cpp:116
T parse_unsigned_integer(utils::InputStream &source)
Read an unsigned integer from a stream and return it.
Definition: parser.hpp:56
std::string at() const
Return a textual representation of the current input position in the form "line:column".
T parse_integer(utils::InputStream &source)
Alias for parse_signed_integer().
Definition: parser.hpp:134
T parse_signed_integer(utils::InputStream &source)
Read a signed integer from a stream and return it.
Definition: parser.hpp:91
std::string parse_number_string(utils::InputStream &source)
Read a general number string from an input stream.
Definition: parser.cpp:48
std::string source_name() const
Get the input source name where this stream reads from.
T parse_float(utils::InputStream &source)
Read a floating point number from a stream and return it.
Definition: parser.hpp:155
Stream interface for reading data from an InputSource, that keeps track of line and column counters...