C++でSchemeインタプリタを作ろう

少し作った。

(define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1)))))
; ok
(factorial 10)
; 3628800

おー。Accelerated C++ と Effective C++ という本を読んだんだけど書き方がわからないのでひげぽんのコードを参考に勉強しようとしたんだけど日記にコードは殆ど載ってなくてつかえねーと思いつつ書いた。そういう訳であんまり C++ の勉強にはなってないような。ポインタとか参照とかリソース管理とかがさっぱりわからない。メモリが駄々漏れ。

以下ソースコード

main

#include <iostream>
#include <scheme.h>

using namespace std;
using namespace scheme;

int main() {
  Environment* env = createGlobalEnvironment();
  string str, line;
  while (getline(cin, line)) {
    str += line;
    if(Expression* exp = parse(str)) {
      cout << "; " << exp->eval(env)->string() << endl;
      str = "";
    }
  }

  return 0;
}

scheme.h

#ifndef SCHEME_H_INCLUDED
#define SCHEME_H_INCLUDED
#include <map>
#include <vector>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>

namespace scheme {

  class Expression;
  class Variable;
  typedef std::vector<Expression*> Expressions;


  // Parse
  Expression* parse(const std::string& str);


  // Environment - 変数テーブルをもってる
  class Environment {
  public:
    Environment(Environment* env = 0): base(env) {};
    Expression* variableValue(Variable* var);
    void defineVariable(Variable* var, Expression* value);
    Environment* extend(Expressions* vars, Expressions* vals);
  private:
    std::map<std::string, Expression*> table;
    Environment* base;
  };
  Environment* createGlobalEnvironment();


  // Expressions
  Expressions* evalAll(Expressions const* exprs, Environment* env);
  std::string toString(Expressions* exprs);

  // Expression
  class Expression {
  public:
    virtual ~Expression() {};
    virtual Expression* eval(Environment* env) = 0;
    virtual std::string string() const = 0;
    virtual bool boolValue() const { return false; }
  };

  class Number: public Expression {
  public:
    Number(int n): num(n) {};
    virtual Expression* eval(Environment* env);
    virtual std::string string() const;
    virtual bool boolValue() const;
    int intValue() const;
  private:
    int num;
  };

  Number* True = new Number(1);
  Number* False = new Number(0);

  class String: public Expression {
  public:
    String(const std::string& s): str(s) {};
    virtual Expression* eval(Environment* env);
    virtual std::string string() const;
  private:
    std::string str;
  };

  class Variable: public Expression {
  public:
    Variable(const std::string& str): name_(str) {}
    virtual Expression* eval(Environment* env);
    virtual std::string string() const;
    const std::string name() const;
  private:
    std::string name_;
  };

  class If: public Expression {
  public:
    If(Expression* p, Expression* c, Expression* a)
      : predicate(p), consequent(c), alternative(a) {}
    virtual Expression* eval(Environment* env);
    virtual std::string string() const;
  private:
    Expression* predicate;
    Expression* consequent;
    Expression* alternative;
  };

  class Sequence: public Expression {
  public:
    Sequence(Expressions* exprs): expressions(exprs) {};
    virtual Expression* eval(Environment* env);
    virtual std::string string() const;
  private:
    Expressions* expressions;
  };

  class Define: public Expression {
  public:
    Define(Variable* var, Expression* expr): variable(var), value(expr) {}
    virtual Expression* eval(Environment* env);
    virtual std::string string() const;
  private:
    Variable* variable;
    Expression* value;
  };

  class Lambda: public Expression {
  public:
    Lambda(Expressions* exprs, Expression* b): parameters(exprs), body(b) {}
    virtual Expression* eval(Environment* env);
    virtual std::string string() const;
  private:
    Expressions* parameters;
    Expression* body;
  };

  class Procedure: public Expression {
  public:
    Procedure(Expressions* params, Expression* expr, Environment* env)
      : parameters(params), body(expr), environment(env) {}
    virtual Expression* eval(Environment* env);
    virtual Expression* apply(Expressions* arguments);
    virtual std::string string() const;
  protected:
    Expressions* parameters;
    Expression* body;
    Environment* environment;
  };

  class Operation: public Expression {
  public:
    Operation(Expression* opr, Expressions* opd)
      : op(opr), operands(opd) {}
    virtual Expression* eval(Environment* env);
    virtual std::string string() const;
  protected:
    Expression* op;
    Expressions* operands;
  };

