10 #include "glps_parser.h"
12 # define M_PI 3.14159265358979323846
14 #define YYSTYPE GLPS_STYPE
21 parse_element::parse_element(std::string L, std::string E, kvlist_t::map_t &M)
24 assert(!label.empty() && !etype.empty());
28 parse_line::parse_line(std::string L, std::string E, strlist_t::list_t& N)
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)
37 for(
unsigned i=0; i<N; i++)
38 arg_types[i] = (glps_expr_type)va_arg(args,
int);
41 void glps_error(
void *scan, parse_context *ctxt,
const char* fmt, ...)
45 glps_verror(scan, ctxt, fmt, args);
49 void glps_verror(
void *scan, parse_context *ctxt,
const char*fmt, va_list args)
51 if(ctxt->last_error.size())
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);
59 const char *glps_expr_type_name(glps_expr_type 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";
74 void glps_string_debug(FILE *fp,
const string_t *s)
76 fprintf(fp,
"%s", s->str.c_str());
79 void glps_expr_debug(FILE *fp,
const expr_t *E)
81 fprintf(fp,
"%p type %s", E, glps_expr_type_name(E->etype));
82 if(E->etype==glps_expr_line) {
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());
89 }
catch(std::exception& e){
90 fprintf(fp,
" oops %s", e.what());
95 string_t* glps_string_alloc(
const char *s,
size_t n)
98 return new string_t(s, n);
104 void glps_string_cleanup(string_t* str)
109 void glps_expr_cleanup(expr_t* expr)
114 void glps_vector_cleanup(vector_t* vec)
119 void glps_kvlist_cleanup(kvlist_t* pval)
124 void glps_strlist_cleanup(strlist_t* pval)
129 kvlist_t* glps_append_kv(parse_context *ctxt, kvlist_t* L, kv_t* V)
131 std::auto_ptr<string_t> SN(V->key);
132 std::auto_ptr<expr_t> EV(V->value);
136 }
catch(std::bad_alloc&) {
137 glps_error(ctxt->scanner, ctxt,
"Allocation failure");
141 L->map[V->key->str] = *V->value;
145 strlist_t* glps_append_expr(parse_context *ctxt, strlist_t* list, expr_t *expr)
148 std::auto_ptr<expr_t> E(expr);
149 std::auto_ptr<strlist_t> L(list);
153 L.reset(
new strlist_t);
156 switch(expr->etype) {
159 L->list.push_back(boost::get<std::string>(expr->value));
164 std::vector<std::string>& N(boost::get<std::vector<std::string> >(expr->value));
166 size_t orig = L->list.size();
167 L->list.resize(L->list.size()+N.size());
168 std::copy(N.rbegin(),
170 L->list.begin()+orig);
174 glps_error(ctxt->scanner, ctxt,
"Lines can not be constructed from %s",
175 glps_expr_type_name(expr->etype));
179 }
catch(boost::bad_get& e) {
180 glps_error(ctxt->scanner, ctxt,
"Error appending to vector: incorrect type %s", expr->value.type().name());
182 }
catch(std::exception& e) {
183 glps_error(ctxt->scanner, ctxt,
"Error appending to vector: %s", e.what());
190 vector_t* glps_append_vector(parse_context *ctxt, vector_t *list, expr_t *expr)
194 std::auto_ptr<expr_t> E(expr);
195 std::auto_ptr<vector_t> V(list);
197 V.reset(
new vector_t);
199 if(expr->etype==glps_expr_number) {
200 V->value.push_back(boost::get<double>(expr->value));
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());
208 }
catch(std::exception& e) {
209 glps_error(ctxt->scanner, ctxt,
"Error appending to vector: %s", e.what());
214 expr_t *glps_add_value(parse_context *ctxt, glps_expr_type t, ...)
216 std::auto_ptr<expr_t> ret;
218 ret.reset(
new expr_t);
225 case glps_expr_number:
226 ret->value = va_arg(args,
double);
230 string_t *name = va_arg(args, string_t*);
231 std::auto_ptr<string_t> SN(name);
233 parse_context::map_idx_t::const_iterator it;
236 if((it=ctxt->var_idx.find(name->str))!=ctxt->var_idx.end()) {
238 expr_t &E = ctxt->vars[it->second].expr;
240 ret->etype = E.etype;
241 ret->value = E.value;
243 }
else if(ctxt->element_idx.find(name->str)!=ctxt->element_idx.end()) {
245 strlist_t::list_t T(1);
247 ret->etype = glps_expr_line;
250 }
else if((it=ctxt->line_idx.find(name->str))!=ctxt->line_idx.end()) {
252 parse_line &L = ctxt->line[it->second];
253 ret->etype = glps_expr_line;
254 ret->value = L.names;
256 }
else if(name->str==
"pi") {
257 ret->etype = glps_expr_number;
265 glps_error(ctxt->scanner, ctxt,
"Variable/Label '%s' referenced before definition", name->str.c_str());
270 case glps_expr_string:
272 string_t *name = va_arg(args, string_t*);
273 std::auto_ptr<string_t> SN(name);
275 ret->value = name->str;
278 case glps_expr_vector:
280 vector_t *vec = va_arg(args, vector_t *);
282 ret->value = std::vector<double>();
284 std::reverse(vec->value.begin(), vec->value.end());
285 ret->value = vec->value;
291 glps_error(ctxt->scanner, ctxt,
"Logic error, type=%d", (
int)t);
297 }
catch(std::exception& e){
298 glps_error(ctxt->scanner, ctxt,
"Exception while constructing value: %s", e.what());
301 return ret.release();
305 std::string glps_describe_op(
const operation_t* op)
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++) {
313 strm<<glps_expr_type_name(op->arg_types[i]);
320 expr_t *glps_add_op(parse_context *ctxt, string_t *name,
unsigned N, expr_t **args)
322 std::auto_ptr<string_t> SN(name);
323 std::auto_ptr<expr_t> ret;
326 parse_context::operations_iterator_pair opit = ctxt->operations.equal_range(name->str);
328 const operation_t *op=NULL;
329 for(;opit.first!=opit.second; ++opit.first)
331 if(opit.first->second.arg_types.size()!=N)
334 for(
unsigned I=0; I<N; I++)
336 if(opit.first->second.arg_types[I]!=args[I]->etype) {
342 op = &opit.first->second;
348 std::ostringstream strm;
349 strm <<
"Operation '" << name <<
"'(";
350 for(
unsigned i=0; i<N; i++) {
353 strm<<glps_expr_type_name(args[i]->etype);
356 glps_error(ctxt->scanner, ctxt,
"%s", strm.str().c_str());
359 ret.reset(
new expr_t);
360 ret->etype = op->result_type;
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());
371 throw std::runtime_error(ctxt->last_error);
375 }
catch(std::exception& e){
376 glps_error(ctxt->scanner, ctxt,
"Exception evaluating expression op '%s': %s",
377 name->str.c_str(), e.what());
381 while(N) glps_expr_cleanup(args[--N]);
382 return ret.release();
386 void glps_assign(parse_context *ctxt, string_t *name, expr_t*value)
391 std::auto_ptr<string_t> SN(name);
392 std::auto_ptr<expr_t> VN(value);
398 switch(value->etype) {
399 case glps_expr_vector:
400 case glps_expr_number:
401 case glps_expr_string:
402 case glps_expr_config:
409 glps_error(ctxt->scanner, ctxt,
"expression type %d may not be assigned to variable '%s'",
410 value->etype, V.name.c_str());
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());
418 ctxt->vars.push_back(V);
419 ctxt->var_idx[V.name] = ctxt->vars.size()-1;
423 }
catch(std::exception& e) {
424 glps_error(ctxt->scanner, ctxt,
"Variable '%s' assignment error; %s", name->str.c_str(), e.what());
428 void glps_add_element(parse_context *ctxt, string_t *label, string_t *etype, kvlist_t *P)
430 std::auto_ptr<string_t> SL(label), SE(etype);
431 std::auto_ptr<kvlist_t> props(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");
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());
442 ctxt->elements.push_back(parse_element(label->str, etype->str, props->map));
443 ctxt->element_idx[label->str] = ctxt->elements.size()-1;
446 }
catch(std::exception& e) {
447 glps_error(ctxt->scanner, ctxt,
"Element '%s' definition error; %s", label->str.c_str(), e.what());
451 void glps_add_line(parse_context *ctxt, string_t *label, string_t *etype, strlist_t *N)
453 std::auto_ptr<string_t> SL(label), SE(etype);
455 std::auto_ptr<strlist_t> names(N);
457 names.reset(
new strlist_t);
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());
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());
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;
473 }
catch(std::exception& e) {
474 glps_error(ctxt->scanner, ctxt,
"Line '%s' definition error; %s", label->str.c_str(), e.what());
478 void glps_command(parse_context* ctxt, string_t *kw)
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());
486 void glps_call1(parse_context *ctxt, string_t *func, expr_t *arg)
488 std::auto_ptr<string_t> FN(func);
489 std::auto_ptr<expr_t> ARG(arg);
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)<<
" : ";
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);
504 std::copy(vect.begin(), vect.end(), it);
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);
512 std::copy(vect.begin(), vect.end(), it);
517 strm<<
"?? <"<<glps_expr_type_name(arg->etype)<<
"> ??";
524 void parse_common(YY_BUFFER_STATE (*setup)(yyscan_t,
void*),
525 parse_context* ctxt,
void *pvt)
529 if(glps_lex_init_extra(ctxt, &scanner))
530 throw std::runtime_error(
"Failed to allocate/init lexer");
532 YY_BUFFER_STATE buf = setup(scanner, pvt);
534 throw std::runtime_error(
"Failed to allocate lex buffer");
536 ctxt->last_error.clear();
537 glps_set_lineno(1, scanner);
540 ctxt->scanner = arg.scanner = scanner;
543 ctxt->scanner = NULL;
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());
552 glps_lex_destroy(scanner);
554 glps_lex_destroy(scanner);
559 YY_BUFFER_STATE setup_file(yyscan_t scanner,
void* pvt)
561 FILE *fp = (FILE*)pvt;
562 YY_BUFFER_STATE ret = glps__create_buffer(fp, 1024, scanner);
563 glps__switch_to_buffer(ret, scanner);
567 YY_BUFFER_STATE setup_string(yyscan_t scanner,
void* pvt)
569 const std::string *str = (
const std::string*)pvt;
570 return glps__scan_bytes(str->c_str(), str->size(), scanner);
578 YY_BUFFER_STATE setup_bytes(yyscan_t scanner,
void* pvt)
580 bytebuf *buf =
static_cast<bytebuf*
>(pvt);
581 return glps__scan_bytes(buf->bytes, buf->len, scanner);
585 void parse_context::parse(FILE *fp)
587 parse_common(&setup_file,
this, (
void*)fp);
590 void parse_context::parse(
const char* s,
size_t len)
592 bytebuf buf = {s, len};
593 parse_common(&setup_bytes,
this, (
void*)&buf);
596 void parse_context::parse(
const std::string& s)
598 parse_common(&setup_string,
this, (
void*)&s);
602 parse_context::addop(
const char *name,
603 operation_t::eval_t fn,
604 glps_expr_type R,
unsigned N, ...)
609 operations.insert(std::make_pair(name,
610 operation_t(name, fn, R, N, args)