Boost Spirit Classic における計算機の例

ID: 22
creation date: 2013/04/04 12:50
modification date: 2013/04/04 12:50
owner: taiji
tags: C++, Boost, Spirit, Spirit Classic, セマンティックアクション

Boost Spirit のサンプルにはいくつもの計算機の例があるが、四則演算以外をサポートした簡潔な好例がなく、ここで実装例を紹介する価値はありそうである。

手始めに復習を兼ねて Spirit Classic での例を紹介していく。

Spirit Classic の基本形

Spirit Classic の基本形は以下のようになる。

#include <iostream>
#include <string>
#include <boost/spirit/include/classic.hpp>

using namespace boost::spirit::classic;

namespace client {
  struct a_parser : public grammar<a_parser> {
    template <typename S>
    struct definition {
      rule<S> top;
      definition(const a_parser &self)
      {
        top = *~ch_p('\t'); // ここにパーサ規則を書く
      }
      const rule<S> &start() const { return top; }
    };
  };
}
int main()
{
  client::a_parser a_parser;
  std::string str;
  while (std::getline(std::cin, str)) {
    parse_info<std::string::iterator> r =
      parse(str.begin(), str.end(), a_parser, ~anychar_p);
    if (r.full && r.stop == str.end()) {
      std::cout << "succeeded" << std::endl;
    }
    else {
      std::cout << "failed:\t" << std::string(r.stop, str.end()) << std::endl;
      return 1;
    }
  }
  return 0;
}

計算機でサポートする演算子

以下の演算子をサポートする実装例を段階的に示そう。

  1. 単項演算子の単項正負(+ -)、単項論理否定&ビット否定(! ~)、二項演算子の二項加減乗除法(+ - * / %)、関係等号不等号(< <= > >= == !=)、ビットシフト(<< >>)、ビット演算子(& ^ |)、論理積和(&& ||)
  2. 三項演算子の三項条件(?:)
  3. 変数のサポートおよび単項演算子の前後置増減分(++ --)、二項演算子の単純代入(=)、複合代入(+= -+ *= /= %= &= ^= +=)およびカンマ演算子(,)

また、演算は任意の数値型で行えるように実装する。

ここで、int型における1.と2.の演算についてはiexpr、3.についてはicalcというプログラム名をつけるものとする。

ここでは敢えてAST(Abstract Syntax Tree)による例は別稿にゆずり、セマンティックアクションで計算機を実装する例を紹介する。セマンティックアクションでは構文解析しながら演算を行うので、例えば、以下のような代入と三項条件の組み合わせについては困難を伴うので、サポートしないものとする。

i<j ? i++ : i=j

iexpr_classic.cc

int型における1.と2.の演算を行う計算機を Spirit Classic で実装すると以下のようになるだろう。

#include <iostream>
#include <iomanip>
#include <string>
#include <stack>
#include <functional>
#include "more_functional"
#include <boost/spirit/include/classic.hpp>

using namespace boost::spirit::classic;

namespace client {
  template <typename T>
  struct popper {
    popper(std::stack<T> &vs_) : vs(vs_) {}
    void operator()(const T v=0) const { (void)vs.pop(); }
    std::stack<T> &vs;
  };

  template <typename T>
  struct pusher {
    pusher(std::stack<T> &vs_) : vs(vs_) {}
    void operator()(T v) const { vs.push(v); }
    std::stack<T> &vs;
  };

  template <typename T>
  struct top_popper {
    top_popper(std::stack<T> &vs_) : vs(vs_) {}
    T operator()() const { T a = vs.top(); (popper<T>(vs))(); return a; }
    std::stack<T> &vs;
  };

  template <typename F, typename T>
  struct unary_f_pusher {
    unary_f_pusher(F const &f_, std::stack<T> &vs_) : f(f_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      T lhs = (top_popper<T>(vs))();
      (pusher<T>(vs))(f(lhs));
    }
    F f;
    std::stack<T> &vs;
  };

  template <class F, typename T>
  unary_f_pusher<F, T> unary_f_doer(F const &f, std::stack<T> &vs)
  {
    return unary_f_pusher<F, T>(f, vs);
  }