  class PrimitiveProcedure: public Procedure {
  public:
    PrimitiveProcedure(const std::string& str, boost::function<int (int, int)> f)
      : Procedure(0, 0, 0), op(str), applyFunction(f) {}
    virtual Expression* apply(Expressions* arguments);
    virtual std::string string() const;
  private:
    const std::string op;
    boost::function<int (int, int)> applyFunction;
  };

  using namespace boost::lambda;
  PrimitiveProcedure* Plus = new PrimitiveProcedure("+", _1 + _2);
  PrimitiveProcedure* Minus = new PrimitiveProcedure("-", _1 - _2);
  PrimitiveProcedure* Multiplies = new PrimitiveProcedure("*", _1 * _2);
  PrimitiveProcedure* Equals = new PrimitiveProcedure("=", _1 == _2);

}

#endif // SCHEME_H_INCLUDED

scheme.cpp

#include <scheme.h>
#include <boost/lexical_cast.hpp>

namespace scheme {
  using namespace std;

  // Environment
  Expression* Environment::variableValue(Variable* var) {
    if(Expression* result = table[var->name()])
      return result;
    if(base)
      return base->variableValue(var);
    throw "Unbound variable";
  }

  void Environment::defineVariable(Variable* var, Expression* value) {
    table[var->name()] = value;
  }

  Environment* Environment::extend(Expressions* vars, Expressions* vals) {
    if(vars->size() != vals->size())
      throw "Invalid arguments";
    Environment* child = new Environment(this);
    for (size_t i = 0; i < vars->size(); i++)
      child->defineVariable(dynamic_cast<Variable*>((*vars)[i]), (*vals)[i]);
    return child;
  }

  Environment* createGlobalEnvironment() {
    Environment* env = new Environment();
    env->defineVariable(new Variable("+"), Plus);
    env->defineVariable(new Variable("-"), Minus);
    env->defineVariable(new Variable("*"), Multiplies);
    env->defineVariable(new Variable("="), Equals);
    return env;
  }


  // Expressions
  Expressions* evalAll(Expressions const* exprs, Environment* env) {
    Expressions* evaled = new Expressions();
    Expressions::const_iterator from(exprs->begin()), end(exprs->end());
    while (from != end)
      evaled->push_back((*from++)->eval(env));
    return evaled;
  }
  string toString(Expressions* exprs) {
    string str;
    Expressions::const_iterator iter(exprs->begin()), end(exprs->end());
    while (iter != end) {
      str += (*iter++)->string();
      if(iter != end)
        str += " ";
    }
    return str;
  }


  // Expression
  Expression* Number::eval(Environment* env) {
    return this;
  }
  string Number::string() const {
    return boost::lexical_cast<std::string>(num);
  }
  bool Number::boolValue() const {
    return num;
  }
  int Number::intValue() const {
    return num;
  }


  Expression* String::eval(Environment* env) {
    return this;
  }
  string String::string() const {
    return str;
  }


  Expression* Variable::eval(Environment* env) {
    return env->variableValue(this);
  }
  string Variable::string() const {
    return name_;
  }
  const std::string Variable::name() const {
    return name_;
  }


  Expression* If::eval(Environment* env) {
    return predicate->eval(env)->boolValue() ? consequent->eval(env) : alternative->eval(env);
  }
  string If::string() const {
    return "(if " + predicate->string() + " " + consequent->string() + " " + alternative->string() + ")";
  }


  Expression* Sequence::eval(Environment* env) {
    Expressions::const_iterator iter(expressions->begin()), end(expressions->end());
    while (iter != end) {
      Expression* e = (*iter++)->eval(env);
      if(iter == end) return e;
    }
    throw "empty sequence";
  }
  string Sequence::string() const {
    return "(begin " + toString(expressions) + ")";
  }


  Expression* Procedure::eval(Environment* env) {
    return this;
  }
  Expression* Procedure::apply(Expressions* arguments) {
    return body->eval(environment->extend(parameters, arguments));
  }
  string Procedure::string() const {
    return "<#proc (lambda (" + toString(parameters) + ") " + body->string() + ")>";
  }

  Expression* PrimitiveProcedure::apply(Expressions* arguments) {
    Expressions::const_iterator begin(arguments->begin());
    int first = dynamic_cast<Number*>(*(arguments->begin()))->intValue();
    int second = dynamic_cast<Number*>(*(++(arguments->begin())))->intValue();
    return new Number(applyFunction(first, second));
  }
  string PrimitiveProcedure::string() const {
    return "<#proc (" + op + " x y)>";
  }

