From ef864ce9820080be4fac86d3e5f45eb35806802b Mon Sep 17 00:00:00 2001
From: gscalamera <graziano.scalamera@elettra.eu>
Date: Wed, 22 Feb 2017 16:43:16 +0100
Subject: [PATCH] Upgraded parser to support quality, min, max, sin, cos
 conditional expression and string comparison

---
 src/Alarm.cpp         | 287 ++++++++++++++++++++++++++++++++----------
 src/Alarm.h           |   1 -
 src/alarm_table.cpp   |   9 --
 src/alarm_table.h     |  14 +--
 src/event_table.cpp   |  12 +-
 src/event_table.h     |   4 +-
 src/formula_grammar.h | 150 +++++++++++++++++-----
 7 files changed, 348 insertions(+), 129 deletions(-)

diff --git a/src/Alarm.cpp b/src/Alarm.cpp
index c49c801..7f3aa79 100644
--- a/src/Alarm.cpp
+++ b/src/Alarm.cpp
@@ -390,8 +390,18 @@ void Alarm::init_device()
 	rule_names[formula_grammar::mult_exprID] = "MultE";
 	rule_names[formula_grammar::expr_atomID] = "AtomicE";
 	rule_names[formula_grammar::shift_exprID] = "ShiftE";
-	rule_names[formula_grammar::unary_exprID] = "UnaryE";    	
-	
+	rule_names[formula_grammar::unary_exprID] = "UnaryE";
+	rule_names[formula_grammar::funcID] = "FunctionE";
+	rule_names[formula_grammar::nameID] = "NameE";
+	rule_names[formula_grammar::indexID] = "IndexE";
+	rule_names[formula_grammar::val_stringID] = "ValString";
+	rule_names[formula_grammar::func_dualID] = "FuncDualE";
+	rule_names[formula_grammar::logical_expr_parenID] = "LogicalParenE";
+	rule_names[formula_grammar::cond_exprID] = "ConditionalE";
+	rule_names[formula_grammar::nonempty_exprID] = "NonEmptyE";
+	rule_names[formula_grammar::exprID] = "Expression";
+	rule_names[formula_grammar::val_qualityID] = "ValQuality";
+
 	/*
 	 * get device attribute properties and initialize internal
 	 * data structures
@@ -1940,13 +1950,9 @@ void Alarm::modify(Tango::DevString argin)
 	alm.send_arg_n = false;
 	alm.dp_n = NULL;
 
-#ifndef _ACCESS_NODE_D
-	alm.formula_tree = ast_parse(alarm_string.c_str(), al_gr, space_p);	//parse string s with grammar al_gr, skipping white spaces
-#else
 	alm.formula_tree =
 	//boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp =
 	ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p);	//parse string s with grammar al_gr, skipping white spaces
-#endif
 	if (alm.formula_tree.full)
 	{
     	std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower);		//transform to lowercase
@@ -1986,11 +1992,7 @@ void Alarm::modify(Tango::DevString argin)
     else
     {
        	ostringstream o;
-#ifndef _ACCESS_NODE_D
-		o << __func__<<": Parsing Failed, syntax error stopped at " << alm.formula_tree.stop << ends;
-#else
 		o << __func__<<": Parsing Failed, syntax error stopped at " << string(alm.formula_tree.stop, alarm_string.end()) << ends; //TODO
-#endif
        	DEBUG_STREAM << o.str() << endl;
        	Tango::Except::throw_exception( \
 				(const char*)"Parsing Failed!", \
@@ -2238,13 +2240,9 @@ void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
 	alm.dp_n = NULL;
 	evn.clear();	
 
-#ifndef _ACCESS_NODE_D	
-	alm.formula_tree = ast_parse(alarm_string.c_str(), al_gr, space_p);	//parse string s with grammar al_gr, skipping white spaces	
-#else	
 	alm.formula_tree = 
 	//boost::spirit::tree_parse_info< std::string::iterator, factory_t> tmp =
 	ast_parse<factory_t>(alarm_string.begin(), alarm_string.end(), al_gr, space_p);	//parse string s with grammar al_gr, skipping white spaces
-#endif
 	if (alm.formula_tree.full)
 	{
     	std::transform(alm.name.begin(), alm.name.end(), alm.name.begin(), (int(*)(int))tolower);		//transform to lowercase
@@ -2307,11 +2305,7 @@ void Alarm::load_alarm(string alarm_string, alarm_t &alm, vector<string> &evn)
     else
     {
        	ostringstream o;
-#ifndef _ACCESS_NODE_D       	
-		o << "Alarm::load_alarm(): Parsing Failed, syntax error stopped at " << alm.formula_tree.stop << ends;
-#else       	
 		o << "Alarm::load_alarm(): Parsing Failed, syntax error stopped at " << string(alm.formula_tree.stop, alarm_string.end()) << ends; //TODO
-#endif		
        	DEBUG_STREAM << o.str() << endl;
        	Tango::Except::throw_exception( \
 				(const char*)"Parsing Failed!", \
@@ -2729,6 +2723,7 @@ void Alarm::do_alarm(bei_t& e)
 	if (found != events->v_event.end())
 	{	
 		found->value = e.value;
+		found->value_string = e.value_string;
 		found->quality = e.quality;
 		//found->errors = e.errors;
 		found->ex_reason = e.ex_reason;
@@ -3230,44 +3225,27 @@ formula_res_t Alarm::eval_expression(iter_t const& i, string &attr_values, int e
         	throw err.str(); 
         }     		
         string val_st(i->value.begin(), i->value.end());
-#ifndef _ACCESS_NODE_D    
- 		Tango::DevState st;     
-		if(val_st == "ON")
-        	st = Tango::ON;
-        else if(val_st == "OFF")
-        	st = Tango::OFF;
-       	else if(val_st == "CLOSE")
-        	st = Tango::CLOSE;
-        else if(val_st == "OPEN")
-        	st = Tango::OPEN;
-        else if(val_st == "INSERT")
-        	st = Tango::INSERT;
-        else if(val_st == "EXTRACT")
-        	st = Tango::EXTRACT;
-        else if(val_st == "MOVING")
-        	st = Tango::MOVING;
-        else if(val_st == "STANDBY")
-        	st = Tango::STANDBY;
-        else if(val_st == "FAULT")
-        	st = Tango::FAULT;
-        else if(val_st == "INIT")
-        	st = Tango::INIT;
-        else if(val_st == "RUNNING")
-        	st = Tango::RUNNING;  
-        else if(val_st == "ALARM")
-        	st = Tango::ALARM; 
-        else if(val_st == "DISABLE")
-        	st = Tango::DISABLE; 
-        else if(val_st == "UNKNOWN")
-        	st = Tango::UNKNOWN;               	
-#else
         double st =  i->value.value();			//get value directly from node saved with access_node_d
-#endif //_ACCESS_NODE_D    	        	        	      	        	        	        	        	        	        	        	        	
 		DEBUG_STREAM << "		node value state : " << val_st << "=" << st << endl;
 		formula_res_t res;
 		res.value = st;
         return res;
-    }       
+    }
+	else if (i->value.id() == formula_grammar::val_qualityID)
+	{
+		if(i->children.size() != 0)
+		{
+			err <<  "in node val_qualityID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
+			throw err.str();
+		}
+		string val_quality(i->value.begin(), i->value.end());
+
+		double quality =  i->value.value();			//get value directly from node saved with access_node_d
+		DEBUG_STREAM << "		node value quality : " << val_quality << "=" << quality << endl;
+		formula_res_t res;
+		res.value = quality;
+        return res;
+	}
     else if (i->value.id() == formula_grammar::unary_exprID)
     {
 		DEBUG_STREAM << "		node unary expression: " << string(i->value.begin(), i->value.end()) << endl;
@@ -3371,7 +3349,7 @@ formula_res_t Alarm::eval_expression(iter_t const& i, string &attr_values, int e
 				err <<  "in node nameID(" << string(i->value.begin(), i->value.end()) << ") value not valid!" << ends;
         		throw err.str();
         	}	
-			else if(it->value.empty())
+			else if(it->type != Tango::DEV_STRING && it->value.empty())
 			{
 				err <<  "in node nameID(" << string(i->value.begin(), i->value.end()) << ") value not initialized!!" << ends;
         		throw err.str();
@@ -3538,22 +3516,92 @@ formula_res_t Alarm::eval_expression(iter_t const& i, string &attr_values, int e
 		{
         	err <<  "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
         	throw err.str(); 
-        }	
-		if (string(i->value.begin(), i->value.end()) == string("!="))
-        {
-            return eval_expression(i->children.begin(), attr_values) !=
-                eval_expression(i->children.begin()+1, attr_values);
         }
-		else if (string(i->value.begin(), i->value.end()) == string("=="))
-        {
-            return eval_expression(i->children.begin(), attr_values) ==
-                eval_expression(i->children.begin()+1, attr_values);
-        }       
-        else
-        {
-        	err <<  "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
-        	throw err.str(); 
-        }			   
+
+
+		//string comparison here
+		iter_t const& i2_1 = i->children.begin();
+		iter_t const& i2_2 = i->children.begin()+1;
+		//OK only attr == 'string' or attr != 'string'
+		if(i2_1->value.id() == formula_grammar::nameID && i2_2->value.id() == formula_grammar::val_stringID)
+		{
+			if(i2_1->children.size() == 0 && i2_2->children.size() == 0)
+			{
+				//retrieve string from attribute:
+				string attr_val = "";
+				string name_id(i2_1->value.begin(), i2_1->value.end());
+				std::transform(name_id.begin(), name_id.end(), name_id.begin(), (int(*)(int))tolower);		//transform to lowercase
+				formula_res_t res;
+				vector<event>::iterator it = events->v_event.begin();
+
+				while ((it != events->v_event.end()) && (it->name != name_id))
+						it++;
+				if (it != events->v_event.end())
+				{
+					if(!it->valid)
+					{
+						err <<  "in node nameID(" << string(i2_1->value.begin(), i2_1->value.end()) << ") value not valid!" << ends;
+						throw err.str();
+					}
+					else if(it->type != Tango::DEV_STRING && it->value.empty())
+					{
+						err <<  "in node nameID(" << string(i2_1->value.begin(), i2_1->value.end()) << ") value not initialized!!" << ends;
+						throw err.str();
+					}
+					ostringstream temp_attr_val;
+					temp_attr_val << it->name << "=" <<it->value_string << ";";
+					attr_values += temp_attr_val.str();
+					res.quality = it->quality;
+					res.ex_reason = it->ex_reason;
+					res.ex_desc = it->ex_desc;
+					res.ex_origin = it->ex_origin;
+					DEBUG_STREAM << "		node name -> " << temp_attr_val.str() << " quality=" << res.quality << endl;
+					attr_val =  string("'") + it->value_string + string("'");
+				}
+				else
+				{
+					err <<  "in event: (" << string(i->value.begin(), i->value.end()) << ") not found in event table" << ends;
+					throw err.str();
+				}
+
+				//retrieve string from formula
+				string val_string(i2_2->value.begin(), i2_2->value.end());
+
+				if (string(i->value.begin(), i->value.end()) == string("!="))
+				{
+					res.value = attr_val != val_string;
+					return res;
+				}
+				else if (string(i->value.begin(), i->value.end()) == string("=="))
+				{
+					res.value = attr_val == val_string;
+					return res;
+				}
+				else
+				{
+					err <<  "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed (val_stringID)" << ends;
+					throw err.str();
+				}
+			}
+		}
+		else
+		{
+			if (string(i->value.begin(), i->value.end()) == string("!="))
+			{
+				return eval_expression(i->children.begin(), attr_values) !=
+					eval_expression(i->children.begin()+1, attr_values);
+			}
+			else if (string(i->value.begin(), i->value.end()) == string("=="))
+			{
+				return eval_expression(i->children.begin(), attr_values) ==
+					eval_expression(i->children.begin()+1, attr_values);
+			}
+			else
+			{
+				err <<  "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
+				throw err.str();
+			}
+		}
     }   
     else if (i->value.id() == formula_grammar::compare_exprID)
     {
@@ -3599,9 +3647,110 @@ formula_res_t Alarm::eval_expression(iter_t const& i, string &attr_values, int e
         }
 		formula_res_t res;
 		res = eval_expression(i->children.begin(), attr_values);
-		res.value = fabs(res.value);
-		return res;			//now handled only abs as function
+
+		if (string(i->value.begin(), i->value.end()) == string("abs"))
+		{
+			res.value = fabs(res.value);
+			return res;
+		}
+		else if (string(i->value.begin(), i->value.end()) == string("cos"))
+		{
+			res.value = cos(res.value);
+			return res;
+		}
+		else if (string(i->value.begin(), i->value.end()) == string("sin"))
+		{
+			res.value = sin(res.value);
+			return res;
+		}
+		else if (string(i->value.begin(), i->value.end()) == string("quality"))
+		{
+			if(i->children.size() != 1)
+			{
+				err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
+				throw err.str();
+			}
+			if(i->children.begin()->value.id() != formula_grammar::nameID)
+			{
+				string name_id(i->children.begin()->value.begin(), i->children.begin()->value.end());
+				err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << ") children is not an attribute name but " << name_id << ends;
+				throw err.str();
+			}
+			res.value = res.quality;
+			return res;
+		}
+		else
+		{
+			err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
+			throw err.str();
+		}
     }  
+	else if (i->value.id() == formula_grammar::func_dualID)
+	{
+		DEBUG_STREAM << "		node function dual: " << string(i->value.begin(), i->value.end()) << endl;
+		if(i->children.size() != 2)
+		{
+			err <<  "in node func_dualID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
+			throw err.str();
+		}
+		formula_res_t res_1=eval_expression(i->children.begin(), attr_values),
+           	res_2=eval_expression(i->children.begin()+1, attr_values);
+		if (string(i->value.begin(), i->value.end()) == string("min"))
+		{
+        	formula_res_t res;
+        	res.value = min(res_1.value, res_2.value);
+        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+        	res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
+        	res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
+        	res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
+            return res;
+		}
+		else if (string(i->value.begin(), i->value.end()) == string("max"))
+		{
+        	formula_res_t res;
+        	res.value = max(res_1.value, res_2.value);
+        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+        	res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
+        	res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
+        	res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
+            return res;
+		}
+		else if (string(i->value.begin(), i->value.end()) == string("pow"))
+		{
+        	formula_res_t res;
+        	res.value = pow(res_1.value, res_2.value);
+        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+        	res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
+        	res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
+        	res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
+            return res;
+		}
+		else
+		{
+			err <<  "in node func_dualID(" << string(i->value.begin(), i->value.end()) << ") value not allowed" << ends;
+			throw err.str();
+		}
+	}
+	else if (i->value.id() == formula_grammar::cond_exprID)
+	{
+		DEBUG_STREAM << "		node ternary_if expression: " << string(i->value.begin(), i->value.end()) << endl;
+		if(i->children.size() != 3)
+		{
+			err <<  "in node ternary_ifID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size() << ends;
+			throw err.str();
+		}
+		formula_res_t res_1=eval_expression(i->children.begin(), attr_values);
+		if(res_1.value)
+		{
+        	formula_res_t res = eval_expression(i->children.begin()+1, attr_values);
+            return res;
+		}
+		else
+		{
+        	formula_res_t res = eval_expression(i->children.begin()+2, attr_values);
+            return res;
+		}
+	}
     else
     {
         DEBUG_STREAM << "		node unknown id: " << string(i->value.begin(), i->value.end()) << endl;
diff --git a/src/Alarm.h b/src/Alarm.h
index 9bd4f81..39e2af9 100644
--- a/src/Alarm.h
+++ b/src/Alarm.h
@@ -42,7 +42,6 @@
 #include <mysql.h>
 
 #include <boost/version.hpp>
-#define _ACCESS_NODE_D 1
 #if BOOST_VERSION  >= 103600
 #define BOOST_VER_1_36_0 1
 #endif
diff --git a/src/alarm_table.cpp b/src/alarm_table.cpp
index 6bdc90f..09c43dd 100644
--- a/src/alarm_table.cpp
+++ b/src/alarm_table.cpp
@@ -20,7 +20,6 @@
 #include "log_thread.h"
 #include "cmd_thread.h"
 
-#define _ACCESS_NODE_D 1
 
 static const char __FILE__rev[] = __FILE__ " $Revision: 1.5 $";
 
@@ -193,11 +192,7 @@ void alarm_table::init(vector<string>& avs, vector<string> &evn, map< string,vec
 			tmp_alm.msg.clear();
 			tmp_alm.lev.clear();
 			tmp_alm.grp=0;
-#ifndef _ACCESS_NODE_D 			
-			parse_info<> info = parse(i->c_str(), al, space_p);	//parse string i with grammar al, skipping white spaces
-#else			
 			tree_parse_info_t info = ast_parse<factory_t>(i->begin(), i->end(), al, space_p);
-#endif
 			if (info.full)
 			{
            		LOG_STREAM << gettime().tv_sec << " Parsing succeeded: " << tmp_alm.name << endl;
@@ -206,11 +201,7 @@ void alarm_table::init(vector<string>& avs, vector<string> &evn, map< string,vec
 			}	           		
        		else
         	{
-#ifndef _ACCESS_NODE_D       	
-				LOG_STREAM << gettime().tv_sec << " Parsing failed, stopped at: " << info.stop << endl;
-#else       	
 				LOG_STREAM << gettime().tv_sec << " Parsing failed, stopped at: " << string(info.stop, i->end()) << ends; //TODO
-#endif            	
         	}
 
 			if ((tmp_alm.name.empty() == false) && \
diff --git a/src/alarm_table.h b/src/alarm_table.h
index 88dd24a..e829767 100644
--- a/src/alarm_table.h
+++ b/src/alarm_table.h
@@ -52,30 +52,18 @@
 
 using namespace std;
 
-//#define _ACCESS_NODE_D 1
+
 #if BOOST_VERSION  < 103600
-#ifndef _ACCESS_NODE_D
-typedef char const*         iterator_t;
-typedef boost::spirit::tree_match<iterator_t> parse_tree_match_t;
-typedef boost::spirit::tree_parse_info<>    tree_parse_info_t;
-#else
 typedef std::string::iterator  iterator_t;
 typedef boost::spirit::node_val_data_factory<unsigned int> factory_t;		//want a modified node to contain an unsigned int value
 typedef boost::spirit::tree_match<iterator_t, factory_t> parse_tree_match_t;     
 typedef boost::spirit::tree_parse_info<iterator_t, factory_t>    tree_parse_info_t;   
-#endif
-#else
-#ifndef _ACCESS_NODE_D
-typedef char const*         iterator_t;
-typedef boost::spirit::classic::tree_match<iterator_t> parse_tree_match_t;
-typedef boost::spirit::classic::tree_parse_info<>    tree_parse_info_t;
 #else
 typedef std::string::iterator  iterator_t;
 typedef boost::spirit::classic::node_val_data_factory<unsigned int> factory_t;		//want a modified node to contain an unsigned int value
 typedef boost::spirit::classic::tree_match<iterator_t, factory_t> parse_tree_match_t;     
 typedef boost::spirit::classic::tree_parse_info<iterator_t, factory_t>    tree_parse_info_t;   
 #endif
-#endif
 
 typedef parse_tree_match_t::tree_iterator iter_t;
 
diff --git a/src/event_table.cpp b/src/event_table.cpp
index 020b9fb..eeed814 100644
--- a/src/event_table.cpp
+++ b/src/event_table.cpp
@@ -1120,7 +1120,7 @@ void EventCallBack::push_event(Tango::EventData* ev)
 			e.ev_name = ev->attr_name;
 #endif
 			e.ts = ev->attr_value->time;
-			extract_values(ev->attr_value, e.value, e.type);
+			extract_values(ev->attr_value, e.value, e.value_string, e.type);
 		} else {
 #if 0//TANGO_VER >= 711
  			string ev_name_str(ev->attr_name);
@@ -1181,13 +1181,11 @@ void EventCallBack::push_event(Tango::EventData* ev)
 	static_cast<Alarm_ns::Alarm *>(mydev)->evlist.push_back(e);
 }  /* push_event() */
 
