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