  Expression* Operation::eval(Environment* env) {
    return dynamic_cast<Procedure*>(op->eval(env))->apply(evalAll(operands, env));
  }
  string Operation::string() const {
    return "(" + op->string() + " " + toString(operands) + ")";
  }


  Expression* Lambda::eval(Environment* env) {
    return new Procedure(parameters, body, env);
  }
  string Lambda::string() const {
    return "(lambda (" + toString(parameters) + ") " + body->string() + ")";
  }

  Expression* Define::eval(Environment* env) {
    env->defineVariable(variable, value->eval(env));
    return new String("ok");
  }
  string Define::string() const {
    return "(define " + variable->string() + " " + value->string() + ")";
  }

}

parser

#include <scheme.h>
#include <stack>
#include <boost/spirit/core.hpp>

namespace scheme {
  using namespace std;
  using namespace boost::spirit;

  stack<Expression*> expressions;
  stack<Expressions*> sequences;

  // stack operations
  void clear() {
    expressions = stack<Expression*>();
    sequences = stack<Expressions*>();
  }
  void push(Expression* exp) {
    expressions.push(exp);
  }
  Expression* pop() {
    Expression* expr = expressions.top();
    expressions.pop();
    return expr;
  }
  void pushToSequence(Expression* exp) {
    sequences.top()->push_back(exp);
  }
  void pushEmptySequence() {
    sequences.push(new Expressions());
  }
  Expressions* popSequence() {
    Expressions* params = sequences.top();
    sequences.pop();
    return params;
  }

  // callbacks
  void pushNumber(int n) {
    push(new Number(n));
  }
  void pushSymbol(char const* first, char const* last) {
    push(new Variable(string(first, last)));
  }
  void pushBegin(char const* first, char const* last) {
    push(new Sequence(popSequence()));
  }
  void pushCond(char const* first, char const* last) {
    Expression* alternative = pop();
    Expression* consequent = pop();
    Expression* predicate = pop();
    push(new If(predicate, consequent, alternative));
  }
  void pushEmptySequence_(char const* first, char const* last) {
    pushEmptySequence();
  }
  void moveToSequence(char const* first, char const* last) {
    pushToSequence(pop());
  }
  void pushLambda(char const* first, char const* last) {
    push(new Lambda(popSequence(), pop()));
  }
  void pushDefine(char const* first, char const* last) {
    Expression* value = pop();
    Variable* variable = dynamic_cast<Variable*>(pop());
    push(new Define(variable, value));
  }
  void pushDefineLambda(char const* first, char const* last) {
    Expression* body = pop();
    Variable* variable = dynamic_cast<Variable*>(pop());
    push(new Define(variable, new Lambda(popSequence(), body)));
  }
  void pushCall(char const* first, char const* last) {
    push(new Operation(pop(), popSequence()));
  }


  struct SchemeParser: public grammar<SchemeParser> {
    template<typename S> struct definition {
      rule<S> s, num, symbol;
      rule<S> symbol_sequence, sequence;
      rule<S> begin, cond, lambda, define, define_lambda;
      rule<S> call, expr;

      definition(const SchemeParser& self) {
        s = +space_p;
        num = int_p[&pushNumber];
        symbol = (+(graph_p - '(' - ')' - digit_p))[&pushSymbol];

        symbol_sequence = epsilon_p[&pushEmptySequence_] >>
          !(symbol[&moveToSequence] >> *(s >> symbol[&moveToSequence]));
        sequence = epsilon_p[&pushEmptySequence_] >>
          !(expr[&moveToSequence] >> *(s >> expr[&moveToSequence]));

        begin = "(begin" >> s >> sequence >> ')';
        cond = "(if" >> s >> expr >> s >> expr >> s >> expr >> ')';

        lambda = "(lambda" >> s >> '(' >> symbol_sequence >> ')' >> s >> expr >> ')';

        define = "(define" >> s >> symbol >> s >> expr >> ')';
        define_lambda = "(define" >> s >> '(' >> symbol >> s >> symbol_sequence >> ')' >> s >> expr >> ')';

        call = '(' >> expr[&pushEmptySequence_] >> *(s >> expr[&moveToSequence]) >> ')';

        expr =
          num | symbol |
          begin[&pushBegin] | cond[&pushCond] | lambda[&pushLambda] |
          define[&pushDefine] | define_lambda[&pushDefineLambda] |
          call[&pushCall];
      }

      const rule<S>& start() const { return expr; }
    };
  };


  Expression* parse(const string& str) {
    clear();
    SchemeParser scmp;
    return parse(str.c_str(), scmp).full ? pop() : 0;
  }
}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy