FLAME  devel
 All Classes Functions Variables Typedefs Enumerations Pages
glps_parser.cpp
1 
2 #include <stdio.h>
3 #include <stdlib.h>
4 
5 #include <algorithm>
6 #include <memory>
7 #include <stdexcept>
8 #include <sstream>
9 
10 #include "glps_parser.h"
11 
12 # define M_PI 3.14159265358979323846
13 
14 #define YYSTYPE GLPS_STYPE
15 extern "C" {
16 // the generated headers wrap some parts in extern "C" blocks, but not all...
17 #include "glps.par.h"
18 #include "glps.tab.h"
19 }
20 
21 parse_element::parse_element(std::string L, std::string E, kvlist_t::map_t &M)
22  :label(L), etype(E)
23 {
24  assert(!label.empty() && !etype.empty());
25  props.swap(M);
26 }
27 
28 parse_line::parse_line(std::string L, std::string E, strlist_t::list_t& N)
29  :label(L), etype(E)
30 {
31  names.swap(N);
32 }
33 
34 operation_t::operation_t(const char *name, eval_t fn, glps_expr_type R, unsigned N, va_list args)
35  :name(name), fn(fn), result_type(R), arg_types(N)
36 {
37  for(unsigned i=0; i<N; i++)
38  arg_types[i] = (glps_expr_type)va_arg(args, int);
39 }
40 
41 void glps_error(void *scan, parse_context *ctxt, const char* fmt, ...)
42 {
43  va_list args;
44  va_start(args, fmt);
45  glps_verror(scan, ctxt, fmt, args);
46  va_end(args);
47 }
48 
49 void glps_verror(void *scan, parse_context *ctxt, const char*fmt, va_list args)
50 {
51  if(ctxt->last_error.size())
52  return; // don't clobber first error
53  vsnprintf(&ctxt->error_scratch[0], ctxt->error_scratch.size()-1, fmt, args);
54  ctxt->error_scratch[ctxt->error_scratch.size()-1] = '\0';
55  ctxt->last_error = &ctxt->error_scratch[0];
56  ctxt->last_line = glps_get_lineno(scan);
57 }
58 
59 const char *glps_expr_type_name(glps_expr_type e)
60 {
61  switch(e) {
62  case glps_expr_number: return "Number";
63  case glps_expr_vector: return "Vector";
64  case glps_expr_string: return "String";
65  case glps_expr_var: return "Variable";
66  case glps_expr_config: return "Config";
67  case glps_expr_elem: return "Element";
68  case glps_expr_line: return "Beamline";
69  case glps_expr_invalid:return "Invalid";
70  default: return "Unknown_expression_type";
71  }
72 }
73 
74 void glps_string_debug(FILE *fp, const string_t *s)
75 {
76  fprintf(fp, "%s", s->str.c_str());
77 }
78 
79 void glps_expr_debug(FILE *fp, const expr_t *E)
80 {
81  fprintf(fp, "%p type %s", E, glps_expr_type_name(E->etype));
82  if(E->etype==glps_expr_line) {
83  try{
84  const strlist_t::list_t& L(boost::get<strlist_t::list_t>(E->value));
85  fprintf(fp, " [%u] (", (unsigned)L.size());
86  for(size_t i=0, N=L.size(); i<N; i++)
87  fprintf(fp, "%s, ", L[i].c_str());
88  fprintf(fp, ")");
89  }catch(std::exception& e){
90  fprintf(fp, " oops %s", e.what());
91  }
92  }
93 }
94 
95 string_t* glps_string_alloc(const char *s, size_t n)
96 {
97  try{
98  return new string_t(s, n);
99  }catch(...){
100  return NULL;
101  }
102 }
103 
104 void glps_string_cleanup(string_t* str)
105 {
106  delete str;
107 }
108 
109 void glps_expr_cleanup(expr_t* expr)
110 {
111  delete expr;
112 }
113 
114 void glps_vector_cleanup(vector_t* vec)
115 {
116  delete vec;
117 }
118 
119 void glps_kvlist_cleanup(kvlist_t* pval)
120 {
121  delete pval;
122 }
123 
124 void glps_strlist_cleanup(strlist_t* pval)
125 {
126  delete pval;
127 }
128 
129 kvlist_t* glps_append_kv(parse_context *ctxt, kvlist_t* L, kv_t* V)
130 {
131  std::auto_ptr<string_t> SN(V->key);
132  std::auto_ptr<expr_t> EV(V->value);
133  if(!L) {
134  try{
135  L = new kvlist_t;
136  } catch(std::bad_alloc&) {
137  glps_error(ctxt->scanner, ctxt, "Allocation failure");
138  return NULL;
139  }
140  }
141  L->map[V->key->str] = *V->value;
142  return L;
143 }
144 
145 strlist_t* glps_append_expr(parse_context *ctxt, strlist_t* list, expr_t *expr)
146 {
147  assert(expr);
148  std::auto_ptr<expr_t> E(expr);
149  std::auto_ptr<strlist_t> L(list);
150 
151  try{
152  if(!L.get()) {
153  L.reset(new strlist_t);
154  }
155 
156  switch(expr->etype) {
157  case glps_expr_elem:
158  // prepend a single element (append, the result will be reversed in glps_add_line)
159  L->list.push_back(boost::get<std::string>(expr->value));
160  break;
161  case glps_expr_line:
162  {
163  // prepend another line (append in reversed order)
164  std::vector<std::string>& N(boost::get<std::vector<std::string> >(expr->value));
165 
166  size_t orig = L->list.size();
167  L->list.resize(L->list.size()+N.size());
168  std::copy(N.rbegin(),
169  N.rend(),
170  L->list.begin()+orig);
171  }
172  break;
173  default:
174  glps_error(ctxt->scanner, ctxt, "Lines can not be constructed from %s",
175  glps_expr_type_name(expr->etype));
176  L.reset(NULL);
177  }
178 
179  } catch(boost::bad_get& e) {
180  glps_error(ctxt->scanner, ctxt, "Error appending to vector: incorrect type %s", expr->value.type().name());
181  L.reset(NULL);
182  } catch(std::exception& e) {
183  glps_error(ctxt->scanner, ctxt, "Error appending to vector: %s", e.what());
184  L.reset(NULL);
185  }
186 
187  return L.release();
188 }
189 
190 vector_t* glps_append_vector(parse_context *ctxt, vector_t *list, expr_t *expr)
191 {
192  assert(expr);
193  try{
194  std::auto_ptr<expr_t> E(expr);
195  std::auto_ptr<vector_t> V(list);
196  if(!V.get())
197  V.reset(new vector_t);
198 
199  if(expr->etype==glps_expr_number) {
200  V->value.push_back(boost::get<double>(expr->value));
201  } else {
202  std::ostringstream strm;
203  strm << "Vector element types must be scalar not type " << glps_expr_type_name(expr->etype);
204  throw std::runtime_error(strm.str());
205  }
206 
207  return V.release();
208  } catch(std::exception& e) {
209  glps_error(ctxt->scanner, ctxt, "Error appending to vector: %s", e.what());
210  return NULL;
211  }
212 }
213 
214 expr_t *glps_add_value(parse_context *ctxt, glps_expr_type t, ...)
215 {
216  std::auto_ptr<expr_t> ret;
217  try {
218  ret.reset(new expr_t);
219  ret->etype = t;
220 
221  va_list args;
222  va_start(args, t);
223  ret->etype = t;
224  switch(t) {
225  case glps_expr_number:
226  ret->value = va_arg(args, double);
227  break;
228  case glps_expr_var:
229  {
230  string_t *name = va_arg(args, string_t*);
231  std::auto_ptr<string_t> SN(name);
232 
233  parse_context::map_idx_t::const_iterator it;
234 
235  // var may actually be a variable name, or an element/line label
236  if((it=ctxt->var_idx.find(name->str))!=ctxt->var_idx.end()) {
237  // expand variable
238  expr_t &E = ctxt->vars[it->second].expr;
239 
240  ret->etype = E.etype;
241  ret->value = E.value;
242 
243  } else if(ctxt->element_idx.find(name->str)!=ctxt->element_idx.end()) {
244  // expand element
245  strlist_t::list_t T(1);
246  T[0] = name->str;
247  ret->etype = glps_expr_line;
248  ret->value = T;
249 
250  } else if((it=ctxt->line_idx.find(name->str))!=ctxt->line_idx.end()) {
251  // expand beamline
252  parse_line &L = ctxt->line[it->second];
253  ret->etype = glps_expr_line;
254  ret->value = L.names;
255 
256  } else if(name->str=="pi") {
257  ret->etype = glps_expr_number;
258  ret->value = M_PI;
259 
260  } else {
261  /* having this check in the parser ensure that variables
262  * are defined before first use, which prevents definition
263  * loops from forming.
264  */
265  glps_error(ctxt->scanner, ctxt, "Variable/Label '%s' referenced before definition", name->str.c_str());
266  ret.reset();
267  }
268  }
269  break;
270  case glps_expr_string:
271  {
272  string_t *name = va_arg(args, string_t*);
273  std::auto_ptr<string_t> SN(name);
274  assert(name);
275  ret->value = name->str;
276  }
277  break;
278  case glps_expr_vector:
279  {
280  vector_t *vec = va_arg(args, vector_t *);
281  if(!vec)
282  ret->value = std::vector<double>();
283  else {
284  std::reverse(vec->value.begin(), vec->value.end());
285  ret->value = vec->value;
286  delete vec;
287  }
288  break;
289  }
290  default:
291  glps_error(ctxt->scanner, ctxt, "Logic error, type=%d", (int)t);
292  ret.reset();
293  break;
294  }
295  va_end(args);
296 
297  }catch(std::exception& e){
298  glps_error(ctxt->scanner, ctxt, "Exception while constructing value: %s", e.what());
299  return NULL;
300  }
301  return ret.release();
302 }
303 
304 static
305 std::string glps_describe_op(const operation_t* op)
306 {
307  std::ostringstream strm;
308  strm << glps_expr_type_name(op->result_type)
309  << " '" << op->name <<"'(";
310  for(unsigned i=0; i<op->arg_types.size(); i++) {
311  if(i>0)
312  strm<<", ";
313  strm<<glps_expr_type_name(op->arg_types[i]);
314  }
315  strm << ")";
316  return strm.str();
317 
318 }
319 
320 expr_t *glps_add_op(parse_context *ctxt, string_t *name, unsigned N, expr_t **args)
321 {
322  std::auto_ptr<string_t> SN(name);
323  std::auto_ptr<expr_t> ret;
324  try{
325 
326  parse_context::operations_iterator_pair opit = ctxt->operations.equal_range(name->str);
327 
328  const operation_t *op=NULL;
329  for(;opit.first!=opit.second; ++opit.first)
330  {
331  if(opit.first->second.arg_types.size()!=N)
332  continue;
333  bool match=true;
334  for(unsigned I=0; I<N; I++)
335  {
336  if(opit.first->second.arg_types[I]!=args[I]->etype) {
337  match=false;
338  break;
339  }
340  }
341  if(match) {
342  op = &opit.first->second;
343  break;
344  }
345  }
346 
347  if(!op) {
348  std::ostringstream strm;
349  strm << "Operation '" << name <<"'(";
350  for(unsigned i=0; i<N; i++) {
351  if(i>0)
352  strm<<", ";
353  strm<<glps_expr_type_name(args[i]->etype);
354  }
355  strm << ")";
356  glps_error(ctxt->scanner, ctxt, "%s", strm.str().c_str());
357 
358  } else {
359  ret.reset(new expr_t);
360  ret->etype = op->result_type;
361  int rv = 0;
362  try{
363  rv = (*op->fn)(ctxt, &ret->value, args);
364  }catch(std::exception& e){
365  glps_error(ctxt->scanner, ctxt, "User exception evaluating '%s': %s",
366  glps_describe_op(op).c_str(), e.what());
367  ret.reset(0);
368  }
369 
370  if(rv)
371  throw std::runtime_error(ctxt->last_error);
372  }
373 
374 
375  }catch(std::exception& e){
376  glps_error(ctxt->scanner, ctxt, "Exception evaluating expression op '%s': %s",
377  name->str.c_str(), e.what());
378  ret.reset(0);
379  }
380 
381  while(N) glps_expr_cleanup(args[--N]);
382  return ret.release();
383 }
384 
385 
386 void glps_assign(parse_context *ctxt, string_t *name, expr_t*value)
387 {
388  assert(name);
389  assert(value);
390  try{
391  std::auto_ptr<string_t> SN(name);
392  std::auto_ptr<expr_t> VN(value);
393 
394  bool ok = false;
395  parse_var V;
396  V.name = name->str;
397 
398  switch(value->etype) {
399  case glps_expr_vector:
400  case glps_expr_number:
401  case glps_expr_string:
402  case glps_expr_config:
403  {
404  V.expr = *value;
405  ok = true;
406  }
407  break;
408  default:
409  glps_error(ctxt->scanner, ctxt, "expression type %d may not be assigned to variable '%s'",
410  value->etype, V.name.c_str());
411 
412  }
413 
414  if(ok) {
415  if(ctxt->var_idx.find(V.name)!=ctxt->var_idx.end()) {
416  glps_error(ctxt->scanner, ctxt, "Name '%s' already defined", V.name.c_str());
417  } else {
418  ctxt->vars.push_back(V);
419  ctxt->var_idx[V.name] = ctxt->vars.size()-1;
420  }
421  }
422 
423  } catch(std::exception& e) {
424  glps_error(ctxt->scanner, ctxt, "Variable '%s' assignment error; %s", name->str.c_str(), e.what());
425  }
426 }
427 
428 void glps_add_element(parse_context *ctxt, string_t *label, string_t *etype, kvlist_t *P)
429 {
430  std::auto_ptr<string_t> SL(label), SE(etype);
431  std::auto_ptr<kvlist_t> props(P);
432  try{
433  if(!P)
434  props.reset(new kvlist_t);
435  if(label->str.empty() || etype->str.empty()) {
436  glps_error(ctxt->scanner, ctxt, "Element with null label or type");
437 
438  } else if(ctxt->element_idx.find(label->str)!=ctxt->element_idx.end()) {
439  glps_error(ctxt->scanner, ctxt, "Name '%s' already used", label->str.c_str());
440 
441  } else {
442  ctxt->elements.push_back(parse_element(label->str, etype->str, props->map));
443  ctxt->element_idx[label->str] = ctxt->elements.size()-1;
444  }
445 
446  } catch(std::exception& e) {
447  glps_error(ctxt->scanner, ctxt, "Element '%s' definition error; %s", label->str.c_str(), e.what());
448  }
449 }
450 
451 void glps_add_line(parse_context *ctxt, string_t *label, string_t *etype, strlist_t *N)
452 {
453  std::auto_ptr<string_t> SL(label), SE(etype);
454  try{
455  std::auto_ptr<strlist_t> names(N);
456  if(!N)
457  names.reset(new strlist_t);
458 
459  if(strcasecmp(etype->str.c_str(),"LINE")!=0) {
460  glps_error(ctxt->scanner, ctxt, "line-like definition %s with '%s' instead of 'LINE'",
461  label->str.c_str(), etype->str.c_str());
462 
463  } else if(ctxt->line_idx.find(label->str)!=ctxt->line_idx.end()) {
464  glps_error(ctxt->scanner, ctxt, "Name '%s' already used", label->str.c_str());
465 
466  } else {
467  // reverse order of elements
468  std::reverse(names->list.begin(), names->list.end());
469  ctxt->line.push_back(parse_line(label->str, etype->str, names->list));
470  ctxt->line_idx[label->str] = ctxt->line.size()-1;
471  }
472 
473  } catch(std::exception& e) {
474  glps_error(ctxt->scanner, ctxt, "Line '%s' definition error; %s", label->str.c_str(), e.what());
475  }
476 }
477 
478 void glps_command(parse_context* ctxt, string_t *kw)
479 {
480  std::auto_ptr<string_t> SK(kw);
481  if(strcmp(kw->str.c_str(), "END")!=0) {
482  glps_error(ctxt->scanner, ctxt, "Undefined command '%s'", kw->str.c_str());
483  }
484 }
485 
486 void glps_call1(parse_context *ctxt, string_t *func, expr_t *arg)
487 {
488  std::auto_ptr<string_t> FN(func);
489  std::auto_ptr<expr_t> ARG(arg);
490 
491  if(func->str!="print") {
492  glps_error(ctxt->scanner, ctxt, "Undefined global function '%s'", func->str.c_str());
493  } else if(ctxt->printer) {
494  std::ostream& strm = *ctxt->printer;
495  strm<<"On line "<<glps_get_lineno(ctxt->scanner)<<" : ";
496  switch(arg->etype)
497  {
498  case glps_expr_number: strm<< boost::get<double>(arg->value); break;
499  case glps_expr_string: strm<<"\""<< boost::get<std::string>(arg->value)<<"\""; break;
500  case glps_expr_vector: {
501  std::ostream_iterator<double> it(strm, ", ");
502  const std::vector<double>& vect = boost::get<std::vector<double> >(arg->value);
503  strm<<"[";
504  std::copy(vect.begin(), vect.end(), it);
505  strm<<"]";
506  }
507  break;
508  case glps_expr_line: {
509  std::ostream_iterator<std::string> it(strm, ", ");
510  const std::vector<std::string>& vect = boost::get<std::vector<std::string> >(arg->value);
511  strm<<"(";
512  std::copy(vect.begin(), vect.end(), it);
513  strm<<")";
514  }
515  break;
516  default:
517  strm<<"?? <"<<glps_expr_type_name(arg->etype)<<"> ??";
518  }
519  strm<<"\n";
520  }
521 }
522 
523 namespace {
524 void parse_common(YY_BUFFER_STATE (*setup)(yyscan_t, void*),
525  parse_context* ctxt, void *pvt)
526 {
527  yyscan_t scanner;
528 
529  if(glps_lex_init_extra(ctxt, &scanner))
530  throw std::runtime_error("Failed to allocate/init lexer");
531  try{
532  YY_BUFFER_STATE buf = setup(scanner, pvt);
533  if(!buf)
534  throw std::runtime_error("Failed to allocate lex buffer");
535 
536  ctxt->last_error.clear();
537  glps_set_lineno(1, scanner);
538 
539  yacc_arg arg;
540  ctxt->scanner = arg.scanner = scanner;
541  arg.ctxt = ctxt;
542  glps_parse(arg);
543  ctxt->scanner = NULL;
544 
545  if(ctxt->last_error.size()) {
546  std::ostringstream strm;
547  strm << "On line " << ctxt->last_line;
548  strm << ": " << ctxt->last_error;
549  throw std::runtime_error(strm.str());
550  }
551 
552  glps_lex_destroy(scanner);
553  } catch(...) {
554  glps_lex_destroy(scanner);
555  throw;
556  }
557 }
558 
559 YY_BUFFER_STATE setup_file(yyscan_t scanner, void* pvt)
560 {
561  FILE *fp = (FILE*)pvt;
562  YY_BUFFER_STATE ret = glps__create_buffer(fp, 1024, scanner);
563  glps__switch_to_buffer(ret, scanner);
564  return ret;
565 }
566 
567 YY_BUFFER_STATE setup_string(yyscan_t scanner, void* pvt)
568 {
569  const std::string *str = (const std::string*)pvt;
570  return glps__scan_bytes(str->c_str(), str->size(), scanner);
571 }
572 
573 struct bytebuf {
574  const char *bytes;
575  size_t len;
576 };
577 
578 YY_BUFFER_STATE setup_bytes(yyscan_t scanner, void* pvt)
579 {
580  bytebuf *buf = static_cast<bytebuf*>(pvt);
581  return glps__scan_bytes(buf->bytes, buf->len, scanner);
582 }
583 }
584 
585 void parse_context::parse(FILE *fp)
586 {
587  parse_common(&setup_file, this, (void*)fp);
588 }
589 
590 void parse_context::parse(const char* s, size_t len)
591 {
592  bytebuf buf = {s, len};
593  parse_common(&setup_bytes, this, (void*)&buf);
594 }
595 
596 void parse_context::parse(const std::string& s)
597 {
598  parse_common(&setup_string, this, (void*)&s);
599 }
600 
601 void
602 parse_context::addop(const char *name,
603  operation_t::eval_t fn,
604  glps_expr_type R, unsigned N, ...)
605 {
606  va_list args;
607  va_start(args, N);
608  try{
609  operations.insert(std::make_pair(name,
610  operation_t(name, fn, R, N, args)
611  ));
612 
613  va_end(args);
614  }catch(...){
615  va_end(args);
616  throw;
617  }
618 }