-void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, int &type)
+void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type)
 {
 	Tango::DevState stval;
 	vector<Tango::DevState> v_st;
-#if 1//TANGO_VER >= 600
 	vector<Tango::DevULong> v_ulo;
-#endif
 	vector<Tango::DevUChar> v_uch;
 	vector<Tango::DevShort> v_sh;
 	vector<Tango::DevUShort> v_ush;
@@ -1197,6 +1195,8 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
 	vector<Tango::DevBoolean> v_bo;
 	vector<Tango::DevLong64> v_lo64;
 	vector<Tango::DevULong64> v_ulo64;
+	vector<string> v_string;
+	val_string = string("");
 
 	if (attr_value->get_type() == Tango::DEV_UCHAR) {
 		*(attr_value) >> v_uch;
@@ -1257,6 +1257,10 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
 		for(vector<Tango::DevULong64>::iterator  it = v_ulo64.begin(); it != v_ulo64.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_ULONG64;
+	} else if (attr_value->get_type() == Tango::DEV_STRING) {
+		*(attr_value) >> v_string;
+		val_string = *(v_string.begin());	//TODO: support string spectrum attrbutes
+		type = Tango::DEV_STRING;
 	}
 	else {
 		ostringstream o;
diff --git a/src/event_table.h b/src/event_table.h
index d9beb8e..8e6f95e 100644
--- a/src/event_table.h
+++ b/src/event_table.h
@@ -49,6 +49,7 @@ class event {
 		string	devname;
 		string	attname;
 		value_t value;				/* event value */
+		string value_string;	//added for DevString attributes
 		int quality;
 		//Tango::DevErrorList 	errors;
 		string ex_reason;
@@ -101,6 +102,7 @@ class event {
 typedef struct basic_event_info_s {
 	string ev_name;
 	value_t value;
+	string value_string;
 	int quality;
 	//Tango::DevErrorList 	errors;
 	string ex_reason;
@@ -190,7 +192,7 @@ class EventCallBack : public Tango::CallBack, public Tango::LogAdapter
 		~EventCallBack(void);
 		void push_event(Tango::EventData* ev);
 		//void init(event_list* e);
-		void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, int &type);
+		void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type);
 	private:
 		//event_list* e_ptr;
 		Tango::DeviceImpl *mydev;
diff --git a/src/formula_grammar.h b/src/formula_grammar.h
index f3bc90a..5b0c94c 100644
--- a/src/formula_grammar.h
+++ b/src/formula_grammar.h
@@ -15,6 +15,7 @@
 #ifndef FORMULA_GRAMMAR_H_
 #define FORMULA_GRAMMAR_H_
 
+#include <boost/version.hpp>
 
 //#define BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING  //test trying to have node also if formula of type (ev/ev/ev/ev) 27/02/2008
 
@@ -24,23 +25,25 @@
 #endif
 #endif
 
-#if BOOST_VERSION  < 103600     
+#if BOOST_VERSION  < 103600
 #include <boost/spirit/core.hpp>
 #include <boost/spirit/tree/ast.hpp>
+//for ast parse trees (in tree_formula)
+#include <boost/spirit/symbols/symbols.hpp>				//for symbol table
 using namespace boost::spirit;
 #else
 #include <boost/spirit/include/classic_core.hpp>
 #include <boost/spirit/include/classic_ast.hpp>
-using namespace boost::spirit::classic;	
+//for ast parse trees (in tree_formula)
+#include <boost/spirit/include/classic_symbols.hpp>				//for symbol table
+using namespace boost::spirit::classic;
 #endif
-				//for ast parse trees (in tree_formula)
-//#include <boost/spirit/symbols/symbols.hpp>				//for symbol table
+
 
 using namespace std;  
 
 
 
-#ifdef _ACCESS_NODE_D
 /*typedef char const*                    iterator_t;       
 typedef node_val_data_factory<unsigned int>    factory_t;
 typedef tree_match<iterator_t, factory_t>        parse_tree_match_t;   
@@ -60,7 +63,7 @@ static void Assign_Stat (tree_node_t & node, const iterator_t & begin, const ite
 	node.value.value(stat_tmp);
 }*/
 
-unsigned int stat_tmp;
+static unsigned int stat_tmp;
 struct Save_Stat
 {   
 	void operator () (unsigned int val) const
@@ -77,9 +80,19 @@ struct Assign_Stat
 	}
 };
 
-#endif //_ACCESS_NODE_D
 struct formula_grammar : public grammar<formula_grammar>
 {
+
+	/*formula_t &m_formula;
+
+	symbols<unsigned int> sym_grp;
+
+	formula_grammar(formula_t &f) \
+		: m_formula(f)
+		{
+
+		}*/
+
     static const int val_rID = 1;
     static const int val_hID = 2; 
     static const int val_stID = 3;    
@@ -96,8 +109,16 @@ struct formula_grammar : public grammar<formula_grammar>
     static const int expr_atomID = 14;
     static const int shift_exprID = 15;
     static const int unary_exprID = 16;
+    static const int val_stringID = 17;	//TODO: OK ?
+    static const int func_dualID = 18;
+    static const int logical_expr_parenID = 19;
+    static const int cond_exprID = 20;
+    static const int exprID = 21;
+    static const int nonempty_exprID = 22;
+    static const int val_qualityID = 23;
     
-    symbols<unsigned int> tango_states;           
+    symbols<unsigned int> tango_states;
+    symbols<unsigned int> attr_quality;
     
 	formula_grammar() 
 	{
@@ -115,6 +136,12 @@ struct formula_grammar : public grammar<formula_grammar>
 		tango_states.add("ALARM", (unsigned int)Tango::ALARM);
 		tango_states.add("DISABLE", (unsigned int)Tango::DISABLE);
 		tango_states.add("UNKNOWN", (unsigned int)Tango::UNKNOWN);
+
+		attr_quality.add("ATTR_VALID", (unsigned int)Tango::ATTR_VALID);
+		attr_quality.add("ATTR_INVALID", (unsigned int)Tango::ATTR_INVALID);
+		attr_quality.add("ATTR_ALARM", (unsigned int)Tango::ATTR_ALARM);
+		attr_quality.add("ATTR_CHANGING", (unsigned int)Tango::ATTR_CHANGING);
+		attr_quality.add("ATTR_WARNING", (unsigned int)Tango::ATTR_WARNING);
 	}   
    
     template <typename ScannerT>
@@ -139,7 +166,7 @@ struct formula_grammar : public grammar<formula_grammar>
         definition(formula_grammar const& self)
         {      
             symbol
-            	=	(alnum_p | '.' | '_' | '-' | '+')				//any alpha numeric char plus '.', '_', '-', '+'
+            	=	(alnum_p | '.' | '_' | '-' | '+')				//any alpha numeric char plus '.', '_', '-'
             	;
             //------------------------------ALARM NAME--------------------------------------	
             name
@@ -176,21 +203,45 @@ struct formula_grammar : public grammar<formula_grammar>
 				;
 			val_st
 				=
-#ifndef _ACCESS_NODE_D				
-					token_node_d[self.tango_states]				//match only group defined in sym_grp symbol table				            	   
-#else				
 					//access_node_d[self.tango_states[&Save_Stat]][&Assign_Stat]	//save Tango::state value in node
 					access_node_d[self.tango_states[Save_Stat()]][Assign_Stat()]	//save Tango::state value in node
-#endif //_ACCESS_NODE_D					
+            	;
+			val_quality
+				=
+					//access_node_d[self.tango_states[&Save_Stat]][&Assign_Stat]	//save Tango::state value in node
+					access_node_d[self.attr_quality[Save_Stat()]][Assign_Stat()]	//save Tango::state value in node
+            	;
+            val_string
+#if BOOST_VERSION  < 103600
+            	=	token_node_d[
+#else
+            	=	reduced_node_d[
+#endif
+            	 	    lexeme_d[							//to conserve white spaces
+            				ch_p('\'')
+            				>> (+(anychar_p - '\'')) 		//one ore more char except '"'
+            				>> '\''
+            			]
+            		]
+//            	=	repeat_p(3)[(+symbol) >> ch_p('/')] >> (+symbol)
             	;
 
 			event_
 				=	name
 					>> !(index)
 				;				
-				
-			top = logical_expr
-				;	
+
+			/*top = ternary_if;
+
+			ternary_if
+			   =	logical_expr_paren
+			   	   >> !(root_node_d[str_p("?")] >> logical_expr_paren >> discard_node_d[ch_p(':')] >> logical_expr_paren)
+			    ;*/
+
+			cond_expr = logical_expr >> *(root_node_d[ch_p('?')] >> cond_expr >> discard_node_d[ch_p(':')] >> cond_expr);
+
+			/*top = logical_expr
+				;*/
 
             logical_expr
                 = 	bitwise_expr
@@ -235,36 +286,64 @@ struct formula_grammar : public grammar<formula_grammar>
                 		)
                 ;
             mult_expr
-                = 	expr_atom 
-                	>> *(	(root_node_d[ch_p('*')] >> expr_atom)
-                		| 	(root_node_d[ch_p('/')] >> expr_atom)
+                = 	unary_expr
+                	>> *(	(root_node_d[ch_p('*')] >> unary_expr)
+                		| 	(root_node_d[ch_p('/')] >> unary_expr)
                 		)
                 ;
-            function
-            	=	root_node_d[str_p("abs")] >> (inner_node_d[ch_p('(') >> logical_expr >> ')'])
-            	;
+
             unary_expr
-            	=	(	(root_node_d[ch_p('+')] >> expr_atom)
+            	=	(	expr_atom
+            		 |	function
+            		 |	function_dual
+            		 |	(root_node_d[ch_p('+')] >> expr_atom)
             		 |	(root_node_d[ch_p('-')] >> expr_atom)
             		 |	(root_node_d[ch_p('!')] >> expr_atom)
+            		// |	(root_node_d[ch_p('~')] >> expr_atom)	//TODO
+            		)
+            	;
+
+            function
+            	=	( root_node_d[str_p("abs")] >> (inner_node_d[ch_p('(') >> cond_expr >> ')'])	//TODO: ? not expr_atom ?
+            		| root_node_d[str_p("cos")] >> (inner_node_d[ch_p('(') >> cond_expr >> ')'])	//TODO: ? not expr_atom ?
+            		| root_node_d[str_p("sin")] >> (inner_node_d[ch_p('(') >> cond_expr >> ')'])	//TODO: ? not expr_atom ?
+					| root_node_d[str_p("quality")] >> (inner_node_d[ch_p('(') >> name >> ')'])	//TODO: ? not expr_atom ?
             		)
             	;
+            function_dual
+        	=	(	(root_node_d[str_p("max")] >> (inner_node_d[ch_p('(') >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> ')']))
+        		//|	(root_node_d[str_p("max")] >> (inner_node_d[ch_p('(') >> discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')] >> discard_node_d[ch_p(',')] >> discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')] >> ')']))
+        		|	(root_node_d[str_p("min")] >> (inner_node_d[ch_p('(') >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> ')']))
+        		//|	(root_node_d[str_p("min")] >> (inner_node_d[ch_p('(') >> discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')] >> discard_node_d[ch_p(',')] >> discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')] >> ')']))
+				|	(root_node_d[str_p("pow")] >> (inner_node_d[ch_p('(') >> cond_expr >> discard_node_d[ch_p(',')] >> cond_expr >> ')']))
+        		)
+            	//=	*(	(root_node_d[str_p("max")] >> (inner_node_d[ch_p('(') >> logical_expr_paren >> discard_node_d[ch_p(',')] >> logical_expr_paren >> ')']))
+            	//	|	(root_node_d[str_p("min")] >> (inner_node_d[ch_p('(') >> logical_expr_paren >> discard_node_d[ch_p(',')] >> logical_expr_paren >> ')']))
+            		//|	(root_node_d[str_p("min")] >> (discard_node_d[ch_p('(')] >> logical_expr_paren >> discard_node_d[ch_p(',')] >> logical_expr_paren >> discard_node_d[ch_p(',')]))
+            		//|	(root_node_d[str_p("min")] >> (ch_p('(') >> expr_atom >> ch_p(',') >> expr_atom >> ch_p(',')))
+            		//)
+            	;
+
+            non_empty_expression = cond_expr;
+            top = non_empty_expression | epsilon_p;
+           // top = non_empty_expression;
+
             expr_atom
-                =	//val_h | val_r	              
+                =	//val_h | val_r
 					event_
-                	| unary_expr					
-					| val_h | val_r | val_st
-               		| function										     
-                	//| (inner_node_d[ch_p('(') >> logical_expr >> ')'])
-                	| (discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')])
-                	| unary_expr
-
+					| val_h | val_r | val_st  | val_quality | val_string
+                	//| (inner_node_d[ch_p('(') >> non_empty_expression >> ')'])
+               		| (discard_node_d[ch_p('(')] >> non_empty_expression >> discard_node_d[ch_p(')')])
+                ;
+            logical_expr_paren
+            	=	(discard_node_d[ch_p('(')] >> logical_expr >> discard_node_d[ch_p(')')])
+                	| logical_expr
                 ;
         }
         
         rule<ScannerT> top;
         //rule<ScannerT> symbol;
-        rule<typename lexeme_scanner<ScannerT>::type> symbol;					//neede to use lexeme_d in rule name
+        rule<typename lexeme_scanner<ScannerT>::type> symbol;					//needed to use lexeme_d in rule name
         rule<ScannerT, parser_context<>, parser_tag<val_rID> > val_r;
         rule<ScannerT, parser_context<>, parser_tag<val_hID> > val_h;
         rule<ScannerT, parser_context<>, parser_tag<val_stID> > val_st;        
@@ -281,6 +360,13 @@ struct formula_grammar : public grammar<formula_grammar>
         rule<ScannerT, parser_context<>, parser_tag<funcID> > function;
 		rule<ScannerT, parser_context<>, parser_tag<nameID> > name;
 		rule<ScannerT, parser_context<>, parser_tag<indexID> > index;
+		rule<ScannerT, parser_context<>, parser_tag<val_stringID> > val_string;
+		rule<ScannerT, parser_context<>, parser_tag<func_dualID> > function_dual;
+		rule<ScannerT, parser_context<>, parser_tag<logical_expr_parenID> > logical_expr_paren;
+		rule<ScannerT, parser_context<>, parser_tag<cond_exprID> > cond_expr;
+		rule<ScannerT, parser_context<>, parser_tag<nonempty_exprID> > non_empty_expression;
+		rule<ScannerT, parser_context<>, parser_tag<exprID> > expression;
+		rule<ScannerT, parser_context<>, parser_tag<val_qualityID> > val_quality;
 
         rule<ScannerT> const&
         start() const { return top; }      
-- 
GitLab