Commit c1f4db8e040ca942fe896b40cb385eecbec85ba7
1 parent
ef417f05
Exists in
master
and in
87 other branches
Add process to test the parser
Showing
9 changed files
with
172 additions
and
40 deletions
Show diff stats
src/Common/DicError.hh
... | ... | @@ -32,6 +32,11 @@ enum { |
32 | 32 | AMDA_LOCALFILE_TIMEPARAM = 21, /// Cannot find time parameter |
33 | 33 | AMDA_OUTOFTIME_ERR = 22, /// Out of data time |
34 | 34 | |
35 | + /* | |
36 | + * Parser error | |
37 | + */ | |
38 | + AMDA_PARSER_TEST_ERROR = 30, /// At leat an error occured during test of the parser | |
39 | + | |
35 | 40 | /*------------ Errors of DD_serveur ---------------------*/ |
36 | 41 | AMDA_ERROR_NOCONNECTION =-1, // No connection with DD_server |
37 | 42 | AMDA_ERROR_TOOMANYREQ =-2, // too many request | ... | ... |
src/expressionParser/CMakeLists.txt
src/expressionParser/ExpressionPrinter.hh
... | ... | @@ -3,6 +3,8 @@ |
3 | 3 | |
4 | 4 | #include "ExpressionContainer.hh" |
5 | 5 | |
6 | +//#define ADD_DEBUG_TAG | |
7 | + | |
6 | 8 | namespace AMDA { |
7 | 9 | namespace parser { |
8 | 10 | namespace Expression { |
... | ... | @@ -10,24 +12,47 @@ namespace Expression { |
10 | 12 | class ExpressionPrinter : public boost::static_visitor<void> |
11 | 13 | { |
12 | 14 | public: |
13 | - ExpressionPrinter(std::ostream& os) : _os(os) {} | |
14 | - std::ostream& _os; | |
15 | + ExpressionPrinter(std::ostream& os) : _os(os) {} | |
16 | + std::ostream& _os; | |
15 | 17 | |
16 | - // | |
17 | - void operator()(const var& v) const { _os << v; } | |
18 | + void operator()(const var& v) const { | |
19 | + #ifdef ADD_DEBUG_TAG | |
20 | + _os << "@VAR@"; | |
21 | + #endif | |
22 | + _os << v; | |
23 | + } | |
18 | 24 | |
19 | - void operator()(const BinaryOperation& b) const { print(b.op.kernelSymbol, b.l, b.r); } | |
20 | - void operator()(const UnaryOperation& u) const{ printUnique(u.op.kernelSymbol,u.e); } | |
25 | + void operator()(const BinaryOperation& b) const { | |
26 | + #ifdef ADD_DEBUG_TAG | |
27 | + _os << "@BINOP@"; | |
28 | + #endif | |
29 | + _os << "("; | |
30 | + boost::apply_visitor(*this, b.l); | |
31 | + _os << b.op.kernelSymbol; | |
32 | + boost::apply_visitor(*this, b.r); | |
33 | + _os << ")"; | |
34 | + } | |
21 | 35 | |
22 | - void operator()(const FunctionOperation& f) const{ | |
23 | - _os << f.func << "("; | |
24 | - for (unsigned int i = 0; i < f.args.size(); ++i) { | |
25 | - if (i != 0) { | |
26 | - _os << ","; | |
27 | - } | |
28 | - boost::apply_visitor(*this, f.args[i]); | |
36 | + void operator()(const UnaryOperation& u) const{ | |
37 | + #ifdef ADD_DEBUG_TAG | |
38 | + _os << "@UNOP@"; | |
39 | + #endif | |
40 | + _os << u.op.kernelSymbol; | |
41 | + boost::apply_visitor(*this, u.e); | |
29 | 42 | } |
30 | - _os << ")"; | |
43 | + | |
44 | + void operator()(const FunctionOperation& f) const{ | |
45 | + #ifdef ADD_DEBUG_TAG | |
46 | + _os << "@FUNC@"; | |
47 | + #endif | |
48 | + _os << f.func << "("; | |
49 | + for (unsigned int i = 0; i < f.args.size(); ++i) { | |
50 | + if (i != 0) { | |
51 | + _os << ","; | |
52 | + } | |
53 | + boost::apply_visitor(*this, f.args[i]); | |
54 | + } | |
55 | + _os << ")"; | |
31 | 56 | } |
32 | 57 | |
33 | 58 | // Logical |
... | ... | @@ -38,20 +63,7 @@ public: |
38 | 63 | |
39 | 64 | // Functions |
40 | 65 | // printer |
41 | - void print(const std::string& op, const ExpressionContainer& l, const ExpressionContainer& r) const | |
42 | - { | |
43 | - _os << "("; | |
44 | - boost::apply_visitor(*this, l); | |
45 | - _os << op; | |
46 | - boost::apply_visitor(*this, r); | |
47 | - _os << ")"; | |
48 | - } | |
49 | 66 | |
50 | - void printUnique(const std::string& op, const ExpressionContainer& l) const | |
51 | - { | |
52 | - _os << op; | |
53 | - boost::apply_visitor(*this, l); | |
54 | - } | |
55 | 67 | void printPowerTen(const std::string& op, const ExpressionContainer& l, const ExpressionContainer& r) const |
56 | 68 | { |
57 | 69 | boost::apply_visitor(*this, l); | ... | ... |
src/expressionParser/Main.cc
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | |
13 | 13 | #include "log4cxx/logger.h" |
14 | 14 | #include "DicError.hh" |
15 | +#include "Helper.hh" | |
15 | 16 | |
16 | 17 | // Other includes |
17 | 18 | #include "ExpressionParser.hh" |
... | ... | @@ -37,6 +38,7 @@ int main(int argc, char *argv[]) { |
37 | 38 | ("help,h", "Produce help message") |
38 | 39 | ("version,v", "Program version") |
39 | 40 | ("expression,e", po::value< vector<string> >(), "expression(s) to parse") |
41 | + ("testfile,t", po::value< std::string >(), "CSV test file") | |
40 | 42 | ; |
41 | 43 | |
42 | 44 | po::positional_options_description p; |
... | ... | @@ -55,15 +57,49 @@ int main(int argc, char *argv[]) { |
55 | 57 | return result; |
56 | 58 | } |
57 | 59 | |
60 | + bool testRunning = false; | |
61 | + std::string testFile = ""; | |
62 | +std::cout << "BRE - " << (!vm.count("expression")) << std::endl; | |
58 | 63 | if (!vm.count("expression")) { |
59 | - return result; | |
64 | +std::cout << "BRE - " << !vm.count("testfile") << std::endl; | |
65 | + if (vm.count("testfile")) { | |
66 | + testFile = vm["testfile"].as<std::string>(); | |
67 | + testRunning = true; | |
68 | + } | |
69 | + else { | |
70 | + return result; | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + std::vector<std::vector<std::string> > testExpressions; | |
75 | + if (testRunning) | |
76 | + { | |
77 | + testExpressions = AMDA::Helpers::Helper::loadCSVFile(testFile.c_str(), ';'); | |
78 | + if (testExpressions.empty()) { | |
79 | + cout << "Cannot load test file or is empty: " << testFile << std::endl; | |
80 | + } | |
60 | 81 | } |
61 | 82 | |
62 | 83 | AMDA::Common::Application lMain; |
63 | 84 | |
64 | 85 | return lMain.main(argc,argv,[&](int , char **, AMDA::helpers::Properties& lProperties) -> int { |
86 | + std::vector<std::string> lExpressionList; | |
87 | + | |
88 | + if (testRunning) { | |
89 | + for (std::vector<std::vector<std::string>>::iterator it = testExpressions.begin(); it != testExpressions.end(); ++it) { | |
90 | + if (it == testExpressions.begin()) { | |
91 | + //Skip header line | |
92 | + continue; | |
93 | + } | |
94 | + if ((*it).size() >= 2) { | |
95 | + lExpressionList.push_back((*it)[0]); | |
96 | + } | |
97 | + } | |
98 | + } | |
99 | + else { | |
100 | + lExpressionList = vm["expression"].as< vector<string> >(); | |
101 | + } | |
65 | 102 | |
66 | - vector<string> lExpressionList = vm["expression"].as< vector<string> >(); | |
67 | 103 | std::map<std::string, std::string> expressionMap; |
68 | 104 | for(auto expression :lExpressionList){ |
69 | 105 | LOG4CXX_INFO(logger,"Parsing expression: "<<expression); |
... | ... | @@ -74,7 +110,22 @@ int main(int argc, char *argv[]) { |
74 | 110 | |
75 | 111 | } |
76 | 112 | } |
77 | - | |
113 | + | |
114 | + if (testRunning) { | |
115 | + for (std::vector<std::vector<std::string>>::iterator it = testExpressions.begin(); it != testExpressions.end(); ++it) { | |
116 | + if (it == testExpressions.begin()) { | |
117 | + //Skip header line | |
118 | + continue; | |
119 | + } | |
120 | + if ((*it).size() >= 2) { | |
121 | + if ((*it)[1].compare(expressionMap[(*it)[0]]) != 0) { | |
122 | + LOG4CXX_ERROR(logger, (*it)[0] << " parsed as : " << expressionMap[(*it)[0]] << " but waiting result is : " << (*it)[1]) | |
123 | + result = AMDA_PARSER_TEST_ERROR; | |
124 | + } | |
125 | + | |
126 | + } | |
127 | + } | |
128 | + } | |
78 | 129 | |
79 | 130 | |
80 | 131 | return result; | ... | ... |
src/expressionParser/ParserGrammar.hh
... | ... | @@ -18,6 +18,8 @@ namespace qi = boost::spirit::qi; |
18 | 18 | using namespace qi; |
19 | 19 | using namespace Expression; |
20 | 20 | |
21 | +#define PARSERGRAMMAR_ADD_OPERATOR(operation, next, operator) fold<operation>(next.alias())[operator >> next] | |
22 | + | |
21 | 23 | template <typename It, typename Skipper = boost::spirit::standard_wide::space_type> |
22 | 24 | class ParserGrammar : public qi::grammar<It, Expression::ExpressionContainer(), Skipper> |
23 | 25 | { |
... | ... | @@ -27,21 +29,22 @@ public: |
27 | 29 | expr_ = or_.alias(); |
28 | 30 | |
29 | 31 | // Logical Operators |
30 | - or_ = fold<OrOperation>(and_.alias())[orOperator_ >> and_]; | |
31 | - and_ = fold<AndOperation>(equal_.alias())[andOperator_ >> equal_]; | |
32 | - equal_ = fold<EqualOperation>(unequal_.alias())[equalOperator_ >> unequal_]; | |
33 | - unequal_ = fold<UnequalOperation>(greaterOrEqual_.alias())[unequalOperator_ >>greaterOrEqual_]; | |
34 | - greaterOrEqual_ = fold<GreaterOrEqualOperation>(lowerOrEqual_.alias())[greaterOrEqualOperator_ >> lowerOrEqual_]; | |
35 | - lowerOrEqual_ = fold<LowerOrEqualOperation>(plusSign_.alias())[lowerOrEqualOperator_ >> plusSign_]; | |
32 | + or_ = PARSERGRAMMAR_ADD_OPERATOR(OrOperation, and_, orOperator_); | |
33 | + and_ = PARSERGRAMMAR_ADD_OPERATOR(AndOperation, equal_, andOperator_); | |
34 | + equal_ = PARSERGRAMMAR_ADD_OPERATOR(EqualOperation, unequal_, equalOperator_); | |
35 | + unequal_ = PARSERGRAMMAR_ADD_OPERATOR(UnequalOperation, greaterOrEqual_, unequalOperator_); | |
36 | + greaterOrEqual_ = PARSERGRAMMAR_ADD_OPERATOR(GreaterOrEqualOperation, lowerOrEqual_, greaterOrEqualOperator_); | |
37 | + lowerOrEqual_ = PARSERGRAMMAR_ADD_OPERATOR(LowerOrEqualOperation, sum_, lowerOrEqualOperator_); | |
38 | + | |
39 | + sum_ = fold<SumOperation>(difference_.alias())[sumOperator_ >> difference_]; | |
40 | + difference_ = fold<DifferenceOperation>(plusSign_.alias())[differenceOperator_ >> plusSign_]; | |
36 | 41 | |
37 | 42 | plusSign_ = ((sumOperator_ >>-*sumOperator_)> minusSign_ ) [_val = boost::phoenix::construct<PlusSignOperation>(_1)] || |
38 | 43 | ((differenceOperator_ >>differenceOperator_)> minusSign_ ) [_val = boost::phoenix::construct<PlusSignOperation>(_1)] |minusSign_ [_val = _1]; |
39 | - minusSign_ = (-*sumOperator_>>differenceOperator_ >>-*sumOperator_> sum_) [_val = boost::phoenix::construct<MinusSignOperation>(_1)] | sum_[_val = _1]; | |
44 | + minusSign_ = (-*sumOperator_>>differenceOperator_ >>-*sumOperator_> powerTen_) [_val = boost::phoenix::construct<MinusSignOperation>(_1)] | powerTen_[_val = _1]; | |
40 | 45 | |
41 | 46 | // Numerical Operators |
42 | - sum_ = fold<SumOperation>(difference_.alias())[sumOperator_ >> difference_]; | |
43 | - difference_ = fold<DifferenceOperation>(powerTen_.alias())[differenceOperator_ >> powerTen_]; | |
44 | - powerTen_ = fold<PowerTenOperation>(division_.alias())[powerTenOperator_ >> division_]; | |
47 | + powerTen_ = fold<PowerTenOperation>(factor_.alias())[powerTenOperator_ >> factor_]; | |
45 | 48 | factor_ = fold<FactorOperation>(division_.alias())[factorOperator_ >> division_]; |
46 | 49 | division_ = fold<DivisionOperation>(pow_.alias())[divisionOperator_ >> pow_]; |
47 | 50 | |
... | ... | @@ -65,6 +68,9 @@ public: |
65 | 68 | var_ = (+qi::char_('0','9') >> -qi::char_('.') >> -(+qi::char_('0','9'))) | ((qi::char_('.') >> +qi::char_('0','9'))); |
66 | 69 | vectorArgs_%=qi::raw[qi::int_ > -(qi::char_(',')>>qi::int_) ]; |
67 | 70 | spectArgs_ %=qi::raw[(qi::int_>>qi::char_(',')>>'*')|(qi::char_('*')>>qi::char_(',')>>qi::int_)]; |
71 | + | |
72 | + | |
73 | + | |
68 | 74 | powOperator_ = qi::char_('^'); |
69 | 75 | powerTenOperator_ = qi::char_('e'); |
70 | 76 | notOperator_ = qi::char_('!'); | ... | ... |
src/helpers/CMakeLists.txt
src/helpers/Helper.cc
... | ... | @@ -21,6 +21,9 @@ |
21 | 21 | |
22 | 22 | #include <iostream> |
23 | 23 | #include <sstream> |
24 | +#include <fstream> | |
25 | + | |
26 | +#include <boost/regex.hpp> | |
24 | 27 | |
25 | 28 | #include "Helper.hh" |
26 | 29 | |
... | ... | @@ -144,6 +147,43 @@ bool Helper::SystemCommand(std::string command, log4cxx::LoggerPtr pLogger) { |
144 | 147 | return anError; |
145 | 148 | } |
146 | 149 | |
150 | +/* | |
151 | + * @brief Load a CSV file | |
152 | + */ | |
153 | +std::vector<std::vector<std::string> > Helper::loadCSVFile(const char* filePath, char colSeparator) { | |
154 | + std::vector<std::vector<std::string> > result; | |
155 | + | |
156 | + std::ifstream infile(filePath); | |
157 | + | |
158 | + std::string pattern = std::string(1,colSeparator); | |
159 | + pattern += "(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))"; | |
160 | + boost::regex fieldsregx(pattern); | |
161 | + | |
162 | + std::string line; | |
163 | + while (std::getline(infile, line)) { | |
164 | + line.erase( std::remove(line.begin(), line.end(), '\r'), line.end() ); | |
165 | + | |
166 | + // Split line to tokens | |
167 | + | |
168 | + boost::sregex_token_iterator ti(line.begin(), line.end(), fieldsregx, -1); | |
169 | + boost::sregex_token_iterator end2; | |
170 | + | |
171 | + std::vector<std::string> row; | |
172 | + while (ti != end2) { | |
173 | + std::string token = ti->str(); | |
174 | + ++ti; | |
175 | + row.push_back(token); | |
176 | + } | |
177 | + if (line.back() == ';') { | |
178 | + // last character was a separator | |
179 | + row.push_back(""); | |
180 | + } | |
181 | + result.push_back(row); | |
182 | + } | |
183 | + return result; | |
184 | +} | |
185 | + | |
186 | + | |
147 | 187 | |
148 | 188 | } /* namespace Parameters */ |
149 | 189 | } /* namespace AMDA */ | ... | ... |
src/helpers/Helper.hh
... | ... | @@ -55,6 +55,11 @@ public: |
55 | 55 | static bool SystemCommand(std::string command, log4cxx::LoggerPtr pLogger); |
56 | 56 | |
57 | 57 | |
58 | + /* | |
59 | + * @brief Load a CSV file (with ; as columns separator) | |
60 | + */ | |
61 | + static std::vector<std::vector<std::string> > loadCSVFile(const char* filePath, char colSeparator); | |
62 | + | |
58 | 63 | /** |
59 | 64 | * @brief return the pid of process |
60 | 65 | */ | ... | ... |