diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c60988e12317074aee65e72688cc2648b1c61815..226d711e2cbedb4ca44518d695becec2b61e8299 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,7 @@
 # driver source files
-SET(sources imagine-planner.cpp types.cpp queries.cpp)
+SET(sources imagine-planner.cpp types.cpp queries.cpp parsing.cpp)
 # application header files
-SET(headers imagine-planner.h types.h queries.h)
+SET(headers imagine-planner.h types.h queries.h parsing.h)
 # Boost
 FIND_PACKAGE(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
 # Swi-pl
diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt
index 27851e08db4d615d18d3b700109c0dfca5f87210..dd6dd89c4c842afdb3c2396ee643052fd1d23683 100644
--- a/src/examples/CMakeLists.txt
+++ b/src/examples/CMakeLists.txt
@@ -17,3 +17,10 @@ TARGET_LINK_LIBRARIES(queries_test
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
 
+ADD_EXECUTABLE(parsing_test parsing_test.cpp)
+TARGET_LINK_LIBRARIES(parsing_test
+                      imagine-planner
+                      ${Boost_FILESYSTEM_LIBRARY}
+                      ${Boost_SYSTEM_LIBRARY}
+                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+
diff --git a/src/examples/parsing_test.cpp b/src/examples/parsing_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6d7422c4c8a3aa0dcf4eafece2891ae6dc355192
--- /dev/null
+++ b/src/examples/parsing_test.cpp
@@ -0,0 +1,142 @@
+#define BOOST_TEST_MODULE Parsing Test
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+#include "parsing.h"
+#include <iostream>
+using namespace imagine_planner;
+
+#if 0 // Set to 1 if __PRETTY_FUNCTION__ macro is not available
+#define __PRETTY_FUNCTION__ __func__
+#endif
+
+#if 1
+#define INFO(x)\
+  std::cout << "\e[1m\e[32m\e[4m" <<  __PRETTY_FUNCTION__ << " [" << __LINE__ << "]" << "\e[24m: " << x << "\e[0m" << std::endl;
+#else
+#define INFO(x)
+#endif
+
+std::ostream& operator<<(std::ostream& os, const TokenV& tokens)
+{
+  bool first = true;
+  os << '[';
+  for (const Token& token : tokens)
+  {
+    if (not first) os << ", ";
+    os << token.first << "(" << token.second << ")";
+    first = false;
+  }
+  os << ']';
+  return os;
+}
+
+BOOST_AUTO_TEST_CASE(spaces)
+{
+  std::string str("   Hello  ( world) ");
+  std::string str_clean = remove_spaces(str);
+  INFO("str_clean: " << str_clean);
+  BOOST_CHECK_EQUAL(str_clean, "Hello(world)");
+}
+
+BOOST_AUTO_TEST_CASE(test_parse_predicate)
+{
+  std::string str("at(lettuce,east), cost(2.5), r(), s(");
+  TokenV tokens = decompose(str);
+  INFO(tokens);
+  std::size_t cursor = 0;
+  Predicate* predicate = parse_predicate(tokens, cursor);
+  BOOST_REQUIRE(predicate);
+  BOOST_CHECK_EQUAL(*predicate, Predicate("at", "lettuce", "east"));
+  BOOST_CHECK_EQUAL(cursor, 6);
+  delete predicate;
+  cursor = 7;
+  predicate = parse_predicate(tokens, cursor);
+  BOOST_REQUIRE(predicate);
+  BOOST_CHECK_EQUAL(*predicate, Predicate("cost", 2.5));
+  BOOST_CHECK_EQUAL(cursor, 11);
+  delete predicate;
+  cursor = 12;
+  predicate = parse_predicate(tokens, cursor);
+  BOOST_REQUIRE(predicate);
+  BOOST_CHECK_EQUAL(*predicate, Predicate("r"));
+  BOOST_CHECK_EQUAL(cursor, 15);
+  delete predicate;
+  cursor = 16;
+  predicate = parse_predicate(tokens, cursor);
+  BOOST_REQUIRE(not predicate);
+}
+
+BOOST_AUTO_TEST_CASE(test_parse_simple_expressions)
+{
+  std::string str1("at(X, Y)");
+  std::string str2("\\+at(X, Y)");
+  std::string str3("(at(X, Y))");
+  std::string str4("\\+(at(X, Y))");
+  QuerySpecification* q1 = parse_expression(str1);
+  if (q1)
+  {
+    INFO("q1: " << *q1);
+    delete q1;
+  }
+  else INFO("q1: none");
+  QuerySpecification* q2 = parse_expression(str2);
+  if (q2)
+  {
+    INFO("q2: " << *q2);
+    delete q2;
+  }
+  else INFO("q2: none");
+  QuerySpecification* q3 = parse_expression(str3);
+  if (q3)
+  {
+    INFO("q3: " << *q3);
+    delete q3;
+  }
+  else INFO("q3: none");
+  QuerySpecification* q4 = parse_expression(str4);
+  if (q4)
+  {
+    INFO("q4: " << *q4);
+    delete q4;
+  }
+  else INFO("q4: none");
+}
+
+BOOST_AUTO_TEST_CASE(test_parse_complex_expressions)
+{
+  std::string str1("at(X, Y), at(Z, Y)");
+  std::string str2("at(X, Y), at(Z, Y), \\+at(boat, Y)");
+  std::string str3("fixes(X, Y), \\+(precedes(_1, X), occluded_by(X, _2))");
+  std::string str4("\\+(\\+q(X), \\+q(Y), \\+r())");
+  QuerySpecification* q1 = parse_expression(str1);
+  if (q1)
+  {
+    INFO("q1: " << *q1);
+    delete q1;
+  }
+  else INFO("q1: none");
+  QuerySpecification* q2 = parse_expression(str2);
+  if (q2)
+  {
+    INFO("q2: " << *q2);
+    delete q2;
+  }
+  else INFO("q2: none");
+  QuerySpecification* q3 = parse_expression(str3);
+  if (q3)
+  {
+    INFO("q3: " << *q3);
+    delete q3;
+  }
+  else INFO("q3: none");
+  QuerySpecification* q4 = parse_expression(str4);
+  if (q4)
+  {
+    INFO("q4: " << *q4);
+    delete q4;
+  }
+  else INFO("q4: none");
+}
+
+
diff --git a/src/examples/queries_test.cpp b/src/examples/queries_test.cpp
index ca9aa7c50df273ef1a9273e1f762aedb9ddb16bd..e86e3c675a2dc180f206eb7df1dfe11f930a8e16 100644
--- a/src/examples/queries_test.cpp
+++ b/src/examples/queries_test.cpp
@@ -1,4 +1,4 @@
-#define BOOST_TEST_MODULE Types Test
+#define BOOST_TEST_MODULE Queries Test
 #define BOOST_TEST_DYN_LINK
 #include <boost/test/unit_test.hpp>
 
@@ -24,6 +24,7 @@ BOOST_AUTO_TEST_CASE(simple_query_test_sat)
   INFO(state);
   SimpleQuery q1(state, Predicate("p", "a", "X"));
   SimpleQuery q2(state, Predicate("q", "w"));
+  INFO("q1: " << q1 << ", " << q2);
   BOOST_REQUIRE(q1.next_solution());
   BOOST_CHECK_EQUAL(q1.get_solution().to_str(), "{\n  X -> b\n}");
   BOOST_REQUIRE(q1.next_solution());
@@ -41,6 +42,7 @@ BOOST_AUTO_TEST_CASE(simple_query_test_unsat)
   INFO(state);
   SimpleQuery q1(state, Predicate("p", "c", "X"));
   SimpleQuery q2(state, Predicate("p", "a", "d"));
+  INFO("q1: " << q1 << ", " << q2);
   BOOST_REQUIRE(not q1.next_solution());
   BOOST_REQUIRE(not q2.next_solution());
 }
@@ -48,16 +50,19 @@ BOOST_AUTO_TEST_CASE(simple_query_test_unsat)
 BOOST_AUTO_TEST_CASE(and_query_test_sat)
 {
   PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
-      Predicate("p", "b", "d"), Predicate("p","d","a"), Predicate("q","a"),
-      Predicate("q", "d")});
+      Predicate("p", "b", "d"), Predicate("p","d","a"), Predicate("q","b")});
   INFO("state: " << state);