  template <typename F, typename T>
  struct binary_f_pusher {
    binary_f_pusher(F const &f_, std::stack<T> &vs_) : f(f_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      T rhs = (top_popper<T>(vs))(), lhs = (top_popper<T>(vs))();
      (pusher<T>(vs))(f(lhs, rhs));
    }
    F f;
    std::stack<T> &vs;
  };

  template <class F, typename T>
  binary_f_pusher<F, T> binary_f_doer(F const &f, std::stack<T> &vs)
  {
    return binary_f_pusher<F, T>(f, vs);
  }

#if !0 /* ternary operator */
  template <typename T>
  struct ternary_condition_doer {
    ternary_condition_doer(std::stack<T> &vs_) : vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      T c = (top_popper<T>(vs))(), b = (top_popper<T>(vs))(), a = (top_popper<T>(vs))();
      (pusher<T>(vs))(a ? b : c);
    }
    std::stack<T> &vs;
  };
#endif

  template <typename T>
  struct calc : public grammar<calc<T> > {
    calc(std::stack<T> &vs_) : vs(vs_) {}
    template <typename S>
    struct definition {
      rule<S> expr, t[9], term, fctr;
      definition(calc const &self)
      {
#if !0 /* ternary operator */
        expr = t[0] >> *('?'    >> expr >>
                         ':'    >> expr)[ternary_condition_doer<T>(self.vs)];
#else
        expr = t[0];
#endif
        t[0] = t[1] >> *("||"   >> t[1][binary_f_doer(std::logical_or<T>(), self.vs)]);
        t[1] = t[2] >> *("&&"   >> t[2][binary_f_doer(std::logical_and<T>(), self.vs)]);
        t[2] = t[3] >> *('|'    >> t[3][binary_f_doer(std::bitwise_or<T>(), self.vs)]);
        t[3] = t[4] >> *('^'    >> t[4][binary_f_doer(std::bitwise_xor<T>(), self.vs)]);
        t[4] = t[5] >> *('&'    >> t[5][binary_f_doer(std::bitwise_and<T>(), self.vs)]);
        t[5] = t[6] >> *("<<"   >> t[6][binary_f_doer(std::bitshift_left<T>(), self.vs)] |
                         ">>"   >> t[6][binary_f_doer(std::bitshift_right<T>(), self.vs)]);
        t[6] = t[7] >> *('<'    >> t[7][binary_f_doer(std::less<T>(), self.vs)] |
                         '>'    >> t[7][binary_f_doer(std::greater<T>(), self.vs)] |
                         "<="   >> t[7][binary_f_doer(std::less_equal<T>(), self.vs)] |
                         ">="   >> t[7][binary_f_doer(std::greater_equal<T>(), self.vs)]);
        t[7] = t[8] >> *("=="   >> t[8][binary_f_doer(std::equal_to<T>(), self.vs)] |
                         "!="   >> t[8][binary_f_doer(std::not_equal_to<T>(), self.vs)]);
        t[8] = term >> *('+'    >> term[binary_f_doer(std::plus<T>(), self.vs)] |
                         '-'    >> term[binary_f_doer(std::minus<T>(), self.vs)]);
        term = fctr >> *('*'    >> fctr[binary_f_doer(std::multiplies<T>(), self.vs)] |
                         '/'    >> fctr[binary_f_doer(std::divides<T>(), self.vs)] |
                         '%'    >> fctr[binary_f_doer(std::modulus<T>(), self.vs)]);
        fctr = "0x" >> hex_p[pusher<T>(self.vs)] |
          '0' >> oct_p[pusher<T>(self.vs)] |
          uint_p[pusher<T>(self.vs)] |
          '(' >> expr >> ')' |
          '-' >> fctr[unary_f_doer(std::negate<T>(), self.vs)] |
          '+' >> fctr |
          '!' >> fctr[unary_f_doer(std::logical_not<T>(), self.vs)] |
          '~' >> fctr[unary_f_doer(std::bitwise_not<T>(), self.vs)];
      }
      rule<S> const &start() const { return expr; }
    };
    mutable T *var;
    std::stack<T> &vs;
  };
}

