Commit c1f4db8e040ca942fe896b40cb385eecbec85ba7

Authored by Benjamin Renard
1 parent ef417f05

Add process to test the parser

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
... ... @@ -29,6 +29,7 @@ ADD_EXECUTABLE( expressionParser ${source_files} )
29 29 target_link_libraries(
30 30 expressionParser
31 31 AMDA_COMMON
  32 + helpers
32 33 ${CMAKE_THREAD_LIBS_INIT}
33 34 Parameters
34 35 ${LOG4CXX_LIBRARIES}
... ...
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
... ... @@ -20,5 +20,6 @@ target_link_libraries(
20 20 helpers
21 21 ${Boost_LIBRARY_DIR}/libboost_system.so
22 22 ${Boost_LIBRARY_DIR}/libboost_thread.so
  23 + ${Boost_LIBRARY_DIR}/libboost_regex.so
23 24 rt
24 25 )
... ...
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 */
... ...
test/parser/amda_test_parser.csv 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +IHM Expression;Kernel Expression
  2 +1;1
  3 +-1;-1
  4 +1*2;(1*2)
  5 +-1*2;-(1*2)
  6 +2*-1;(2*-1)
  7 +-1+2;(-1+2)
  8 +1+2;(1+2)
  9 +1-2;(1-2)
  10 +-(1+2);-(1+2)
  11 +-(-1-2);-(-1-2)
... ...