-  SimpleQuery q1(state, Predicate("p", "X", "Y"));
-  SimpleQuery q2(state, Predicate("q", "X"));
-  //NotQuery not1(q2);
-  AndQuery and1(q1, q2);
-  while (and1.next_solution())
-  {
-    INFO(and1.get_solution());
-  }
+  SimpleQuery* q1 = new SimpleQuery(state, Predicate("p", "X", "Y"));
+  SimpleQuery* q2 = new SimpleQuery(state, Predicate("q", "X"));
+  NotQuery* not1 = new NotQuery(q2);
+  AndQuery* and1 = new AndQuery(q1, not1);
+  INFO("and1: " << *and1);
+  BOOST_REQUIRE(and1->next_solution());
+  BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n  X -> a,\n  Y -> b\n}");
+  BOOST_REQUIRE(and1->next_solution());
+  BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n  X -> a,\n  Y -> c\n}");
+  BOOST_REQUIRE(and1->next_solution());
+  BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n  X -> d,\n  Y -> a\n}");
+  BOOST_REQUIRE(not and1->next_solution());
 }
 
diff --git a/src/parsing.cpp b/src/parsing.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..49677a1bf2694abeb28eb451d862d963e4b0f54c
--- /dev/null
+++ b/src/parsing.cpp
@@ -0,0 +1,249 @@
+#include "parsing.h"
+#include <cctype>
+#include <sstream>
+#include <iostream>
+
+namespace imagine_planner
+{
+
+bool is_number(const std::string& str)
+{
+  try
+  {
+    std::size_t idx = 0;
+    std::stod(str, &idx);
+    return idx == str.length(); // no more chars after the number
+  }
+  catch (...)
+  {
+    return false;
+  }
+}
+
+std::string remove_spaces(const std::string& in)
+{
+  std::ostringstream oss;
+  for (char c : in)
+  {
+    if (not std::isspace(c)) oss << c;
+  }
+  return oss.str();
+}
+
+TokenV decompose(const std::string& in)
+{
+  TokenV tokens;
+  std::string in_clean = remove_spaces(in);
+  std::size_t cursor = 0;
+  while (cursor < in_clean.length())
+  {
+    if (in_clean.compare(cursor, 2, "\\+") == 0)
+    {
+      tokens.push_back({"NOT", ""});
+      cursor += 2;
+    }
+    else if (in_clean[cursor] == '(')
+    {
+      tokens.push_back({"PAR_OPEN", ""});
+      ++cursor;
+    }
+    else if (in_clean[cursor] == ')')
+    {
+      tokens.push_back({"PAR_CLOSE", ""});
+      ++cursor;
+    }
+    else if (in_clean[cursor] == ',')
+    {
+      tokens.push_back({"COMMA", ""});
+      ++cursor;
+    }
+    else
+    {
+      std::size_t end = in_clean.find_first_of(",()\\", cursor);
+      if (end == std::string::npos) end = in_clean.length();
+      std::size_t len = end - cursor;
+      std::string substr = in_clean.substr(cursor, len);
+      std::string type = is_number(substr)? "NUMBER" : "SYMBOL";
+      tokens.push_back({type, substr});
+      cursor = end;
+    }
+  }
+  tokens.push_back({"EOF", ""});
+  return tokens;
+}
+
+Predicate* parse_predicate(const TokenV& tokens, std::size_t& cursor)
+{
+  enum State {EXPECTING_NAME, EXPECTING_PAR_OPEN, EXPECTING_ARG_OR_END,
+    EXPECTING_COMMA_OR_END, EXPECTING_ARG, KO, OK};
+  State state = EXPECTING_NAME;
+  Predicate* predicate = nullptr;
+  std::string pred_name;
+  TermV arguments;
+  std::size_t idx = cursor;
+  while (state != OK and state != KO)
+  {
+    const Token& token = tokens[idx];
+    switch (state)
+    {
+      case EXPECTING_NAME:
+        if (token.first == "SYMBOL")
+        {
+          pred_name = token.second;
+          state = EXPECTING_PAR_OPEN;
+        }
+        else state = KO;
+        break;
+      case EXPECTING_PAR_OPEN:
+        if (token.first == "PAR_OPEN") state = EXPECTING_ARG_OR_END;
+        else state = KO;
+        break;
+      case EXPECTING_ARG_OR_END:
+        if (token.first == "PAR_CLOSE") state = OK;
+        else if (token.first == "SYMBOL")
+        {
+          arguments.push_back(TermWrapper(token.second));
+          state = EXPECTING_COMMA_OR_END;
+        }
+        else if (token.first == "NUMBER")
+        {
+          arguments.push_back(TermWrapper(std::stod(token.second)));
+          state = EXPECTING_COMMA_OR_END;
+        }
+        else state = KO;
+        break;
+      case EXPECTING_COMMA_OR_END:
+        if (token.first == "COMMA") state = EXPECTING_ARG;
+        else if (token.first == "PAR_CLOSE") state = OK;
+        else state = KO;
+        break;
+      case EXPECTING_ARG:
+        if (token.first == "SYMBOL")
+        {
+          arguments.push_back(TermWrapper(token.second));
+          state = EXPECTING_COMMA_OR_END;
+        }
+        else if (token.first == "NUMBER")
+        {
+          arguments.push_back(TermWrapper(std::stod(token.second)));
+          state = EXPECTING_COMMA_OR_END;
+        }
+        else state = KO;
+        break;
+      default:
+        /* do nothing */
+        break;
+    }
+    ++idx;
+  }
+  if (state == OK)
+  {
+    cursor = idx;
+    predicate = new Predicate(pred_name, arguments);
+  }
+  return predicate;
+}
+
+QuerySpecification* parse_expression(const TokenV& tokens, std::size_t& cursor)
+{
+  enum State {EXPECTING_PRED_OR_PAR, EXPECTING_PAR_EXPR,
+    EXPECTING_PAR_CLOSE, EXPECTING_COMMA_OR_END, EXPECTING_END_EXPR, OK, KO};
+  State state = EXPECTING_PRED_OR_PAR;
+  bool negated = false;
+  QuerySpecification* query = nullptr;
+  std::size_t idx = cursor;
+  while (state != OK and state != KO)
+  {
+    const Token& token = tokens[idx];
+    std::cout << token.first << '(' << token.second << ')' << std::endl;
+    switch (state)
+    {
+      case EXPECTING_PRED_OR_PAR:
+        std::cout << "EXPECTING_PRED_OR_PAR" << std::endl;
+        if (token.first == "NOT")
+        {
+          negated = not negated;
+          ++idx;
+          /* Stay in the same state */
+        }
+        else if (Predicate* predicate = parse_predicate(tokens, idx))
+        {
+          query = new SimpleQuerySpecification(*predicate);
+          query = negated? new NotQuerySpecification(query) : query;
+          state = EXPECTING_COMMA_OR_END;
+          delete predicate;
+        }
+        else if (token.first == "PAR_OPEN")
+        {
+          state = EXPECTING_PAR_EXPR;
+          ++idx;
+        }
+        else state = KO;
+        break;
+      case EXPECTING_PAR_EXPR:
+        std::cout << "EXPECTING_PAR_EXPR" << std::endl;
+        if ((query = parse_expression(tokens, idx)))
+        {
+          query = negated? new NotQuerySpecification(query) : query;
+          state = EXPECTING_PAR_CLOSE;
+        }
+        else state = KO;
+        break;
+      case EXPECTING_PAR_CLOSE:
+        std::cout << "EXPECTING_PAR_CLOSE" << std::endl;
+        if (token.first == "PAR_CLOSE")
+        {
+          state = EXPECTING_COMMA_OR_END;
+          ++idx;
+        }
+        else state = KO;
+        break;
+      case EXPECTING_COMMA_OR_END:
+        std::cout << "EXPECTING_COMMA_OR_END" << std::endl;
+        if (token.first == "COMMA")
+        {
+          state = EXPECTING_END_EXPR;
+          ++idx;
+        }
+        else state = OK;
+        break;
+      case EXPECTING_END_EXPR:
+        std::cout << "EXPECTING_END_EXPR" << std::endl;
+        if (QuerySpecification* query_snd = parse_expression(tokens, idx))
+        {
+          query = new AndQuerySpecification(query, query_snd);
+          state = OK;
+        }
+        break;
+      default:
+        /* do nothing */
+        break;
+    }
+  }
+  if (state == OK)
+  {
+    std::cout << "OK" << std::endl;
+    cursor = idx;
+  }
+  else
+  {
+    std::cout << "KO" << std::endl;
+    if (query)
+    {
+      delete query;
+      query = nullptr;
+    }
+  }
+  return query;
+}
+
+QuerySpecification* parse_expression(const std::string& str)
+{
+  TokenV tokens = decompose(str);
+  std::size_t cursor = 0;
+  return parse_expression(tokens, cursor);
+}
+
+}
+
+
diff --git a/src/parsing.h b/src/parsing.h
new file mode 100644
index 0000000000000000000000000000000000000000..c89d6f2f4fbcfeac0a18afb7bafb6693824e4e39
--- /dev/null
+++ b/src/parsing.h
@@ -0,0 +1,26 @@
+#ifndef _LIBIMAGINE_PLANNER_PARSING_H_
+#define _LIBIMAGINE_PLANNER_PARSING_H_
+
+#include "queries.h"
+
+namespace imagine_planner
+{
+
+typedef std::pair<std::string, std::string> Token;
+typedef std::vector<Token> TokenV;
+
+bool is_number(const std::string& str);
+
+std::string remove_spaces(const std::string& in);
+
+TokenV decompose(const std::string& in);
+
+Predicate* parse_predicate(const TokenV& tokens, std::size_t& cursor);
+
+QuerySpecification* parse_expression(const TokenV& tokens, std::size_t& cursor);
+
+QuerySpecification* parse_expression(const std::string& str);
+
+} /* end namespace imagine_planner */
+
+#endif
diff --git a/src/queries.cpp b/src/queries.cpp
index 9ec9d7bde3121b2d5668c4c7d27c40149ca56766..3566caf868ffff48cab415dce7db43807abde301 100644
--- a/src/queries.cpp
+++ b/src/queries.cpp
@@ -7,12 +7,12 @@ namespace imagine_planner
 
 bool SimpleQuery::unify(const Predicate& goal)
 {
-  if (goal.arity() != target_.arity()) return false;
-  if (goal.get_name() != target_.get_name()) return false;
+  if (goal.arity() != pattern_.arity()) return false;
+  if (goal.get_name() != pattern_.get_name()) return false;
   sigma_ = sigma0_;
   for (int idx = 0; idx < goal.arity(); ++idx)
   {
-    const TermWrapper& term1 = target_.get_arguments()[idx];
+    const TermWrapper& term1 = pattern_.get_arguments()[idx];
     const TermWrapper& term2 = goal.get_arguments()[idx];
     if (term1.is_ground())
     {
@@ -30,19 +30,24 @@ bool SimpleQuery::unify(const Predicate& goal)
   return true;
 }
 
-SimpleQuery::SimpleQuery(const PlanState& state, const Predicate& target,
+SimpleQuery::SimpleQuery(const PlanState& state, const Predicate& pattern,
     const Substitution& sigma0) :
-  state_(state), target_(target), sigma0_(sigma0)
+  state_(state), pattern_(pattern), sigma0_(sigma0)
 {
   cursor_ = state_.begin();
 }
 
+std::string SimpleQuery::to_str() const
+{
+  return pattern_.to_str();
+}
+
 bool SimpleQuery::next_solution()
 {
-  if (cursor_ != state_.end() and target_.is_ground())
+  if (cursor_ != state_.end() and pattern_.is_ground())
   {
     cursor_ = state_.end();
-    return state_.has(target_);
+    return state_.has(pattern_);
   }
 
   while (cursor_ != state_.end())
@@ -65,37 +70,52 @@ void SimpleQuery::reset(const Substitution& sigma0)
 
 // NotQuery methods
 
-NotQuery::NotQuery(Query& q) : query_(q), done_(false) {}
+NotQuery::NotQuery(Query* q) : query_(q), done_(false) {}
+
+std::string NotQuery::to_str() const
+{
+  return std::string("\\+") + query_->to_str();
+}
 
 bool NotQuery::next_solution()
 {
   if (done_) return false;
   done_ = true;
-  return not query_.next_solution();
+  return not query_->next_solution();
 }
 
 void NotQuery::reset(const Substitution& sigma0)
 {
-  query_.reset(sigma0);
+  query_->reset(sigma0);
   done_ = false;
 }
 
+NotQuery::~NotQuery()
+{
+  delete query_;
+}
+
 // AndQuery methods
 
-AndQuery::AndQuery(Query& q1, Query& q2) :
+AndQuery::AndQuery(Query* q1, Query* q2) :
   q1_(q1), q2_(q2), first_fixed_(false) {}
 
+std::string AndQuery::to_str() const
+{
+  return std::string(1, '(') + q1_->to_str() + ',' + q2_->to_str() + ')';
+}
+
 bool AndQuery::next_solution()
 {
-  if (first_fixed_ and q2_.next_solution())
+  if (first_fixed_ and q2_->next_solution())
   {
     return true;
   }
   first_fixed_ = false;
-  while (q1_.next_solution())
+  while (q1_->next_solution())
   {
-    q2_.reset(q1_.get_solution());
-    if (q2_.next_solution())
+    q2_->reset(q1_->get_solution());
+    if (q2_->next_solution())
     {
       first_fixed_ = true;
       return true;
@@ -104,5 +124,71 @@ bool AndQuery::next_solution()
   return false;
 }
 
+AndQuery::~AndQuery()
+{
+  delete q1_;
+  delete q2_;
+}
+
+// SimpleQuerySpecification methods
+
+std::string SimpleQuerySpecification::to_str() const
+{
+  return pattern_.to_str();
+}
+
+SimpleQuerySpecification::SimpleQuerySpecification(const Predicate& pattern)
+  : pattern_(pattern) {}
+
+Query* SimpleQuerySpecification::operator()(const PlanState& state,
+    const Substitution& sigma0) const
+{
+  return new SimpleQuery(state, pattern_, sigma0);
+}
+
+
+// NotQuerySpecification methods
+
+std::string NotQuerySpecification::to_str() const
+{
+  return std::string("\\+") + query_->to_str();
+}
+
+NotQuerySpecification::~NotQuerySpecification()
+{
+  delete query_;
+}
+
+NotQuerySpecification::NotQuerySpecification(QuerySpecification* query)
+  : query_(query) {}
+
+Query* NotQuerySpecification::operator()(const PlanState& state,
+    const Substitution& sigma0) const
+{
+  return new NotQuery((*query_)(state, sigma0));
+}
+
+// AndQuerySpecification methods
+
+std::string AndQuerySpecification::to_str() const
+{
+  return std::string(1,'(') + q1_->to_str() + ',' + q2_->to_str() + ')';
+}
+
+AndQuerySpecification::~AndQuerySpecification()
+{
+  delete q1_;
+  delete q2_;
+}
+
+AndQuerySpecification::AndQuerySpecification(QuerySpecification* q1,
+    QuerySpecification* q2) : q1_(q1), q2_(q2) {}
+
+Query* AndQuerySpecification::operator()(const PlanState& state,
+    const Substitution& sigma0) const
+{
+  return new AndQuery((*q1_)(state, sigma0), (*q2_)(state, sigma0));
+}
+
 }
 
diff --git a/src/queries.h b/src/queries.h
index 3efe6e4f5f660b41333cda521410133fbec859d5..86f6976174299c996e60387d9e8909777bfb5b69 100644
--- a/src/queries.h
+++ b/src/queries.h
@@ -6,10 +6,10 @@
 namespace imagine_planner
 {
 
-class Query
+class Query : public Stringifiable
 {
   public:
-    virtual ~Query() {};
+    virtual ~Query() {}
 
     virtual bool next_solution() =0;
 
@@ -25,16 +25,18 @@ class SimpleQuery : public Query
 {
   private:
     const PlanState& state_;
-    Predicate target_;
+    Predicate pattern_;
     Substitution sigma0_, sigma_;
     PlanState::CIter cursor_;
 
     bool unify(const Predicate& goal);
     
   public:
-    SimpleQuery(const PlanState& state, const Predicate& target,
+    SimpleQuery(const PlanState& state, const Predicate& pattern,
         const Substitution& sigma0=Substitution());
 
+    virtual std::string to_str() const override;
+
     virtual bool next_solution() override;
 
     virtual const Substitution& get_solution() const override { return sigma_; }
@@ -48,54 +50,117 @@ class SimpleQuery : public Query
 class NotQuery : public Query
 {
   private:
-    Query& query_;
+    Query* query_;
     bool done_;
 
   public:
-    NotQuery(Query& q);
+    NotQuery(Query* q);
+
+    virtual std::string to_str() const override;
 
     virtual bool next_solution() override;
 
     virtual const Substitution& get_solution() const override
     {
-      return query_.get_sigma0();
+      return query_->get_sigma0();
     }
 
     virtual const Substitution& get_sigma0() const override
     {
-      return query_.get_sigma0();
+      return query_->get_sigma0();
     }
 
     virtual void reset(const Substitution& sigma0) override;
+
+    virtual ~NotQuery() override;
 };
 
 class AndQuery : public Query
 {
   private:
-    Query& q1_;
-    Query& q2_;
+    Query* q1_;
+    Query* q2_;
     bool first_fixed_;
 
   public:
-    AndQuery(Query& q1, Query& q2);
+    AndQuery(Query* q1, Query* q2);
+
+    virtual std::string to_str() const override;
 
     virtual bool next_solution() override;
 
     virtual const Substitution& get_solution() const override
     {
-      return q2_.get_solution();
+      return q2_->get_solution();
     }
 
     virtual const Substitution& get_sigma0() const override
     {
-      return q1_.get_sigma0();
+      return q1_->get_sigma0();
     }
 
     virtual void reset(const Substitution& sigma0) override
     {
-      q1_.reset(sigma0);
+      q1_->reset(sigma0);
     }
 
+    virtual ~AndQuery() override;
+
+};
+
+class QuerySpecification : public Stringifiable
+{
+  public:
+    virtual Query* operator()(const PlanState& state,
+        const Substitution& sigma0=Substitution()) const=0;
+
+    virtual ~QuerySpecification() {}
+};
+
+class SimpleQuerySpecification : public QuerySpecification
+{
+  private:
+    Predicate pattern_;
+
+  public:
+    virtual std::string to_str() const override;
+
+    SimpleQuerySpecification(const Predicate& pattern);
+
+    virtual Query* operator()(const PlanState& state,
+        const Substitution& sigma0=Substitution()) const override;
+};
+
+class NotQuerySpecification : public QuerySpecification
+{
+  private:
+    QuerySpecification* query_;
+
+  public:
+    virtual std::string to_str() const override;
+
+    NotQuerySpecification(QuerySpecification* query);
+
+    virtual Query* operator()(const PlanState& state,
+        const Substitution& sigma0=Substitution()) const override;
+
+    virtual ~NotQuerySpecification() override;
+};
+
+class AndQuerySpecification : public QuerySpecification
+{
+  private:
+    QuerySpecification* q1_;
+    QuerySpecification* q2_;
+  public:
+    virtual std::string to_str() const override;
+
+    AndQuerySpecification(QuerySpecification* q1, QuerySpecification* q2);
+
+    virtual Query* operator()(const PlanState& state,
+        const Substitution& sigma0=Substitution()) const override;
+
+    virtual ~AndQuerySpecification() override;
 };
 
 } /* end namespace imagine-planner */