Expressions

- Broke up the parsing process into smaller steps to allow second pass
  parsing when "exp" tokens are expanded.
This commit is contained in:
Paul Beckingham 2011-06-11 13:44:11 -04:00
parent 8f20efc739
commit ad75ba49a4
4 changed files with 404 additions and 341 deletions

View file

@ -286,7 +286,7 @@ void Arguments::categorize ()
if (found_sequence) if (found_sequence)
found_something_after_sequence = true; found_something_after_sequence = true;
arg->second = "attribute"; arg->second = "attr";
} }
// /<from>/<to>/[g] // /<from>/<to>/[g]
@ -296,7 +296,7 @@ void Arguments::categorize ()
if (found_sequence) if (found_sequence)
found_something_after_sequence = true; found_something_after_sequence = true;
arg->second = "substitution"; arg->second = "subst";
} }
// /pattern/ // /pattern/
@ -1143,7 +1143,7 @@ Arguments Arguments::extract_read_only_filter ()
// Included. // Included.
else if (i->second == "tag" || else if (i->second == "tag" ||
i->second == "pattern" || i->second == "pattern" ||
i->second == "attribute" || i->second == "attr" ||
i->second == "attmod" || i->second == "attmod" ||
i->second == "id" || i->second == "id" ||
i->second == "uuid" || i->second == "uuid" ||
@ -1158,7 +1158,7 @@ Arguments Arguments::extract_read_only_filter ()
else else
{ {
// substitution // substitution
throw std::string ("A substitutions '") + i->first + "' is not allowed " throw std::string ("A substitution '") + i->first + "' is not allowed "
"in a read-only command filter."; "in a read-only command filter.";
} }
} }
@ -1189,7 +1189,7 @@ Arguments Arguments::extract_write_filter ()
// Included. // Included.
else if (i->second == "tag" || else if (i->second == "tag" ||
i->second == "pattern" || i->second == "pattern" ||
i->second == "attribute" || i->second == "attr" ||
i->second == "attmod" || i->second == "attmod" ||
i->second == "id" || i->second == "id" ||
i->second == "uuid" || i->second == "uuid" ||
@ -1239,8 +1239,8 @@ Arguments Arguments::extract_modifications ()
// Included. // Included.
else if (i->second == "tag" || else if (i->second == "tag" ||
i->second == "attribute" || i->second == "attr" ||
i->second == "substitution" || i->second == "subst" ||
i->second == "op" || i->second == "op" ||
i->second == "word") i->second == "word")
{ {
@ -1298,11 +1298,11 @@ void Arguments::dump (const std::string& label)
color_map["override"] = Color ("white on red"); color_map["override"] = Color ("white on red");
color_map["tag"] = Color ("green on gray3"); color_map["tag"] = Color ("green on gray3");
color_map["pattern"] = Color ("cyan on gray3"); color_map["pattern"] = Color ("cyan on gray3");
color_map["attribute"] = Color ("bold red on gray3"); color_map["attr"] = Color ("bold red on gray3");
color_map["attmod"] = Color ("bold red on gray3"); color_map["attmod"] = Color ("bold red on gray3");
color_map["id"] = Color ("yellow on gray3"); color_map["id"] = Color ("yellow on gray3");
color_map["uuid"] = Color ("yellow on gray3"); color_map["uuid"] = Color ("yellow on gray3");
color_map["substitution"] = Color ("bold cyan on gray3"); color_map["subst"] = Color ("bold cyan on gray3");
color_map["op"] = Color ("bold blue on gray3"); color_map["op"] = Color ("bold blue on gray3");
color_map["exp"] = Color ("bold green on gray5"); color_map["exp"] = Color ("bold green on gray5");
color_map["none"] = Color ("white on gray3"); color_map["none"] = Color ("white on gray3");

View file

@ -223,6 +223,11 @@ bool DOM::is_primitive (const std::string& input)
double d; double d;
int i; int i;
// TODO Date?
// TODO Quoted Date?
// TODO Duration?
// TODO Quoted Duration?
// String? // String?
Nibbler n (input); Nibbler n (input);
if (n.getQuoted ('"', s) && n.depleted ()) if (n.getQuoted ('"', s) && n.depleted ())

View file

@ -29,6 +29,9 @@
#include <sstream> #include <sstream>
#include <Context.h> #include <Context.h>
#include <Lexer.h> #include <Lexer.h>
#include <Date.h>
#include <Duration.h>
#include <Variant.h>
#include <text.h> #include <text.h>
#include <Expression.h> #include <Expression.h>
@ -37,12 +40,19 @@ extern Context context;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Perform all the necessary steps prior to an eval call. // Perform all the necessary steps prior to an eval call.
Expression::Expression (Arguments& arguments) Expression::Expression (Arguments& arguments)
: _original (arguments) : _args (arguments)
{ {
expand_sequence (); // Convert sequence to expression. _args.dump ("Expression::Expression");
to_infix (); // Old-style to infix.
expand_expression (); // Lex expressions to dom, op tokens. expand_sequence ();
to_postfix (); // Infix --> Postfix implicit_and ();
expand_tag ();
expand_pattern (); // Configurable
expand_attr ();
expand_attmod ();
expand_word ();
expand_expression (); // Configurable
postfix ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -53,11 +63,13 @@ Expression::~Expression ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool Expression::eval (Task& task) bool Expression::eval (Task& task)
{ {
std::vector <Variant> value_stack;
std::vector <std::pair <std::string, std::string> >::iterator arg; std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _postfix.begin (); arg != _postfix.end (); ++arg) for (arg = _args.begin (); arg != _args.end (); ++arg)
{ {
// if (arg->second != "op") // if (arg->second != "op")
// eval_stack.push_back (*arg); // value_stack.push_back (Variant (*arg));
// else // else
// { // {
@ -68,9 +80,14 @@ bool Expression::eval (Task& task)
// add the two operands // add the two operands
// push result // push result
// } // }
// else if () // else if (arg->first == "?")
// { // {
// } // }
// else if (arg->first == "?")
// {
// }
// else
// throw std::string ("Unsupported operator '") + arg->first + "'.";
// } // }
} }
@ -85,13 +102,12 @@ bool Expression::eval (Task& task)
void Expression::expand_sequence () void Expression::expand_sequence ()
{ {
Arguments temp; Arguments temp;
_sequenced.clear ();
// Extract all the components of a sequence. // Extract all the components of a sequence.
std::vector <int> ids; std::vector <int> ids;
std::vector <std::string> uuids; std::vector <std::string> uuids;
std::vector <std::pair <std::string, std::string> >::iterator arg; std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _original.begin (); arg != _original.end (); ++arg) for (arg = _args.begin (); arg != _args.end (); ++arg)
{ {
if (arg->second == "id") if (arg->second == "id")
Arguments::extract_id (arg->first, ids); Arguments::extract_id (arg->first, ids);
@ -102,10 +118,7 @@ void Expression::expand_sequence ()
// If there is no sequence, we're done. // If there is no sequence, we're done.
if (ids.size () == 0 && uuids.size () == 0) if (ids.size () == 0 && uuids.size () == 0)
{
_sequenced = _original;
return; return;
}
// Construct the algebraic form. // Construct the algebraic form.
std::stringstream sequence; std::stringstream sequence;
@ -120,7 +133,9 @@ void Expression::expand_sequence ()
if (uuids.size ()) if (uuids.size ())
{ {
if (sequence.str ().length () > 1)
sequence << " or "; sequence << " or ";
for (unsigned int i = 0; i < uuids.size (); ++i) for (unsigned int i = 0; i < uuids.size (); ++i)
{ {
if (i) if (i)
@ -133,7 +148,7 @@ void Expression::expand_sequence ()
sequence << ")"; sequence << ")";
// Copy everything up to the first id/uuid. // Copy everything up to the first id/uuid.
for (arg = _original.begin (); arg != _original.end (); ++arg) for (arg = _args.begin (); arg != _args.end (); ++arg)
{ {
if (arg->second == "id" || arg->second == "uuid") if (arg->second == "id" || arg->second == "uuid")
break; break;
@ -146,7 +161,7 @@ void Expression::expand_sequence ()
// Now copy everything after the last id/uuid. // Now copy everything after the last id/uuid.
bool found_id = false; bool found_id = false;
for (arg = _original.begin (); arg != _original.end (); ++arg) for (arg = _args.begin (); arg != _args.end (); ++arg)
{ {
if (arg->second == "id" || arg->second == "uuid") if (arg->second == "id" || arg->second == "uuid")
found_id = true; found_id = true;
@ -155,59 +170,170 @@ void Expression::expand_sequence ()
temp.push_back (*arg); temp.push_back (*arg);
} }
_sequenced.swap (temp); _args.swap (temp);
_sequenced.dump ("Expression::expand_sequence"); _args.dump ("Expression::expand_sequence");
}
////////////////////////////////////////////////////////////////////////////////
// Inserts the 'and' operator by default between terms that are not separated by
// at least one operator.
//
// Converts: <term1> <term2> <op> <term>
// to: <term1> and <term2> <op> <term>
//
void Expression::implicit_and ()
{
Arguments temp;
bool delta = false;
std::string previous = "op";
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _args.begin (); arg != _args.end (); ++arg)
{
// Old-style filters need 'and' conjunctions.
if (previous != "op" &&
arg->second != "op")
{
temp.push_back (std::make_pair ("and", "op"));
delta = true;
}
// Now insert the adjacent non-operator.
temp.push_back (*arg);
previous = arg->second;
}
if (delta)
{
_args.swap (temp);
_args.dump ("Expression::implicit_and");
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Convert: +with -without // Convert: +with -without
//
// To: tags ~ with // To: tags ~ with
// tags !~ without // tags !~ without
void Expression::expand_tag (const std::string& input) void Expression::expand_tag ()
{ {
Arguments temp;
bool delta = false;
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _args.begin (); arg != _args.end (); ++arg)
{
if (arg->second == "tag")
{
char type; char type;
std::string value; std::string value;
Arguments::extract_tag (input, type, value); Arguments::extract_tag (arg->first, type, value);
_infix.push_back (std::make_pair ("tags", "dom")); temp.push_back (std::make_pair ("tags", "lvalue"));
_infix.push_back (std::make_pair (type == '+' ? "~" : "!~", "op")); temp.push_back (std::make_pair (type == '+' ? "~" : "!~", "op"));
_infix.push_back (std::make_pair (value, "exp")); temp.push_back (std::make_pair (value, "rvalue"));
delta = true;
}
else
temp.push_back (*arg);
}
if (delta)
{
_args.swap (temp);
_args.dump ("Expression::expand_tag");
}
}
////////////////////////////////////////////////////////////////////////////////
// Convert: /foo/
// To: description ~ foo
void Expression::expand_pattern ()
{
Arguments temp;
bool delta = false;
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _args.begin (); arg != _args.end (); ++arg)
{
if (arg->second == "pattern")
{
std::string value;
Arguments::extract_pattern (arg->first, value);
temp.push_back (std::make_pair ("description", "lvalue"));
temp.push_back (std::make_pair ("~", "op"));
temp.push_back (std::make_pair (value, "rvalue"));
delta = true;
}
else
temp.push_back (*arg);
}
if (delta)
{
_args.swap (temp);
_args.dump ("Expression::expand_pattern");
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Convert: <name>[:=]<value> // Convert: <name>[:=]<value>
//
// To: <name> = lex<value> // To: <name> = lex<value>
void Expression::expand_attr (const std::string& input) void Expression::expand_attr ()
{ {
// TODO Should canonicalize 'name'. Arguments temp;
bool delta = false;
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _args.begin (); arg != _args.end (); ++arg)
{
if (arg->second == "attr")
{
// TODO Canonicalize 'name'.
std::string name; std::string name;
std::string value; std::string value;
Arguments::extract_attr (input, name, value); Arguments::extract_attr (arg->first, name, value);
// Always quote the value, so that empty values, or values containing spaces // Always quote the value, so that empty values, or values containing spaces
// are preserved. // are preserved.
value = "\"" + value + "\""; value = "\"" + value + "\"";
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("=", "op")); temp.push_back (std::make_pair ("=", "op"));
_infix.push_back (std::make_pair (value, "exp")); temp.push_back (std::make_pair (value, "rvalue"));
delta = true;
}
else
temp.push_back (*arg);
}
if (delta)
{
_args.swap (temp);
_args.dump ("Expression::expand_attr");
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Convert: <name>.<mod>[:=]<value> // Convert: <name>.<mod>[:=]<value>
//
// To: <name> <op> lex<value> // To: <name> <op> lex<value>
void Expression::expand_attmod (const std::string& input) void Expression::expand_attmod ()
{ {
Arguments temp;
bool delta = false;
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _args.begin (); arg != _args.end (); ++arg)
{
if (arg->second == "attmod")
{
// TODO Should canonicalize 'name'. // TODO Should canonicalize 'name'.
std::string name; std::string name;
// TODO Should canonicalize 'mod'. // TODO Should canonicalize 'mod'.
std::string mod; std::string mod;
std::string value; std::string value;
std::string sense; std::string sense;
Arguments::extract_attmod (input, name, mod, value, sense); Arguments::extract_attmod (arg->first, name, mod, value, sense);
// Always quote the value, so that empty values, or values containing spaces // Always quote the value, so that empty values, or values containing spaces
// are preserved. // are preserved.
@ -216,122 +342,155 @@ void Expression::expand_attmod (const std::string& input)
if (mod == "before" || mod == "under" || mod == "below") if (mod == "before" || mod == "under" || mod == "below")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("<", "op")); temp.push_back (std::make_pair ("<", "op"));
_infix.push_back (std::make_pair (value, "exp")); temp.push_back (std::make_pair (value, "rvalue"));
} }
else if (mod == "after" || mod == "over" || mod == "above") else if (mod == "after" || mod == "over" || mod == "above")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair (">", "op")); temp.push_back (std::make_pair (">", "op"));
_infix.push_back (std::make_pair (value, "exp")); temp.push_back (std::make_pair (value, "rvalue"));
} }
else if (mod == "none") else if (mod == "none")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("==", "op")); temp.push_back (std::make_pair ("==", "op"));
_infix.push_back (std::make_pair ("\"\"", "exp")); temp.push_back (std::make_pair ("\"\"", "rvalue"));
} }
else if (mod == "any") else if (mod == "any")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("!=", "op")); temp.push_back (std::make_pair ("!=", "op"));
_infix.push_back (std::make_pair ("\"\"", "exp")); temp.push_back (std::make_pair ("\"\"", "rvalue"));
} }
else if (mod == "is" || mod == "equals") else if (mod == "is" || mod == "equals")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("=", "op")); temp.push_back (std::make_pair ("=", "op"));
_infix.push_back (std::make_pair (value, "exp")); temp.push_back (std::make_pair (value, "rvalue"));
} }
else if (mod == "isnt" || mod == "not") else if (mod == "isnt" || mod == "not")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("!=", "op")); temp.push_back (std::make_pair ("!=", "op"));
_infix.push_back (std::make_pair (value, "exp")); temp.push_back (std::make_pair (value, "rvalue"));
} }
else if (mod == "has" || mod == "contains") else if (mod == "has" || mod == "contains")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("~", "op")); temp.push_back (std::make_pair ("~", "op"));
_infix.push_back (std::make_pair (value, "exp")); temp.push_back (std::make_pair (value, "rvalue"));
} }
else if (mod == "hasnt") else if (mod == "hasnt")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("!~", "op")); temp.push_back (std::make_pair ("!~", "op"));
_infix.push_back (std::make_pair (value, "exp")); temp.push_back (std::make_pair (value, "rvalue"));
} }
else if (mod == "startswith" || mod == "left") else if (mod == "startswith" || mod == "left")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("~", "op")); temp.push_back (std::make_pair ("~", "op"));
_infix.push_back (std::make_pair ("^" + raw_value, "rx")); temp.push_back (std::make_pair ("^" + raw_value, "rx"));
} }
else if (mod == "endswith" || mod == "right") else if (mod == "endswith" || mod == "right")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("~", "op")); temp.push_back (std::make_pair ("~", "op"));
_infix.push_back (std::make_pair (raw_value + "$", "rx")); temp.push_back (std::make_pair (raw_value + "$", "rx"));
} }
else if (mod == "word") else if (mod == "word")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("~", "op")); temp.push_back (std::make_pair ("~", "op"));
_infix.push_back (std::make_pair ("\\b" + raw_value + "\\b", "rx")); temp.push_back (std::make_pair ("\\b" + raw_value + "\\b", "rx"));
} }
else if (mod == "noword") else if (mod == "noword")
{ {
_infix.push_back (std::make_pair (name, "dom")); temp.push_back (std::make_pair (name, "lvalue"));
_infix.push_back (std::make_pair ("!~", "op")); temp.push_back (std::make_pair ("!~", "op"));
_infix.push_back (std::make_pair ("\\b" + raw_value + "\\b", "rx")); temp.push_back (std::make_pair ("\\b" + raw_value + "\\b", "rx"));
}
else
throw std::string ("Error: unrecognized attribute modifier '") + mod + "'.";
delta = true;
}
else
temp.push_back (*arg);
}
if (delta)
{
_args.swap (temp);
_args.dump ("Expression::expand_attmod");
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Convert: <word> // Convert: <word>
//
// To: description ~ <word> // To: description ~ <word>
void Expression::expand_word (const std::string& input) void Expression::expand_word ()
{ {
_infix.push_back (std::make_pair ("description", "dom")); Arguments temp;
_infix.push_back (std::make_pair ("~", "op")); bool delta = false;
_infix.push_back (std::make_pair (input, "exp"));
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _args.begin (); arg != _args.end (); ++arg)
{
if (arg->second == "word")
{
temp.push_back (std::make_pair ("description", "lvalue"));
temp.push_back (std::make_pair ("~", "op"));
temp.push_back (std::make_pair (arg->first, "rvalue"));
delta = true;
}
else
temp.push_back (*arg);
}
if (delta)
{
_args.swap (temp);
_args.dump ("Expression::expand_word");
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Convert: /<pattern>/ // Look for "exp" arguments, and convert them to one of:
// // "date"
// To: description ~ <pattern> // "duration"
void Expression::expand_pattern (const std::string& input) // Lexer::tokenize
{
std::string value;
Arguments::extract_pattern (input, value);
_infix.push_back (std::make_pair ("description", "dom"));
_infix.push_back (std::make_pair ("~", "op"));
_infix.push_back (std::make_pair (value, "exp"));
}
////////////////////////////////////////////////////////////////////////////////
// Convert: <exp>
//
// To: lex<exp>
void Expression::expand_expression () void Expression::expand_expression ()
{ {
Arguments temp; Arguments temp;
bool delta = false;
// Get a list of all operators. // Get a list of all operators.
std::vector <std::string> operators = Arguments::operator_list (); std::vector <std::string> operators = Arguments::operator_list ();
// Look for all 'exp' args. // Look for all 'exp' args.
std::vector <std::pair <std::string, std::string> >::iterator arg; std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _infix.begin (); arg != _infix.end (); ++arg) for (arg = _args.begin (); arg != _args.end (); ++arg)
{ {
if (arg->second == "exp") if (arg->second == "exp")
{ {
/* obsolete */ // Remove quotes.
Lexer lexer (unquoteText (arg->first)); arg->first = unquoteText (arg->first);
if (Date::valid (arg->first, context.config.get ("dateformat")))
temp.push_back (std::make_pair (arg->first, "date"));
else if (Duration::valid (arg->first))
temp.push_back (std::make_pair (arg->first, "duration"));
// The expression does not appear to be syntactic sugar, so it should be
// lexed.
else
{
Lexer lexer (arg->first);
lexer.skipWhitespace (true); lexer.skipWhitespace (true);
lexer.coalesceAlpha (true); lexer.coalesceAlpha (true);
lexer.coalesceDigits (true); lexer.coalesceDigits (true);
@ -342,91 +501,23 @@ void Expression::expand_expression ()
std::vector <std::string>::iterator token; std::vector <std::string>::iterator token;
for (token = tokens.begin (); token != tokens.end (); ++token) for (token = tokens.begin (); token != tokens.end (); ++token)
{ temp.push_back (
if (_infix.is_operator (*token)) std::make_pair (
temp.push_back (std::make_pair (*token, "op")); *token,
else (_args.is_operator (*token) ? "op" : "dom")));
temp.push_back (std::make_pair (*token, "dom"));
} }
/* obsolete */
/* proposed */ delta = true;
/*
Nibbler n (arg->first);
*/
/* proposed */
} }
else else
temp.push_back (*arg); temp.push_back (*arg);
} }
_infix.swap (temp); if (delta)
_infix.dump ("Expression::expand_expression");
}
////////////////////////////////////////////////////////////////////////////////
// Inserts the 'and' operator by default between terms that are not separated by
// at least one operator.
//
// Converts: <term1> <term2> <op> <exp>
// to: <term1> and <term2> <op> <token> <token> <token>
//
// Rules:
// 1. Two adjacent non-operator arguments have an 'and' inserted between them.
//
void Expression::to_infix ()
{
_infix.clear ();
bool new_style = is_new_style ();
std::string value;
std::string previous = "op";
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _sequenced.begin (); arg != _sequenced.end (); ++arg)
{ {
// Old-style filters need 'and' conjunctions. _args.swap (temp);
if (!new_style && _args.dump ("Expression::expand_expression");
previous != "op" &&
arg->second != "op")
{
_infix.push_back (std::make_pair ("and", "op"));
} }
// Upgrade all arguments to new-style.
// ID & UUID sequence has already been converted.
if (arg->second == "id" ||
arg->second == "uuid")
; // NOP.
else if (arg->second == "tag")
expand_tag (arg->first);
else if (arg->second == "pattern")
expand_pattern (arg->first);
else if (arg->second == "attribute")
expand_attr (arg->first);
else if (arg->second == "attmod")
expand_attmod (arg->first);
else if (arg->second == "word")
expand_word (arg->first);
else if (arg->second == "op")
_infix.push_back (*arg);
// Skip expressions, convert later.
else if (arg->second == "exp")
_infix.push_back (*arg);
else
throw std::string ("Error: unrecognized argument category '") + arg->second + "'";
previous = arg->second;
}
_infix.dump ("Expression::toInfix");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -461,9 +552,9 @@ void Expression::to_infix ()
// Pop the operator onto the output queue. // Pop the operator onto the output queue.
// Exit. // Exit.
// //
void Expression::to_postfix () void Expression::postfix ()
{ {
_postfix.clear (); Arguments temp;
std::pair <std::string, std::string> item; std::pair <std::string, std::string> item;
Arguments op_stack; Arguments op_stack;
@ -472,7 +563,7 @@ void Expression::to_postfix ()
char associativity; char associativity;
std::vector <std::pair <std::string, std::string> >::iterator arg; std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _infix.begin (); arg != _infix.end (); ++arg) for (arg = _args.begin (); arg != _args.end (); ++arg)
{ {
if (arg->first == "(") if (arg->first == "(")
{ {
@ -483,7 +574,7 @@ void Expression::to_postfix ()
while (op_stack.size () > 0 && while (op_stack.size () > 0 &&
op_stack.back ().first != "(") op_stack.back ().first != "(")
{ {
_postfix.push_back (op_stack.back ()); temp.push_back (op_stack.back ());
op_stack.pop_back (); op_stack.pop_back ();
} }
@ -506,7 +597,7 @@ void Expression::to_postfix ()
((associativity == 'l' && precedence <= precedence2) || ((associativity == 'l' && precedence <= precedence2) ||
(associativity == 'r' && precedence < precedence2))) (associativity == 'r' && precedence < precedence2)))
{ {
_postfix.push_back (op_stack.back ()); temp.push_back (op_stack.back ());
op_stack.pop_back (); op_stack.pop_back ();
} }
@ -514,7 +605,7 @@ void Expression::to_postfix ()
} }
else else
{ {
_postfix.push_back (*arg); temp.push_back (*arg);
} }
} }
@ -524,38 +615,12 @@ void Expression::to_postfix ()
op_stack.back ().first == ")") op_stack.back ().first == ")")
throw std::string ("Mismatched parentheses in expression"); throw std::string ("Mismatched parentheses in expression");
_postfix.push_back (op_stack.back ()); temp.push_back (op_stack.back ());
op_stack.pop_back (); op_stack.pop_back ();
} }
_postfix.dump ("Expression::toPostfix"); _args.swap (temp);
} _args.dump ("Expression::toPostfix");
////////////////////////////////////////////////////////////////////////////////
// Test whether the _original arguments are old style or new style.
//
// Old style: no single argument corresponds to an operator, ie no 'and', 'or',
// etc.
//
// New style: at least one argument that is an operator.
//
bool Expression::is_new_style ()
{
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = _original.begin (); arg != _original.end (); ++arg)
if (Arguments::is_operator (arg->first))
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
void Expression::dump ()
{
_original.dump ("Original Arguments");
_sequenced.dump ("Sequence Expanded");
_infix.dump ("Converted to Infix");
_postfix.dump ("Converted to Postfix");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -42,24 +42,17 @@ public:
private: private:
void expand_sequence (); void expand_sequence ();
void implicit_and ();
void expand_tag ();
void expand_pattern ();
void expand_attr ();
void expand_attmod ();
void expand_word ();
void expand_expression (); void expand_expression ();
void postfix ();
void expand_tag (const std::string&);
void expand_attr (const std::string&);
void expand_attmod (const std::string&);
void expand_word (const std::string&);
void expand_pattern (const std::string&);
void to_infix ();
void to_postfix ();
bool is_new_style ();
void dump ();
private: private:
Arguments _original; Arguments _args;
Arguments _sequenced;
Arguments _infix;
Arguments _postfix;
}; };
#endif #endif