int main()
{
  int rv = 0;

  typedef int value_type;
  std::stack<value_type> st;
  client::calc<value_type> calc(st);
  std::string str;
  while (std::getline(std::cin, str)) {
    parse_info<> r = parse(str.c_str(), calc, space_p);
    if (r.full && r.stop == str.c_str()+str.size()) {
      std::cout << "succeeded:\t" << std::endl;
      std::cout << calc.vs.top() << std::endl;
    }
    else {
      std::cout << "failed:\t" << std::string(r.stop, str.c_str()+str.size()) << std::endl;
      rv = !0;
    }
    calc.vs = std::stack<value_type>();
  }
  return rv;
}

もし unsigned int 型の演算を行いたければ、main 関数の冒頭を typedef unsigned int value_type; に書き換えれば良い。

ちなみに、ここでは別項で使用した more_functional を使用していることに注意。

icalc_classic.cc

さて、iexpr_classic.cc に変数のサポートと代入演算子を導入すると以下のようになるだろう。

#include <iostream>
#include <iomanip>
#include <string>
#include <stack>
#include <functional>
#include "more_functional"
#include <boost/spirit/include/classic.hpp>

using namespace boost::spirit::classic;

namespace client {
  template <typename T>
  struct popper {
    popper(std::stack<T> &vs_) : vs(vs_) {}
    void operator()(const T v=0) const { (void)vs.pop(); }
    std::stack<T> &vs;
  };

  template <typename T>
  struct pusher {
    pusher(std::stack<T> &vs_) : vs(vs_) {}
    void operator()(T v) const { vs.push(v); }
    std::stack<T> &vs;
  };

  template <typename T>
  struct swapper {
   swapper(std::stack<T> &vs_) : vs(vs_) {}
    void operator()(T v) const { (popper<T>(vs))(); (pusher<T>(vs))(v); }
    std::stack<T> &vs;
  };

  template <typename T>
  struct top_popper {
    top_popper(std::stack<T> &vs_) : vs(vs_) {}
    T operator()() const { T a = vs.top(); (popper<T>(vs))(); return a; }
    std::stack<T> &vs;
  };

  template <typename F, typename T>
  struct unary_f_pusher {
    unary_f_pusher(F const &f_, std::stack<T> &vs_) : f(f_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      T lhs = (top_popper<T>(vs))();
      (pusher<T>(vs))(f(lhs));
    }
    F f;
    std::stack<T> &vs;
  };

  template <class F, typename T>
  unary_f_pusher<F, T> unary_f_doer(F const &f, std::stack<T> &vs)
  {
    return unary_f_pusher<F, T>(f, vs);
  }

  template <typename F, typename T>
  struct binary_f_pusher {
    binary_f_pusher(F const &f_, std::stack<T> &vs_) : f(f_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      T rhs = (top_popper<T>(vs))(), lhs = (top_popper<T>(vs))();
      (pusher<T>(vs))(f(lhs, rhs));
    }
    F f;
    std::stack<T> &vs;
  };

  template <class F, typename T>
  binary_f_pusher<F, T> binary_f_doer(F const &f, std::stack<T> &vs)
  {
    return binary_f_pusher<F, T>(f, vs);
  }

#if !0 /* ternary operator */
  template <typename T>
  struct ternary_condition_doer {
    ternary_condition_doer(std::stack<T> &vs_) : vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      T c = (top_popper<T>(vs))(), b = (top_popper<T>(vs))(), a = (top_popper<T>(vs))();
      (pusher<T>(vs))(a ? b : c);
    }
    std::stack<T> &vs;
  };
