summaryrefslogtreecommitdiff
path: root/valexpr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'valexpr.cc')
-rw-r--r--valexpr.cc96
1 files changed, 75 insertions, 21 deletions
diff --git a/valexpr.cc b/valexpr.cc
index 15aa69f8..4180b176 100644
--- a/valexpr.cc
+++ b/valexpr.cc
@@ -2,6 +2,8 @@
#include "error.h"
#include "datetime.h"
+#include <vector>
+
#include <pcre.h>
namespace ledger {
@@ -22,6 +24,8 @@ mask_t::mask_t(const std::string& pat) : exclude(false)
}
pattern = p;
+ DEBUG_PRINT("valexpr.mask.parse", "pattern = '" << pattern << "'");
+
const char *error;
int erroffset;
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
@@ -337,6 +341,16 @@ void node_t::compute(balance_t& result, const details_t& details) const
}
}
+inline char peek_next_nonws(std::istream& in)
+{
+ char c = in.peek();
+ while (! in.eof() && std::isspace(c) && c != '\n') {
+ in.get(c);
+ c = in.peek();
+ }
+ return c;
+}
+
node_t * parse_term(std::istream& in);
inline node_t * parse_term(const char * p) {
@@ -348,7 +362,7 @@ node_t * parse_term(std::istream& in)
{
node_t * node = NULL;
- char c = in.peek();
+ char c = peek_next_nonws(in);
if (std::isdigit(c) || c == '.' || c == '{') {
std::string ident;
@@ -425,14 +439,14 @@ node_t * parse_term(std::istream& in)
case 'P':
node = new node_t(node_t::F_VALUE);
- if (in.peek() == '(') {
+ if (peek_next_nonws(in) == '(') {
in.get(c);
node->left = parse_expr(in);
- if (in.peek() == ',') {
+ if (peek_next_nonws(in) == ',') {
in.get(c);
node->right = parse_expr(in);
}
- if (in.peek() == ')')
+ if (peek_next_nonws(in) == ')')
in.get(c);
else
throw expr_error("Missing ')'");
@@ -446,7 +460,7 @@ node_t * parse_term(std::istream& in)
std::string ident;
bool payee_mask = false;
- c = in.peek();
+ c = peek_next_nonws(in);
if (c == '/') {
payee_mask = true;
in.get(c);
@@ -474,7 +488,7 @@ node_t * parse_term(std::istream& in)
case '(':
node = parse_expr(in);
- if (in.peek() == ')')
+ if (peek_next_nonws(in) == ')')
in.get(c);
else
throw expr_error("Missing ')'");
@@ -515,7 +529,7 @@ node_t * parse_mul_expr(std::istream& in)
node = parse_term(in);
if (node && ! in.eof()) {
- char c = in.peek();
+ char c = peek_next_nonws(in);
while (c == '*' || c == '/') {
in.get(c);
switch (c) {
@@ -535,7 +549,7 @@ node_t * parse_mul_expr(std::istream& in)
break;
}
}
- c = in.peek();
+ c = peek_next_nonws(in);
}
}
@@ -549,7 +563,7 @@ node_t * parse_add_expr(std::istream& in)
node = parse_mul_expr(in);
if (node && ! in.eof()) {
- char c = in.peek();
+ char c = peek_next_nonws(in);
while (c == '+' || c == '-') {
in.get(c);
switch (c) {
@@ -569,7 +583,7 @@ node_t * parse_add_expr(std::istream& in)
break;
}
}
- c = in.peek();
+ c = peek_next_nonws(in);
}
}
@@ -580,7 +594,7 @@ node_t * parse_logic_expr(std::istream& in)
{
node_t * node = NULL;
- if (in.peek() == '!') {
+ if (peek_next_nonws(in) == '!') {
char c;
in.get(c);
node = new node_t(node_t::O_NOT);
@@ -591,7 +605,7 @@ node_t * parse_logic_expr(std::istream& in)
node = parse_add_expr(in);
if (node && ! in.eof()) {
- char c = in.peek();
+ char c = peek_next_nonws(in);
if (c == '=' || c == '<' || c == '>') {
in.get(c);
switch (c) {
@@ -606,7 +620,7 @@ node_t * parse_logic_expr(std::istream& in)
case '<': {
node_t * prev = node;
node = new node_t(node_t::O_LT);
- if (in.peek() == '=') {
+ if (peek_next_nonws(in) == '=') {
in.get(c);
node->type = node_t::O_LTE;
}
@@ -618,7 +632,7 @@ node_t * parse_logic_expr(std::istream& in)
case '>': {
node_t * prev = node;
node = new node_t(node_t::O_GT);
- if (in.peek() == '=') {
+ if (peek_next_nonws(in) == '=') {
in.get(c);
node->type = node_t::O_GTE;
}
@@ -647,7 +661,7 @@ node_t * parse_expr(std::istream& in)
node = parse_logic_expr(in);
if (node && ! in.eof()) {
- char c = in.peek();
+ char c = peek_next_nonws(in);
while (c == '&' || c == '|' || c == '?') {
in.get(c);
switch (c) {
@@ -674,7 +688,7 @@ node_t * parse_expr(std::istream& in)
node_t * choices = new node_t(node_t::O_COL);
node->right = choices;
choices->left = parse_logic_expr(in);
- c = in.peek();
+ c = peek_next_nonws(in);
if (c != ':') {
std::ostringstream err;
err << "Unexpected character '" << c << "'";
@@ -692,21 +706,57 @@ node_t * parse_expr(std::istream& in)
throw expr_error(err.str());
}
}
- c = in.peek();
+ c = peek_next_nonws(in);
}
}
return node;
}
-} // namespace ledger
+std::string regexps_to_predicate(std::list<std::string>::const_iterator begin,
+ std::list<std::string>::const_iterator end,
+ const bool account_regexp)
+{
+ std::vector<std::string> regexps(2);
+ std::string pred;
+
+ // Treat the remaining command-line arguments as regular
+ // expressions, used for refining report results.
+
+ for (std::list<std::string>::const_iterator i = begin;
+ i != end;
+ i++)
+ if ((*i)[0] == '-') {
+ if (! regexps[1].empty())
+ regexps[1] += "|";
+ regexps[1] += (*i).substr(1);
+ } else {
+ if (! regexps[0].empty())
+ regexps[0] += "|";
+ regexps[0] += *i;
+ }
+ for (std::vector<std::string>::const_iterator i = regexps.begin();
+ i != regexps.end();
+ i++)
+ if (! (*i).empty()) {
+ if (! pred.empty())
+ pred += "&";
+ if (i != regexps.begin())
+ pred += "!";
+ if (! account_regexp)
+ pred += "/";
+ pred += "/(?:";
+ pred += *i;
+ pred += ")/";
+ }
-#ifdef TEST
+ return pred;
+}
-namespace ledger {
+#ifdef DEBUG_ENABLED
-static void dump_tree(std::ostream& out, node_t * node)
+void dump_tree(std::ostream& out, const node_t * node)
{
switch (node->type) {
case node_t::CONSTANT_A:
@@ -834,8 +884,12 @@ static void dump_tree(std::ostream& out, node_t * node)
}
}
+#endif // DEBUG_ENABLED
+
} // namespace ledger
+#ifdef TEST
+
int main(int argc, char *argv[])
{
ledger::dump_tree(std::cout, ledger::parse_expr(argv[1]));