GetFEM  5.4.2
bgeot_ftool.cc
1 /*===========================================================================
2 
3  Copyright (C) 2000-2020 Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 
23 #include "getfem/bgeot_config.h"
24 #include "getfem/bgeot_ftool.h"
25 #include "getfem/getfem_locale.h"
26 #include <ctype.h>
27 #include <limits.h>
28 #ifndef _WIN32
29 # include <unistd.h>
30 #endif
31 #include <fstream>
32 
33 namespace bgeot {
34 
35  bool read_until(std::istream &ist, const char *st) {
36  int i = 0, l = int(strlen(st)); char c;
37  while (!ist.eof() && i < l)
38  { ist.get(c); if (toupper(c) == toupper(st[i])) i++; else i = 0; }
39  if (ist.eof()) return false; else return true;
40  }
41 
42 #define get_c__(r, c) { ist.get(c); \
43  if (ist.eof()) { if (!st.size()) st.push_back('\n'); return r; } \
44  if (to_up) c = char(toupper(c)); }
45 
46 #define sdouble__(c, e) { st.push_back(c); get_c__(5, d); \
47  if (d == e) { st.push_back(e); return 6; } \
48  else { ist.putback(d); return 5; } } \
49 
50  int get_token(std::istream &ist, std::string &st,
51  bool ignore_cr, bool to_up, bool read_un_pm, int *linenb) {
52  st.clear();
53  char c = char(-1), d, e;
54 
55  get_c__(0, c);
56 
57  for(;;) { // Go through spaces, commentaries and '...'
58  if (!ignore_cr && c == '\n') { if (linenb) (*linenb)++; return 1; }
59  if (isspace(c)) { while (isspace(c)) get_c__(0, c); }
60  else if (c == '%') { while (c != '\n') get_c__(0, c); }
61  else if (c == '.') {
62  if (ist.eof()) break; else {
63  get_c__(0, d);
64  if (d == '.' && !ist.eof()) {
65  get_c__(0, e);
66  if (e == '.') {
67  while (c != '\n') get_c__(0, c);
68  if (linenb) (*linenb)++;
69  get_c__(0, c);
70  }
71  else { ist.putback(e); ist.putback(d); break; }
72  }
73  else { ist.putback(d); break; }
74  }
75  }
76  else break;
77  }
78 
79  if (read_un_pm)
80  if (c == '-' || c == '+') { // reading a number beginning with '+' or '-'
81  get_c__(2, d);
82  if (isdigit(d) || d == '.') { st.push_back(c); c = d; }
83  else ist.putback(d);
84  }
85 
86  if (isdigit(c) || c == '.') { // reading a number
87  while (isdigit(c) || c == '.' || c == 'e' || c == 'E') {
88  st.push_back(c);
89  if (c == 'e' || c == 'E') {
90  get_c__(2, c);
91  if (c == '+' || c == '-') st.push_back(c);
92  else ist.putback(c);
93  }
94  get_c__(2, c);
95  }
96  ist.putback(c);
97  return 2;
98  }
99 
100  if (c == '\"') { // reading a string
101  get_c__(3, c);
102  while (true) {
103  if (c == '\"' || c == '\n') return 3;
104  if (c == '\\') { st.push_back(c); get_c__(3, c); }
105  st.push_back(c);
106  get_c__(3, c);
107  }
108  return 3;
109  }
110 
111  if (c == '\'') { // reading a string
112  get_c__(3, c);
113  while (true) {
114  if (c == '\'' || c == '\n') return 3;
115  if (c == '\\') { st.push_back(c); get_c__(3, c); }
116  st.push_back(c);
117  get_c__(3, c);
118  }
119  return 3;
120  }
121 
122  if (isalpha(c) || c == '_') { // reading a name
123  while (isalnum(c) || c == '_') {
124  st.push_back(c);
125  get_c__(4,c);
126  }
127  ist.putback(c);
128  return 4;
129  }
130 
131  if (c == '|') sdouble__(c, '|');
132  if (c == '&') sdouble__(c, '&');
133  if (c == '=') sdouble__(c, '=');
134  if (c == '~') sdouble__(c, '=');
135  if (c == '<') sdouble__(c, '=');
136  if (c == '>') sdouble__(c, '=');
137 
138  st.push_back(c); return 5; // return the symbol read.
139  }
140 
141  std::istream& operator>>(std::istream& is, const skip& t) {
142  char c;
143  int i = 0;
144  while (!is.get(c).eof() && isspace(c)) /*continue*/;
145  for (i=0; t.s[i]; ++i) {
146  if (i) is.get(c);
147  GMM_ASSERT1(toupper(c) == toupper(t.s[i]) && !is.eof(),
148  "expected token '" << t.s << "' not found");
149  }
150  return is;
151  }
152 
153  int casecmp(const char *a, const char *b, unsigned n) {
154  unsigned i;
155  for (i=0; i < n && a[i] && b[i]; ++i) {
156  if (toupper(a[i]) < toupper(b[i])) return -1;
157  else if (toupper(a[i]) > toupper(b[i])) return -1;
158  }
159  if (a[i]) return +1;
160  else if (b[i]) return -1;
161  else return 0;
162  }
163 
164  void md_param::parse_error(const std::string &t) {
165  GMM_ASSERT1(false, "Parse error reading "
166  << current_file << " line " << current_line << " near " << t);
167  }
168 
169  void md_param::syntax_error(const std::string &t) {
170  GMM_ASSERT1(false, "Error reading "
171  << current_file << " line " << current_line << " : " << t);
172  }
173 
174  int md_param::get_next_token(std::istream &f) {
175  static int token_type = 0;
176  if (!token_is_valid)
177  token_type = get_token(f, temp_string, false, false, false,
178  &current_line);
179  token_is_valid = false;
180  return token_type;
181  }
182 
183  void md_param::valid_token() { token_is_valid = true; }
184 
185  std::ostream &operator <<(std::ostream &o, const md_param::param_value& p) {
186  switch (p.type_of_param()) {
187  case md_param::REAL_VALUE : o << p.real(); break;
188  case md_param::STRING_VALUE : o << '\'' << p.string() << '\''; break;
189  case md_param::ARRAY_VALUE :
190  o << "[";
191  if (p.array().size()) o << p.array()[0];
192  for (unsigned i = 1; i < p.array().size(); ++i)
193  o << ", " << p.array()[i];
194  o << "]";
195  }
196  return o;
197  }
198 
199  md_param::param_value md_param::read_expression(std::istream &f,
200  bool skipped) {
201  param_value result;
202  int i = get_next_token(f);
203  if (i == 2) { // a number
204  result = param_value(::strtod(temp_string.c_str(), 0));
205  }
206  else if (i == 3) { // a string
207  result = param_value(temp_string);
208  int j = get_next_token(f);
209  while (j == 3) {
210  result.string() += temp_string;
211  j = get_next_token(f);
212  }
213  valid_token();
214  }
215  else if (i == 4) { // a parameter name
216  std::string name(temp_string);
217  if (parameters.find(name) != parameters.end())
218  result = parameters[name];
219  else if (!skipped) {
220  std::stringstream s; s << "Parameter " << name << " not found";
221  syntax_error(s.str());
222  }
223  }
224  else if (i == 5) { // unary operators, parentheses and arrays
225  switch (temp_string[0]) {
226  case '(' :
227  {
228  result = read_expression_list(f, skipped);
229  int j = get_next_token(f);
230  if (j != 5 || temp_string[0] != ')') parse_error(temp_string);
231  }
232  break;
233  case '+' :
234  result = read_expression(f, skipped);
235  if (result.type_of_param() != REAL_VALUE)
236  syntax_error("Sorry, unary + does not support string "
237  "or array values");
238  break;
239  case '-' :
240  result = read_expression(f, skipped);
241  if (result.type_of_param() != REAL_VALUE)
242  syntax_error("Sorry, unary - does not support string "
243  "or array values");
244  result.real() *= -1.0;
245  break;
246  case '~' :
247  result = read_expression(f, skipped);
248  if (result.type_of_param() != REAL_VALUE)
249  syntax_error("Sorry, unary ! does not support string "
250  "or array values");
251  result.real() = !(result.real());
252  break;
253  case '[' :
254  {
255  bool first = true;
256  result = param_value(ARRAY_VALUE);
257  while (true) {
258  int j = get_next_token(f);
259  if (j == 5 && temp_string[0] == ']') break;
260  if (!first && temp_string[0] != ',') parse_error(temp_string);
261  if (first) valid_token();
262  result.array().push_back(read_expression_list(f, skipped));
263  first = false;
264  }
265  }
266  break;
267  default : parse_error(temp_string);
268  }
269  }
270  else parse_error(temp_string);
271 
272  return result;
273  }
274 
275  static void operator_priority_ftool(int i, char c, int &prior, int &op) {
276  if (i == 5)
277  switch (c) {
278  case '*' : prior = 1; op = 1; return;
279  case '/' : prior = 1; op = 2; return;
280  case '+' : prior = 2; op = 3; return;
281  case '-' : prior = 2; op = 4; return;
282  case '<' : prior = 3; op = 5; return;
283  case '>' : prior = 3; op = 6; return;
284  }
285  if (i == 6)
286  switch (c) {
287  case '<' : prior = 3; op = 7; return; // <=
288  case '>' : prior = 3; op = 8; return; // >=
289  case '=' : prior = 3; op = 9; return; // ==
290  case '~' : prior = 3; op = 10; return; // !=
291  case '&' : prior = 4; op = 11; return; // &&
292  case '|' : prior = 4; op = 12; return; // ||
293  }
294  prior = op = 0;
295  }
296 
297  void md_param::do_bin_op(std::vector<md_param::param_value> &value_list,
298  std::vector<int> &op_list,
299  std::vector<int> &prior_list) {
300  param_value &p1(*(value_list.end() - 2));
301  param_value &p2(*(value_list.end() - 1));
302  if (p1.type_of_param() != REAL_VALUE || p2.type_of_param() != REAL_VALUE)
303  syntax_error("Sorry, binary operators does not support string "
304  "or array values");
305 
306  switch (op_list.back()) {
307  case 1 : p1.real() *= p2.real(); break;
308  case 2 : p1.real() /= p2.real(); break;
309  case 3 : p1.real() += p2.real(); break;
310  case 4 : p1.real() -= p2.real(); break;
311  case 5 : p1.real() = (p1.real() < p2.real()); break;
312  case 6 : p1.real() = (p1.real() > p2.real()); break;
313  case 7 : p1.real() = (p1.real() <= p2.real()); break;
314  case 8 : p1.real() = (p1.real() >= p2.real()); break;
315  case 9 : p1.real() = (p1.real() == p2.real()); break;
316  case 10 : p1.real() = (p1.real() != p2.real()); break;
317  case 11 : p1.real() = ((p1.real() != 0.0) && (p2.real() != 0.0)); break;
318  case 12 : p1.real() = ((p1.real() != 0.0) || (p2.real() != 0.0)); break;
319  }
320  value_list.pop_back(); op_list.pop_back(); prior_list.pop_back();
321  }
322 
323 
324  md_param::param_value md_param::read_expression_list(std::istream &f,
325  bool skipped) {
326  std::vector<param_value> value_list;
327  value_list.push_back(read_expression(f, skipped));
328  std::vector<int> op_list, prior_list;
329  int i = get_next_token(f), prior, op;
330  operator_priority_ftool(i, temp_string[0], prior, op);
331  while (op) {
332  while (!prior_list.empty() && prior_list.back() <= prior)
333  do_bin_op(value_list, op_list, prior_list);
334 
335  value_list.push_back(read_expression(f, skipped));
336  op_list.push_back(op);
337  prior_list.push_back(prior);
338 
339  i = get_next_token(f);
340  operator_priority_ftool(i, temp_string[0], prior, op);
341  }
342  valid_token();
343 
344  while (!prior_list.empty()) do_bin_op(value_list, op_list, prior_list);
345 
346  return value_list[0];
347  }
348 
349  int md_param::read_instruction(std::istream &f, bool skipped) {
350  int i = 1;
351  while (i == 1 || (i == 5 && temp_string[0] == ';')) i = get_next_token(f);
352  if (i == 0) return 1;
353  if (i != 4) parse_error(temp_string);
354  if (temp_string == "end") return 1;
355  if (temp_string == "else") return 2;
356  if (temp_string == "elseif") return 3;
357  if (temp_string == "if") {
358  param_value p = read_expression_list(f, skipped);
359  if (p.type_of_param() != REAL_VALUE)
360  syntax_error("if instruction needs a condition");
361  bool b = (p.real() != 0.0);
362  int j = read_instruction_list(f, !b || skipped);
363  if (j == 0) syntax_error("Unterminated if");
364  if (j == 2) {
365  int k = read_instruction_list(f, b || skipped);
366  if (k != 1) syntax_error("Unterminated else");
367  }
368  if (j == 3) {
369  int k = 0;
370  do {
371  if (b) skipped = true;
372  p = read_expression_list(f, skipped);
373  if (p.type_of_param() != REAL_VALUE)
374  syntax_error("elseif instruction needs a condition");
375  b = (p.real() != 0.0);
376  k = read_instruction_list(f, !b || skipped);
377  if (k == 2) {
378  k = read_instruction_list(f, b || skipped);
379  break;
380  }
381  } while (k == 3);
382  if (k != 1) syntax_error("Unterminated elseif");
383  }
384  return 0;
385  }
386  if (temp_string == "error") {
387  param_value p = read_expression_list(f, skipped);
388  GMM_ASSERT1(skipped, "Error in parameter file: " << p);
389  return 0;
390  }
391  std::string name(temp_string);
392  i = get_next_token(f);
393  if (i != 5 || temp_string[0] != '=') parse_error(temp_string);
394  param_value result = read_expression_list(f, skipped);
395  i = get_next_token(f);
396  if (i != 0 && i != 1 && (i != 5 || temp_string[0] != ';'))
397  parse_error(temp_string);
398  if (!skipped) parameters[name]=result;
399  return 0;
400  }
401 
402  int md_param::read_instruction_list(std::istream &f, bool skipped) {
403  int i; while (!(i = read_instruction(f, skipped))) { }
404  return i;
405  }
406 
407  void md_param::read_param_file(std::istream &f) {
409  token_is_valid = false; current_line = 1;
410  if (read_instruction_list(f) > 1)
411  syntax_error("Parameter file terminated by an else");
412  }
413 
414  void md_param::read_command_line(int argc, char *argv[]) {
416  for (int aa = 1; aa < argc; aa++) {
417  if (argv[aa][0] != '-') {
418  current_file = std::string(argv[aa]);
419  std::ifstream f1(current_file.c_str());
420  if (f1) { read_param_file(f1); f1.close(); }
421  else {
422  std::string r = current_file;
423  current_file += ".param";
424  std::ifstream f2(current_file.c_str());
425  if (f2) { read_param_file(f2); f2.close(); }
426  else GMM_ASSERT1(false, "Parameter file " << r << "not found");
427  }
428  }
429  else if (argv[aa][1] == 'd') {
430  current_file = "command line";
431  if (strlen(argv[aa]) == 2)
432  { std::stringstream ss(argv[++aa]); read_param_file(ss); }
433  else
434  { std::stringstream ss(&(argv[aa][2])); read_param_file(ss); }
435  }
436  }
437  }
438 
439  double md_param::real_value(const std::string &name, const char *comment,
440  double default_val) {
441  if (parameters.find(name) == parameters.end()) {
442  if (comment == 0)
443  return default_val;
444  else {
445  double f;
447  cout << "No parameter " << name << " found, please enter its value\n";
448  cout << comment << " : "; cin >> f;
449  parameters[name] = param_value(f);
450  }
451  }
452  param_value &p(parameters[name]);
453  GMM_ASSERT1(p.type_of_param() == REAL_VALUE,
454  "Parameter " << name << " is not real");
455  return p.real();
456  }
457 
458  long md_param::int_value(const std::string &name, const char *comment,
459  long default_val) {
460  if (parameters.find(name) == parameters.end()) {
461  if (comment == 0)
462  return default_val;
463  else {
464  long f;
466  cout << "No parameter " << name << " found, please enter its value\n";
467  cout << comment << " : "; cin >> f;
468  parameters[name] = param_value(double(f));
469  }
470  }
471  param_value &p(parameters[name]);
472  GMM_ASSERT1(p.type_of_param() == REAL_VALUE,
473  "Parameter " << name << " is not real");
474  return long(p.real());
475  }
476 
477  const std::string &md_param::string_value(const std::string &name,
478  const char *comment,
479  const std::string &default_val) {
480  if (parameters.find(name) == parameters.end()) {
481  if (comment == 0)
482  return default_val;
483  else {
484  std::string s;
486  cout << "No parameter " << name << " found, please enter its value\n";
487  cout << comment << " : "; cin >> s;
488  parameters[name] = param_value(s);
489  }
490  }
491  param_value &p(parameters[name]);
492  GMM_ASSERT1(p.type_of_param() == STRING_VALUE, "Parameter " << name
493  << " is not a character string");
494  return p.string();
495  }
496 
497  const std::vector<md_param::param_value> &
498  md_param::array_value(const std::string &name, const char *comment) {
499 
500  static std::vector<md_param::param_value> empty_array;
501  if (parameters.find(name) == parameters.end()) {
502  if (comment == 0) return empty_array;
503  else {
504  std::string s;
506  cout << "No parameter " << name << " found, please enter its value\n";
507  cout << comment << " : "; cin >> s;
508  parameters[name] = param_value(s);
509  }
510  }
511  param_value &p(parameters[name]);
512  GMM_ASSERT1(p.type_of_param() == ARRAY_VALUE, "Parameter " << name
513  << " is not an array");
514  return p.array();
515  }
516 }
bgeot::operator<<
std::ostream & operator<<(std::ostream &o, const convex_structure &cv)
Print the details of the convex structure cvs to the output stream o.
Definition: bgeot_convex_structure.cc:71
bgeot::get_token
int get_token(std::istream &ist, std::string &st, bool ignore_cr, bool to_up, bool read_un_pm, int *linenb)
Very simple lexical analysis of general interest for reading small languages with a "MATLAB like" syn...
Definition: bgeot_ftool.cc:50
getfem::standard_locale
Identical to gmm::standard_locale, but does not change std::locale in multi-threaded sections of the ...
Definition: getfem_locale.h:50
getfem_locale.h
thread safe standard locale with RAII semantics
bgeot_ftool.h
"File Tools"
bgeot
Basic Geometric Tools.
Definition: bgeot_convex_ref.cc:27
bgeot_config.h
defines and typedefs for namespace bgeot