Awali
Another Weighted Automata library
lr_parse_number.hh
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2022 Sylvain Lombardy, Victor Marsault, Jacques Sakarovitch
3 //
4 // Awali is a free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #ifndef AWALI_STTC_LR_PARSE_NUMBER_HH
18 #define AWALI_STTC_LR_PARSE_NUMBER_HH
19 
20 #include<complex>
21 #include<iostream>
22 
24 #include<awali/common/qfraction.cc>
25 
26 
27 /* In this file, there is two kind of functions.
28  * - lr_scan_..(s,p,..) looks how many characters left of position p in string s
29  * can be eaten to the described purposes.
30  * It returns the number of characters found.
31  * Parameter p, a reference to an int, is decreased by that number.
32  *
33  * - lr_parse_<type> parses from left to right an instance of <type>
34  * Generally does not allow the empty string to be parsed but each function
35  * usually allows two optional parameters `allow_empty` and `value_if_empty`
36  * to control this behavior.
37  */
38 
39 namespace awali {
40 namespace sttc {
41 namespace internal {
42 
50  unsigned
51  lr_scan_one(std::string const& s, size_t& p, char const* t)
52  {
53  if (p<=0)
54  return 0;
55  char c;
56  for (unsigned x = 0; (c = t[x]) != '\0'; x++)
57  if (c == s[p-1]) {
58  --p;
59  return 1;
60  }
61  return 0;
62  }
63 
64 
75  char
76  lr_parse_one(std::string const& s, size_t& p, char const* t,
77  bool allow_empty = false, char value_if_empty = '\0')
78  {
79  if (lr_scan_one(s,p,t))
80  return s[p];
81  else if (allow_empty)
82  return value_if_empty;
83 
84  std::string s2;
85  if (p<=6)
86  s2 = s.substr(p);
87  else
88  s2 = ".."+s.substr(p-4,4);
89  throw parse_exception("Could not parse a char in \"" + std::string(t)
90  + "\", right of position " + std::to_string(p)
91  + " in string \"" + s
92  + "\", i.e., starting from the right of \"" + s2
93  + "\".");
94  }
95 
96 
104  unsigned
105  lr_scan_digits(std::string const& s, size_t& p)
106  {
107  int i = p;
108  while (i>0 && std::isdigit(static_cast<unsigned char>(s[i-1])))
109  --i;
110  unsigned res = (p-i);
111  p = i;
112  return res;
113  }
114 
115 
130  unsigned
131  lr_parse_uint(std::string const& s, size_t& p, bool allow_empty=false,
132  unsigned value_if_empty = 0)
133  {
134  size_t i = p;
135  if (lr_scan_digits(s,i)) {
136  std::stringstream ss (s.substr(i,p-i));
137  unsigned x;
138  ss >> x;
139  p=i;
140  return x;
141  }
142  if (allow_empty)
143  return value_if_empty;
144  std::string s2;
145  if (p<=6)
146  s2 = s.substr(p);
147  else
148  s2 = ".."+s.substr(p-4,4);
149  throw parse_exception("Could not parse an unsigned integer right of position "
150  + std::to_string(p)+" in string \"" + s
151  + "\", i.e., starting from the right of \"" + s2
152  + "\".");
153  }
154 
155 
156  //
157  unsigned
158  lr_scan_sign(std::string const& s, size_t& p)
159  {
160  return lr_scan_one(s,p, "+-");
161  }
162 
163  char
164  lr_parse_sign(std::string const& s, size_t& p, bool allow_empty=true,
165  char value_if_empty='\0')
166  {
167  return lr_parse_one(s,p, "+-", allow_empty, value_if_empty);
168  }
169 
170 
171  unsigned
172  lr_scan_e(std::string const& s, size_t& p)
173  {
174  return lr_scan_one(s,p,"eE");
175  }
176 
178  char
179  lr_parse_e(std::string const& s, size_t& p, bool allow_empty=true,
180  char value_if_empty='\0')
181  {
182  return lr_parse_one(s,p,"eE", allow_empty, value_if_empty);
183  }
184 
185 
186  unsigned
187  lr_scan_dot(std::string const& s, size_t& p) {
188  return lr_scan_one(s,p,".");
189  }
190 
191 
192  char
193  lr_parse_dot(std::string const& s, size_t& p, bool allow_empty=true,
194  char value_if_empty='\0') {
195  return lr_parse_one(s,p,".", allow_empty, value_if_empty);
196  }
197 
198 
199 // unsigned
200 // lr_scan_decimal(std::string const& s, size_t& p)
201 // {
202 // unsigned res = 0;
203 // if (res += lr_scan_digits(s,p)) {
204 // if (res += lr_scan_dot(s,p))
205 // res += lr_scan_digits(s,p);
206 // res += lr_scan_sign(s,p);
207 // return res;
208 // }
209 // else
210 // return res;
211 // }
212 
213 
214  unsigned
215  lr_scan_int(std::string const& s, size_t& p)
216  {
217  unsigned res = 0;
218  if (res += lr_scan_digits(s,p))
219  return (res+lr_scan_sign(s,p));
220  else
221  return false;
222  }
223 
238  int
239  lr_parse_int(std::string const& s, size_t& p, bool allow_empty=false,
240  int value_if_empty = 0)
241  {
242  size_t i = p;
243  if (lr_scan_int(s,i)) {
244  std::stringstream ss (s.substr(i,p-i));
245  int x;
246  ss >> x;
247  p=i;
248  return x;
249  }
250  if (allow_empty)
251  return value_if_empty;
252  std::string s2;
253  if (p<=6)
254  s2 = s.substr(p);
255  else
256  s2 = ".."+s.substr(p-4,4);
257  throw parse_exception("Could not parse an integer right of position "
258  + std::to_string(p)+" in string \"" + s
259  + "\", i.e., starting from the right of \"" + s2
260  + "\".");
261  }
262 
263 
264  unsigned
265  lr_scan_double(std::string const& s, size_t& pp)
266  {
267  size_t p = pp;
268  bool right_digits = lr_scan_digits(s,p);
269  if (right_digits)
270  lr_scan_sign(s,p);
271  bool e = lr_scan_e(s,p);
272  if (e) {
273  if (!right_digits)
274  return 0;
275  else
276  right_digits = lr_scan_digits(s,p);
277  }
278  bool dot = lr_scan_dot(s,p);
279  bool left_digits = dot ? lr_scan_digits(s,p) : false;
280  if (right_digits || dot || left_digits) {
281  lr_scan_sign(s,p);
282  unsigned res = pp-p;
283  pp=p;
284  return res;
285  }
286  return 0;
287  }
288 
289 
290  unsigned
291  lr_scan_complex(std::string const& s, size_t& pp)
292  {
293  size_t p = pp;
294  bool imag = lr_scan_one(s,p,"i");
295  bool sign = false;
296  if (lr_scan_double(s,p)) {
297  if (s[p] == '+' || s[p] == '-')
298  sign = true;
299  }
300  else {
301  if (imag) {
302  if(lr_scan_sign(s,p))
303  sign = true;
304  }
305  else /* We failed to parse anything */
306  return 0;
307  }
308 
309  if (sign) {
310  if ( imag || lr_scan_one(s,p,"i") )
311  if ( !lr_scan_double(s,p) )
312  lr_scan_sign(s,p);
313  }
314  unsigned res = pp-p;
315  pp=p;
316  return res;
317  }
318 
319 
320  static unsigned
321  powten(unsigned i) {
322  if (i == 0)
323  return 1;
324  unsigned x = powten(i/2);
325  x = x*x;
326  if (i%2)
327  return x;
328  else
329  return x*10;
330  }
331 
332 
353  lr_parse_qfraction(std::string const& s, size_t& p, bool allow_empty=false,
354  q_fraction_t value_if_empty = {1,1})
355  {
356  size_t pp = p;
357  q_fraction_t::den_t den = lr_parse_uint(s, pp, true);
358  q_fraction_t::num_t num = 1;
359  if ((p!=pp) && lr_parse_one(s, pp, "/", true))
360  num = lr_parse_int(s,pp);
361  else { /* No denominator */
362  num = den;
363  den = 1u;
364  if (lr_parse_sign(s,pp,true)) { /* integer */
365  if (s[pp] == '-')
366  num = -num;
367  }
368  else if (lr_parse_dot(s, pp, true)) { /* decimal */
369  den = pow(10,p-(pp+1));
370  num = num + den*lr_parse_int(s,pp,true);
371  }
372  }
373 
374  if (p != pp) {
375  p = pp;
376  return {num,den};
377  }
378 
379  if (allow_empty)
380  return value_if_empty;
381  std::string s2;
382  if (p<=6)
383  s2 = s.substr(p);
384  else
385  s2 = ".."+s.substr(p-4,4);
386  throw parse_exception("Could not parse a q fraction right of position"
387  + std::to_string(p) + " in string \"" + s +
388  "\", i.e., starting from the right of \"" + s2 + "\".");
389  }
390 
391 
408  double
409  lr_parse_double(std::string const& s, size_t& p, bool allow_empty=false,
410  double value_if_empty = 0)
411  {
412  size_t i = p;
413  if (lr_scan_double(s,i)) {
414  std::stringstream ss (s.substr(i,p-i));
415  double d;
416  ss >> d;
417  p=i;
418  return d;
419  }
420  if (allow_empty)
421  return value_if_empty;
422 
423  std::string s2;
424  if (p<=6)
425  s2 = s.substr(0,p);
426  else
427  s2 = ".."+s.substr(p-4,4);
428  throw parse_exception("Could not parse a floating point number right of"
429  " position " + std::to_string(p) + " in string \""
430  + s + "\", i.e., starting from the right of \"" + s2
431  + "\".");
432  }
433 
434 
457  std::complex<double>
458  lr_parse_complex(std::string const& s, size_t& p, bool allow_empty=false,
459  std::complex<double> value_if_empty = {0,0})
460  {
461  size_t i = p;
462  if ( lr_scan_complex(s,i) ) {
463  size_t j = p;
464  double imag = 0;
465  double real = 0;
466  for (int x = 0; (x<2 && j>i) ; x++) {
467  if (lr_scan_one(s,j,"i")) { /* Parsing the imaginary part*/
468  size_t k = j;
469  imag = lr_parse_double(s,j, true, 1); // We allow empty string which
470  // means value 1.0
471  if (k == j && lr_scan_sign(s,j) && s[j] == '-') // treats the case
472  imag = -1*imag; // "+i" and "-i"
473  }
474  else
475  real = lr_parse_double(s,j);
476  }
477  p=i;
478  return {real,imag};
479  }
480  if (allow_empty)
481  return value_if_empty;
482 
483  std::string s2;
484  if (p<=6)
485  s2 = s.substr(p);
486  else
487  s2 = ".."+s.substr(p-4,4);
488  throw parse_exception("Could not parse a complex number right of position "
489  + std::to_string(p) + " in string \"" + s
490  + "\", i.e., starting from the right of \"" + s2
491  + "\".");
492  }
493 
494 
495 
496 } // end of namespace awali::sttc::internal
497 } // end of namespace awali::sttc
498 } // end of namespace awali
499 
500 #endif // AWALI_STTC_LR_PARSE_NUMBER_HH
Definition: qfraction.hh:26
int num_t
Definition: qfraction.hh:28
unsigned int den_t
Definition: qfraction.hh:29
The semiring of complex numbers.
Definition: c.hh:44
unsigned lr_scan_double(std::string const &s, size_t &pp)
Definition: lr_parse_number.hh:265
unsigned lr_scan_digits(std::string const &s, size_t &p)
Scans for as many [0-9] digits as possible, left of position p in string s.
Definition: lr_parse_number.hh:105
unsigned lr_scan_int(std::string const &s, size_t &p)
Definition: lr_parse_number.hh:215
double lr_parse_double(std::string const &s, size_t &p, bool allow_empty=false, double value_if_empty=0)
Reads a double left of position p in string, by using as many characters as possible.
Definition: lr_parse_number.hh:409
int lr_parse_int(std::string const &s, size_t &p, bool allow_empty=false, int value_if_empty=0)
Reads an int written in decimal left of position p in string s, by using as many characters as possib...
Definition: lr_parse_number.hh:239
char lr_parse_e(std::string const &s, size_t &p, bool allow_empty=true, char value_if_empty='\0')
Parses the radix point.
Definition: lr_parse_number.hh:179
q_fraction_t lr_parse_qfraction(std::string const &s, size_t &p, bool allow_empty=false, q_fraction_t value_if_empty={1, 1})
Reads a q_fraction_t left of position p in string, by using as many characters as possible.
Definition: lr_parse_number.hh:353
unsigned lr_scan_sign(std::string const &s, size_t &p)
Definition: lr_parse_number.hh:158
unsigned lr_scan_one(std::string const &s, size_t &p, char const *t)
Scans for a character in t left of position p in s.
Definition: lr_parse_number.hh:51
unsigned lr_scan_complex(std::string const &s, size_t &pp)
Definition: lr_parse_number.hh:291
char lr_parse_dot(std::string const &s, size_t &p, bool allow_empty=true, char value_if_empty='\0')
Definition: lr_parse_number.hh:193
unsigned lr_parse_uint(std::string const &s, size_t &p, bool allow_empty=false, unsigned value_if_empty=0)
Reads an unsigned int written in decimal left of position p in string s, by using as many character a...
Definition: lr_parse_number.hh:131
unsigned lr_scan_dot(std::string const &s, size_t &p)
Definition: lr_parse_number.hh:187
char lr_parse_sign(std::string const &s, size_t &p, bool allow_empty=true, char value_if_empty='\0')
Definition: lr_parse_number.hh:164
std::complex< double > lr_parse_complex(std::string const &s, size_t &p, bool allow_empty=false, std::complex< double > value_if_empty={0, 0})
Reads a complex number left of position p in string, by using as many characters as possible.
Definition: lr_parse_number.hh:458
unsigned lr_scan_e(std::string const &s, size_t &p)
Definition: lr_parse_number.hh:172
char lr_parse_one(std::string const &s, size_t &p, char const *t, bool allow_empty=false, char value_if_empty='\0')
Checks whether there is in t left of position p in s.
Definition: lr_parse_number.hh:76
static unsigned powten(unsigned i)
Definition: lr_parse_number.hh:321
std::string to_string(identities i)
std::ostream & dot(const Aut &aut, std::ostream &out, bool dot2tex=false, bool keep_history=true, bool horizontal=true)
Definition: dot.hh:270
Main namespace of Awali.
Definition: ato.hh:22
Exceptions thrown during parsing.
Definition: parse_exception.hh:26