#endif

  template <typename T>
  struct lvar_pusher {
    lvar_pusher(symbols<T> &vars_, T *&var_, std::stack<T> &vs_) : vars(vars_), var(var_), vs(vs_) {}
    void operator()(char const *first, const char *last) const
    {
      if (!(var = find(vars, std::string(first, last).c_str()))) {
        vars.add(first, last, T(0));
        var = find(vars, std::string(first, last).c_str());
      }
      (pusher<T>(vs))(*var);
    }
    symbols<T> &vars;
    T *&var;
    std::stack<T> &vs;
  };

  template <typename T>
  struct postfix_incrementer {
    postfix_incrementer(T *&var_, std::stack<T> &vs_) : var(var_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      (popper<T>(vs))();
      (pusher<T>(vs))((*var)++); 
    }
    T *&var;
    std::stack<T> &vs;
  };

  template <typename T>
  struct postfix_decrementer {
    postfix_decrementer(T *&var_, std::stack<T> &vs_) : var(var_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      (popper<T>(vs))();
      (pusher<T>(vs))((*var)--);
    }
    T *&var;
    std::stack<T> &vs;
  };

  template <typename T>
  struct prefix_incrementer {
    prefix_incrementer(T *&var_, std::stack<T> &vs_) : var(var_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      (pusher<T>(vs))(++(*var));
    }
    T *&var;
    std::stack<T> &vs;
  };

  template <typename T>
  struct prefix_decrementer {
    prefix_decrementer(T *&var_, std::stack<T> &vs_) : var(var_), vs(vs_) {}
    void operator()(char const *first, char const *last) const
    {
      (pusher<T>(vs))(--(*var));
    }
    T *&var;
    std::stack<T> &vs;
  };

  template <typename F, typename T>
  struct unary_f_var_pusher {
    unary_f_var_pusher(F const &f_, T *&var_, std::stack<T> &vs_) : f(f_), var(var_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      (swapper<T>(vs))((*var=f((top_popper<T>(vs))())));
    }
    F f;
    T *&var;
    std::stack<T> &vs;
  };

  template <class F, typename T>
  unary_f_var_pusher<F, T> unary_f_assignor(F const &f, T *&var, std::stack<T> &vs)
  {
    return unary_f_var_pusher<F, T>(f, var, vs);
  }

  template <typename F, typename T>
  struct binary_f_var_pusher {
    binary_f_var_pusher(F const &f_, T *&var_, std::stack<T> &vs_) : f(f_), var(var_), vs(vs_) {}
    void operator()(char const *, char const *) const
    {
      T rhs = (top_popper<T>(vs))();
      (pusher<T>(vs))((*var=f((top_popper<T>(vs))(), rhs)));
    }
    F f;
    T *&var;
    std::stack<T> &vs;
  };

  template <class F, typename T>
  binary_f_var_pusher<F, T> binary_f_assignor(F const &f, T *&var, std::stack<T> &vs)
  {
    return binary_f_var_pusher<F, T>(f, var, vs);
  }


  template <typename T>
  struct calc : public grammar<calc<T> > {
    calc(symbols<T> &vars_, std::stack<T> &vs_) : vars(vars_), vs(vs_) {}
    template <typename S>
    struct definition {
      rule<S> vars, e[7], expr, t[9], term, fctr;
      definition(calc const &self)
      {
        vars = lexeme_d[(alpha_p >> *(alnum_p | '_'))][lvar_pusher<T>(self.vars, self.var, self.vs)];
        expr = e[0] % ch_p(',')[popper<T>(self.vs)];
        e[0] = e[1] | e[2] | e[3] | e[4] | e[5] | e[6];
        e[1] = vars >> ('='     >> e[0][unary_f_assignor(std::identify<T>(), self.var, self.vs)]);
        e[2] = vars >> ("+="    >> e[0][binary_f_assignor(std::plus<T>(), self.var, self.vs)] |
                        "-="    >> e[0][binary_f_assignor(std::minus<T>(), self.var, self.vs)]);
        e[3] = vars >> ("*="    >> e[0][binary_f_assignor(std::multiplies<T>(), self.var, self.vs)] |
                        "/="    >> e[0][binary_f_assignor(std::divides<T>(), self.var, self.vs)] |
                        "%="    >> e[0][binary_f_assignor(std::modulus<T>(), self.var, self.vs)]);
        e[4] = vars >> ("<<="   >> e[0][binary_f_assignor(std::bitshift_left<T>(), self.var, self.vs)] |
                        ">>="   >> e[0][binary_f_assignor(std::bitshift_right<T>(), self.var, self.vs)]);
        e[5] = vars >> ("&="    >> e[0][binary_f_assignor(std::bitwise_and<T>(), self.var, self.vs)] |
                        "^="    >> e[0][binary_f_assignor(std::bitwise_xor<T>(), self.var, self.vs)] |
                        "|="    >> e[0][binary_f_assignor(std::bitwise_or<T>(), self.var, self.vs)]);
#if !0 /* ternary operator */
        e[6] = t[0] >> *('?'    >> e[0] >>
                         ':'    >> e[0])[ternary_condition_doer<T>(self.vs)];
#else
        e[6] = t[0];
#endif
        t[0] = t[1] >> *("||"   >> t[1][binary_f_doer(std::logical_or<T>(), self.vs)]);
        t[1] = t[2] >> *("&&"   >> t[2][binary_f_doer(std::logical_and<T>(), self.vs)]);
        t[2] = t[3] >> *('|'    >> t[3][binary_f_doer(std::bitwise_or<T>(), self.vs)]);
        t[3] = t[4] >> *('^'    >> t[4][binary_f_doer(std::bitwise_xor<T>(), self.vs)]);
        t[4] = t[5] >> *('&'    >> t[5][binary_f_doer(std::bitwise_and<T>(), self.vs)]);
        t[5] = t[6] >> *("<<"   >> t[6][binary_f_doer(std::bitshift_left<T>(), self.vs)] |
                         ">>"   >> t[6][binary_f_doer(std::bitshift_right<T>(), self.vs)]);
        t[6] = t[7] >> *('<'    >> t[7][binary_f_doer(std::less<T>(), self.vs)] |
                         '>'    >> t[7][binary_f_doer(std::greater<T>(), self.vs)] |
                         "<="   >> t[7][binary_f_doer(std::less_equal<T>(), self.vs)] |
                         ">="   >> t[7][binary_f_doer(std::greater_equal<T>(), self.vs)]);
        t[7] = t[8] >> *("=="   >> t[8][binary_f_doer(std::equal_to<T>(), self.vs)] |
                         "!="   >> t[8][binary_f_doer(std::not_equal_to<T>(), self.vs)]);
        t[8] = term >> *('+'    >> term[binary_f_doer(std::plus<T>(), self.vs)] |
                         '-'    >> term[binary_f_doer(std::minus<T>(), self.vs)]);
        term = fctr >> *('*'    >> fctr[binary_f_doer(std::multiplies<T>(), self.vs)] |
                         '/'    >> fctr[binary_f_doer(std::divides<T>(), self.vs)] |
                         '%'    >> fctr[binary_f_doer(std::modulus<T>(), self.vs)]);
        fctr = "0x" >> hex_p[pusher<T>(self.vs)] |
          '0' >> oct_p[pusher<T>(self.vs)] |
          uint_p[pusher<T>(self.vs)] |
          "++" >> vars[prefix_incrementer<T>(self.var, self.vs)] |
          "--" >> vars[prefix_decrementer<T>(self.var, self.vs)] |
          vars >> str_p("++")[postfix_incrementer<T>(self.var, self.vs)] |
          vars >> str_p("--")[postfix_decrementer<T>(self.var, self.vs)] |
          vars |
          '(' >> expr >> ')' |
          '-' >> fctr[unary_f_doer(std::negate<T>(), self.vs)] |
          '+' >> fctr |
          '!' >> fctr[unary_f_doer(std::logical_not<T>(), self.vs)] |
          '~' >> fctr[unary_f_doer(std::bitwise_not<T>(), self.vs)];
      }
      rule<S> const &start() const { return expr; }
    };
    symbols<T> &vars;
    mutable T *var;
    std::stack<T> &vs;
  };
}

int main()
{
  int rv = 0;

  typedef int value_type;
  symbols<value_type> vars;
  std::stack<value_type> st;
  client::calc<value_type> calc(vars, st);
  std::string str;
  while (std::getline(std::cin, str)) {
    parse_info<> r = parse(str.c_str(), calc, space_p);
    if (r.full && r.stop == str.c_str()+str.size()) {
      std::cout << "succeeded:\t" << std::endl;
      std::cout << calc.vs.top() << std::endl;
    }
    else {
      std::cout << "failed:\t" << std::string(r.stop, str.c_str()+str.size()) << std::endl;
      rv = !0;
    }
    calc.vs = std::stack<value_type>();
  }
  return rv;
}

同様に、もし unsigned int 型の演算を行いたければ、main 関数の冒頭を typedef unsigned int value_type; に書き換えれば良い。

ちなみに、この実装では代入時に未使用の変数を新たに使用することができ、変数の参照時に未使用の変数を使用すると零が代入されているものとする。

diff -u iexpr_classic.cc icalc_classic.cc

上述の二つのプログラムリストの掲示だけでは、どのように変数のサポートと代入演算子を導入したかが分かり辛いので、これらの Unified diff 形式をみてみよう。

--- iexpr_classic.cc
+++ icalc_classic.cc
@@ -24,6 +24,13 @@
   };
 
+  template <typename T>
+  struct swapper {
+   swapper(std::stack<T> &vs_) : vs(vs_) {}
+    void operator()(T v) const { (popper<T>(vs))(); (pusher<T>(vs))(v); }
+    std::stack<T> &vs;
+  };
+
   template <typename T>
   struct top_popper {
     top_popper(std::stack<T> &vs_) : vs(vs_) {}
     T operator()() const { T a = vs.top(); (popper<T>(vs))(); return a; }
@@ -80,18 +87,132 @@
 #endif
 
+  template <typename T>
+  struct lvar_pusher {
+    lvar_pusher(symbols<T> &vars_, T *&var_, std::stack<T> &vs_) : vars(vars_), var(var_), vs(vs_) {}
+    void operator()(char const *first, const char *last) const
+    {
+      if (!(var = find(vars, std::string(first, last).c_str()))) {
+        vars.add(first, last, T(0));
+        var = find(vars, std::string(first, last).c_str());
+      }
+      (pusher<T>(vs))(*var);
+    }
+    symbols<T> &vars;
+    T *&var;
+    std::stack<T> &vs;
+  };
+
+  template <typename T>
+  struct postfix_incrementer {
+    postfix_incrementer(T *&var_, std::stack<T> &vs_) : var(var_), vs(vs_) {}
+    void operator()(char const *, char const *) const
+    {
+      (popper<T>(vs))();
+      (pusher<T>(vs))((*var)++); 
+    }
+    T *&var;
+    std::stack<T> &vs;
+  };
+
+  template <typename T>
+  struct postfix_decrementer {
+    postfix_decrementer(T *&var_, std::stack<T> &vs_) : var(var_), vs(vs_) {}
+    void operator()(char const *, char const *) const
+    {
+      (popper<T>(vs))();
+      (pusher<T>(vs))((*var)--);
+    }
+    T *&var;
+    std::stack<T> &vs;
+  };
+
+  template <typename T>
+  struct prefix_incrementer {
+    prefix_incrementer(T *&var_, std::stack<T> &vs_) : var(var_), vs(vs_) {}
+    void operator()(char const *, char const *) const
+    {
+      (pusher<T>(vs))(++(*var));
+    }
+    T *&var;
+    std::stack<T> &vs;
+  };
+
+  template <typename T>
+  struct prefix_decrementer {
+    prefix_decrementer(T *&var_, std::stack<T> &vs_) : var(var_), vs(vs_) {}
+    void operator()(char const *first, char const *last) const
+    {
+      (pusher<T>(vs))(--(*var));
+    }
+    T *&var;
+    std::stack<T> &vs;
+  };
+
+  template <typename F, typename T>
+  struct unary_f_var_pusher {
+    unary_f_var_pusher(F const &f_, T *&var_, std::stack<T> &vs_) : f(f_), var(var_), vs(vs_) {}
+    void operator()(char const *, char const *) const
+    {
+      (swapper<T>(vs))((*var=f((top_popper<T>(vs))())));
+    }
+    F f;
+    T *&var;
+    std::stack<T> &vs;
+  };
+
+  template <class F, typename T>
+  unary_f_var_pusher<F, T> unary_f_assignor(F const &f, T *&var, std::stack<T> &vs)
+  {
+    return unary_f_var_pusher<F, T>(f, var, vs);
+  }
+
+  template <typename F, typename T>
+  struct binary_f_var_pusher {
+    binary_f_var_pusher(F const &f_, T *&var_, std::stack<T> &vs_) : f(f_), var(var_), vs(vs_) {}
+    void operator()(char const *, char const *) const
+    {
+      T rhs = (top_popper<T>(vs))();
+      (pusher<T>(vs))((*var=f((top_popper<T>(vs))(), rhs)));
+    }
+    F f;
+    T *&var;
+    std::stack<T> &vs;
+  };
+
+  template <class F, typename T>
+  binary_f_var_pusher<F, T> binary_f_assignor(F const &f, T *&var, std::stack<T> &vs)
+  {
+    return binary_f_var_pusher<F, T>(f, var, vs);
+  }
+
+
   template <typename T>
   struct calc : public grammar<calc<T> > {
-    calc(std::stack<T> &vs_) : vs(vs_) {}
+    calc(symbols<T> &vars_, std::stack<T> &vs_) : vars(vars_), vs(vs_) {}
     template <typename S>
     struct definition {
-      rule<S> expr, t[9], term, fctr;
+      rule<S> vars, e[7], expr, t[9], term, fctr;
       definition(calc const &self)
       {
+        vars = lexeme_d[(alpha_p >> *(alnum_p | '_'))][lvar_pusher<T>(self.vars, self.var, self.vs)];
+        expr = e[0] % ch_p(',')[popper<T>(self.vs)];
+        e[0] = e[1] | e[2] | e[3] | e[4] | e[5] | e[6];
+        e[1] = vars >> ('='     >> e[0][unary_f_assignor(std::identify<T>(), self.var, self.vs)]);
+        e[2] = vars >> ("+="    >> e[0][binary_f_assignor(std::plus<T>(), self.var, self.vs)] |
+                        "-="    >> e[0][binary_f_assignor(std::minus<T>(), self.var, self.vs)]);
+        e[3] = vars >> ("*="    >> e[0][binary_f_assignor(std::multiplies<T>(), self.var, self.vs)] |
+                        "/="    >> e[0][binary_f_assignor(std::divides<T>(), self.var, self.vs)] |
+                        "%="    >> e[0][binary_f_assignor(std::modulus<T>(), self.var, self.vs)]);
+        e[4] = vars >> ("<<="   >> e[0][binary_f_assignor(std::bitshift_left<T>(), self.var, self.vs)] |
+                        ">>="   >> e[0][binary_f_assignor(std::bitshift_right<T>(), self.var, self.vs)]);
+        e[5] = vars >> ("&="    >> e[0][binary_f_assignor(std::bitwise_and<T>(), self.var, self.vs)] |
+                        "^="    >> e[0][binary_f_assignor(std::bitwise_xor<T>(), self.var, self.vs)] |
+                        "|="    >> e[0][binary_f_assignor(std::bitwise_or<T>(), self.var, self.vs)]);
 #if !0 /* ternary operator */
-        expr = t[0] >> *('?'    >> expr >>
-                         ':'    >> expr)[ternary_condition_doer<T>(self.vs)];
+        e[6] = t[0] >> *('?'    >> e[0] >>
+                         ':'    >> e[0])[ternary_condition_doer<T>(self.vs)];
 #else
-        expr = t[0];
+        e[6] = t[0];
 #endif
         t[0] = t[1] >> *("||"   >> t[1][binary_f_doer(std::logical_or<T>(), self.vs)]);
         t[1] = t[2] >> *("&&"   >> t[2][binary_f_doer(std::logical_and<T>(), self.vs)]);
@@ -114,6 +235,11 @@
         fctr = "0x" >> hex_p[pusher<T>(self.vs)] |
           '0' >> oct_p[pusher<T>(self.vs)] |
           uint_p[pusher<T>(self.vs)] |
+          "++" >> vars[prefix_incrementer<T>(self.var, self.vs)] |
+          "--" >> vars[prefix_decrementer<T>(self.var, self.vs)] |
+          vars >> str_p("++")[postfix_incrementer<T>(self.var, self.vs)] |
+          vars >> str_p("--")[postfix_decrementer<T>(self.var, self.vs)] |
+          vars |
           '(' >> expr >> ')' |
           '-' >> fctr[unary_f_doer(std::negate<T>(), self.vs)] |
           '+' >> fctr |
@@ -122,6 +248,7 @@
       }
       rule<S> const &start() const { return expr; }
     };
+    symbols<T> &vars;
     mutable T *var;
     std::stack<T> &vs;
   };
@@ -132,8 +259,9 @@
   int rv = 0;
 
   typedef int value_type;
+  symbols<value_type> vars;
   std::stack<value_type> st;
-  client::calc<value_type> calc(st);
+  client::calc<value_type> calc(vars, st);
   std::string str;
   while (std::getline(std::cin, str)) {
     parse_info<> r = parse(str.c_str(), calc, space_p);

lvar_pusher 関数オブジェクトにより、変数の新規使用のときは symbols<value_type> vars に登録され、既に登録されている変数ならば symbols<value_type> vars がもつ数値が使用される。

0 コメント
ゲストコメント認証用なぞなぞ:
キーボードのLから左に全部打って下さい。それを二回やって下さい。 ...