From d740efd1dce991eddb2ed007faa2a2bd6c058db8 Mon Sep 17 00:00:00 2001 From: flaming0 Date: Sat, 1 Sep 2012 14:22:01 +0400 Subject: [PATCH] ch4 --- ch4/interpreter-cpp/schint/environment.cpp | 35 +++++++ ch4/interpreter-cpp/schint/environment.h | 26 +++++- ch4/interpreter-cpp/schint/eval.cpp | 13 --- ch4/interpreter-cpp/schint/eval.h | 26 ------ ch4/interpreter-cpp/schint/expression.cpp | 103 ++++++++++++++++----- ch4/interpreter-cpp/schint/expression.h | 86 +++++++++-------- ch4/interpreter-cpp/schint/main.cpp | 11 +-- ch4/interpreter-cpp/schint/schemelist.cpp | 10 +- ch4/interpreter-cpp/schint/schemelist.h | 3 +- ch4/interpreter-cpp/schint/schint.pro | 5 +- ch4/interpreter-cpp/schint/utils.h | 72 ++++++++++++++ 11 files changed, 270 insertions(+), 120 deletions(-) delete mode 100644 ch4/interpreter-cpp/schint/eval.cpp delete mode 100644 ch4/interpreter-cpp/schint/eval.h create mode 100644 ch4/interpreter-cpp/schint/utils.h diff --git a/ch4/interpreter-cpp/schint/environment.cpp b/ch4/interpreter-cpp/schint/environment.cpp index 6eae020..9070901 100644 --- a/ch4/interpreter-cpp/schint/environment.cpp +++ b/ch4/interpreter-cpp/schint/environment.cpp @@ -7,11 +7,46 @@ #include "environment.h" +#include "expression.h" + Environment::Environment(Environment *baseEnv) : m_baseEnvironment(baseEnv) { } +shared_ptr Environment::lookupVariableValue(const Var var) const +{ + if (m_frame.find(var) == m_frame.end()) + { + if (m_baseEnvironment) + return m_baseEnvironment->lookupVariableValue(var); + } + else + return m_frame.find(var)->second; + + return nullexpr; +} + +void Environment::addBindingForFrame(const Var var, const Val val) +{ + m_frame[var] = val; +} + +Environment *Environment::extendEnvironment(std::list vars, std::list vals) +{ + if (vars.size() != vals.size()) + throw std::runtime_error("Sizes doesn't match."); + + Environment *newEnv = new Environment(this); + + auto var = vars.begin(); + auto val = vals.begin(); + for ( ; var != vars.end(); var++, val++) + newEnv->addBindingForFrame(*var, *val); + + return newEnv; +} + Environment *globalEnvironment() { static Environment globalEnv(nullptr); diff --git a/ch4/interpreter-cpp/schint/environment.h b/ch4/interpreter-cpp/schint/environment.h index 5076ed4..2a0c3e2 100644 --- a/ch4/interpreter-cpp/schint/environment.h +++ b/ch4/interpreter-cpp/schint/environment.h @@ -8,19 +8,37 @@ #ifndef ENVIRONMENT_H #define ENVIRONMENT_H -#include -#include +#include "utils.h" +#include "expression.h" -class Evaluable; +// WHY std::less doesn't work????? +struct compare +{ + bool operator() (const shared_ptr &a, const shared_ptr &b) const + { + return *a < *b; + } +}; class Environment { Environment *m_baseEnvironment; - std::map m_frame; + typedef shared_ptr Var; + typedef shared_ptr Val; + + std::map m_frame; public: Environment(Environment *baseEnv); + + shared_ptr lookupVariableValue(const Var var) const; + void addBindingForFrame(const Var var, const Val val); + + Environment *extendEnvironment(std::list vars, std::list vals); + +private: +// static boost::function }; Environment *globalEnvironment(); diff --git a/ch4/interpreter-cpp/schint/eval.cpp b/ch4/interpreter-cpp/schint/eval.cpp deleted file mode 100644 index 7385c7f..0000000 --- a/ch4/interpreter-cpp/schint/eval.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* - * eval.cpp - * - * Author: flamingo - * E-mail: epiforce57@gmail.com - */ - -#include "eval.h" - -Evaluable *eval(Evaluable *exp, Environment *env) -{ - return exp->eval(env); -} diff --git a/ch4/interpreter-cpp/schint/eval.h b/ch4/interpreter-cpp/schint/eval.h deleted file mode 100644 index e6aea7b..0000000 --- a/ch4/interpreter-cpp/schint/eval.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * eval.h - * - * Author: flamingo - * E-mail: epiforce57@gmail.com - */ - -#ifndef EVAL_H -#define EVAL_H - -#include - -class Environment; - -class Evaluable -{ -public: - Evaluable() { } - virtual ~Evaluable() { } - - virtual Evaluable *eval(Environment *env) = 0; -}; - -Evaluable *eval(Evaluable *exp, Environment *env); - -#endif // EVAL_H diff --git a/ch4/interpreter-cpp/schint/expression.cpp b/ch4/interpreter-cpp/schint/expression.cpp index 59bfdf5..a74d730 100644 --- a/ch4/interpreter-cpp/schint/expression.cpp +++ b/ch4/interpreter-cpp/schint/expression.cpp @@ -6,46 +6,94 @@ */ #include "expression.h" + #include "schemelist.h" +#include "environment.h" -#include +/* +;; lambdas +(define (lambda? exp) (tagged-list? exp 'lambda)) +(define (lambda-parameters exp) (cadr exp)) +(define (lambda-body exp) (cddr exp)) +(define (make-lambda parameters body) + (cons 'lambda (cons parameters body))) + */ -Expression::Expression() -{ -} +/* +(define (analyze-lambda exp) + (let ((vars (lambda-parameters exp)) + (bproc (analyze-sequence (lambda-body exp)))) + (lambda (env) (make-procedure vars bproc env)))) + +(define (analyze-sequence exps) + (define (sequentially proc1 proc2) + (lambda (env) (proc1 env) (proc2 env))) + (define (loop first-proc rest-procs) + (if (null? rest-procs) + first-proc ;; only one combination + (loop (sequentially first-proc (car rest-procs)) ;; otherwise, loop through combinations + (cdr rest-procs)))) + (let ((procs (map analyze exps))) + (if (null? procs) + (error "Empty sequence -- ANALYZE")) + (loop (car procs) (cdr procs)))) + */ -//Expression::ExpressionType Expression::typeBySExpression(const std::string &sexpr) -//{ -// std::string tag = sexpr.substr(1, sexpr.find(' ') - 1); +/* +(define (make-procedure parameters body env) + (list 'procedure parameters body env)) +(define (compound-procedure? p) + (tagged-list? p 'procedure)) +(define (procedure-parameters p) (cadr p)) +(define (procedure-body p) (caddr p)) +(define (procedure-environment p) (cadddr p)) +*/ -// throw std::runtime_error(std::string("Unknown expression type ") + tag + " ."); -//} +shared_ptr analyzeDefinition(const SchemeList &str) +{ + SchemeList defVarStr = str.car(); -Expression *Expression::analyzeExpression(const std::string &str) + return make_shared(make_shared(defVarStr), + Expression::analyzeExpression(str.cdr())); +} + +Expression::Expression() +{ +} + +shared_ptr Expression::analyzeExpression(const std::string &str) { SchemeList lst(str); - std::string tag = lst.car(); + SchemeList tag = lst.car(); if (tag == "\'") - return nullptr; + return nullexpr; if (tag == "set!") - return nullptr; + return nullexpr; if (tag == "define") - return new DefinitionExpression(0 /* analyze (rest) */, 0); + return analyzeDefinition(lst.cdr()); if (tag == "if") - return nullptr; + return nullexpr; if (tag == "lambda") - return nullptr; + return nullexpr; if (tag == "begin") - return nullptr; + return nullexpr; + if (isDouble(tag)) + return make_shared >(toDouble(tag)); + if (isInt(tag)) + return make_shared >(toInt(tag)); + if (isLispString(tag)) + return nullexpr; + +// std::isxdigit // if (tag == number); // if (tag == symbol); // if (tag == pair); - throw std::runtime_error(std::string("Unknown expression type ") + tag + " ."); +// throw std::runtime_error(std::string("Unknown expression type ") + tag + " ."); // ExpressionType exprType = typeBySExpression(expr); // new DefinitionExpr(cadr(expr), createExpression(caddr(expr))); @@ -63,7 +111,7 @@ Expression *Expression::analyzeExpression(const std::string &str) // if (exprType == Begin) // return new BeginExpression(""); -// return nullptr; + return nullexpr; } Expression *Expression::car() const @@ -74,19 +122,23 @@ Expression *Expression::cdr() const { } -/* -VariableExpression::VariableExpression(const std::string &value) + +VariableExpression::VariableExpression(const std::string &varSymbol) + : m_symbol(varSymbol) { } -Expression *VariableExpression::eval(Environment *env) +shared_ptr VariableExpression::eval(Environment *env) { +// auto var = make_shared(this); +// return env->lookupVariableValue(var); +// env->lookupVariableValue } std::string VariableExpression::toString() const { } - +/* QuotedExpression::QuotedExpression(const std::string &value) { } @@ -111,11 +163,12 @@ std::string AssignmentExpression::toString() const { }*/ -DefinitionExpression::DefinitionExpression(Expression *variable, Expression *value) +DefinitionExpression::DefinitionExpression(shared_ptr variable, shared_ptr value) + : m_var(variable), m_value(value) { } -Expression *DefinitionExpression::eval(Environment *env) +shared_ptr DefinitionExpression::eval(Environment *env) { } diff --git a/ch4/interpreter-cpp/schint/expression.h b/ch4/interpreter-cpp/schint/expression.h index 87e5cfc..323d695 100644 --- a/ch4/interpreter-cpp/schint/expression.h +++ b/ch4/interpreter-cpp/schint/expression.h @@ -8,59 +8,66 @@ #ifndef EXPRESSION_H #define EXPRESSION_H -#include "eval.h" +#include "utils.h" -class Expression : public Evaluable +class Environment; + +class Expression { protected: Expression(); public: + virtual ~Expression() { } // maybe analyze - static Expression *analyzeExpression(const std::string &str); + static shared_ptr analyzeExpression(const std::string &str); + virtual shared_ptr eval(Environment *env) = 0; virtual std::string toString() const = 0; Expression *car() const; Expression *cdr() const; }; -///** -// * Number. -// */ -//template -//class NumberExpression : public Expression -//{ -// T m_value; -//public: -// NumberExpression(T value) -// { -// m_value = value; -// } - -// virtual std::string toString() const -// { -// return std::to_string(m_value); -// } - -// Evaluable *eval(Environment *env) -// { -// return nullptr; -// } -//}; +/** + * Number. + */ +template +class NumberExpression : public Expression +{ + T m_value; +public: + NumberExpression(T value) + { + m_value = value; + } + + virtual std::string toString() const + { + return std::to_string(m_value); + } + + shared_ptr eval(Environment *env) + { + return nullexpr; + } +}; -///** -// * Variable. -// */ -//class VariableExpression : public Expression -//{ -//public: -// VariableExpression(const std::string &value); +/** + * Variable. + */ +class VariableExpression : public Expression +{ + std::string m_symbol; +public: + VariableExpression(const std::string &varSymbol); -// virtual Expression *eval(Environment *env); + virtual shared_ptr eval(Environment *env); -// virtual std::string toString() const; -//}; + virtual std::string toString() const; + + bool operator< (const VariableExpression &other) const { return m_symbol < other.m_symbol; } +}; ///** // * Quotation. @@ -93,10 +100,13 @@ class Expression : public Evaluable */ class DefinitionExpression : public Expression { + shared_ptr m_var; + shared_ptr m_value; + public: - DefinitionExpression(Expression *variable, Expression *value); + DefinitionExpression(shared_ptr variable, shared_ptr value); - virtual Expression *eval(Environment *env); + virtual shared_ptr eval(Environment *env); virtual std::string toString() const; }; diff --git a/ch4/interpreter-cpp/schint/main.cpp b/ch4/interpreter-cpp/schint/main.cpp index fcf0444..9ac2210 100644 --- a/ch4/interpreter-cpp/schint/main.cpp +++ b/ch4/interpreter-cpp/schint/main.cpp @@ -1,7 +1,4 @@ -#include -#include -#include - +#include "utils.h" #include "expression.h" #include "environment.h" @@ -22,7 +19,7 @@ int main() try bool exit = false; std::string input; - Expression *exp; + shared_ptr exp; while (!exit) { @@ -32,11 +29,11 @@ int main() try // Expression *output = static_cast(eval(exp, globalEnvironment())); // promtOutput(output); - delete exp; +// delete exp; // delete output; } - delete exp; +// delete exp; return 0; } diff --git a/ch4/interpreter-cpp/schint/schemelist.cpp b/ch4/interpreter-cpp/schint/schemelist.cpp index 1f0bea8..e983ae9 100644 --- a/ch4/interpreter-cpp/schint/schemelist.cpp +++ b/ch4/interpreter-cpp/schint/schemelist.cpp @@ -6,7 +6,6 @@ */ #include "schemelist.h" -#include void SchemeList::eraseWhiteSpaces() { @@ -34,7 +33,7 @@ SchemeList::SchemeList(const std::string &expr) { eraseWhiteSpaces(); - if (m_listString.empty() || m_listString[0] != '(' || m_listString[m_listString.size() - 1] != ')') + if (m_listString.empty()/* || m_listString[0] != '(' || m_listString[m_listString.size() - 1] != ')'*/) throw std::runtime_error("Bad expression."); } @@ -43,7 +42,12 @@ SchemeList SchemeList::car() const if (m_listString == "()" || m_listString.at(0) != '(') throw std::runtime_error("Unable to get car."); - return SchemeList(m_listString.substr(1, m_listString.find(' ') - 1)); + if (m_listString.find(' ') != std::string::npos) + return SchemeList(m_listString.substr(1, m_listString.find(' ') - 1)); + else if (m_listString.find(')') != std::string::npos) + return SchemeList(m_listString.substr(1, m_listString.find(')') - 1)); + else + throw std::runtime_error("Unable to get car."); } SchemeList SchemeList::cdr() const diff --git a/ch4/interpreter-cpp/schint/schemelist.h b/ch4/interpreter-cpp/schint/schemelist.h index 6d374a7..b29a38b 100644 --- a/ch4/interpreter-cpp/schint/schemelist.h +++ b/ch4/interpreter-cpp/schint/schemelist.h @@ -8,7 +8,7 @@ #ifndef SCHEMELIST_H #define SCHEMELIST_H -#include +#include "utils.h" /** * Lisp list string representation. @@ -26,6 +26,7 @@ class SchemeList SchemeList cdr() const; operator std::string() { return m_listString; } + bool operator== (const std::string &str) const { return m_listString == str; } }; #endif // SCHEMELIST_H diff --git a/ch4/interpreter-cpp/schint/schint.pro b/ch4/interpreter-cpp/schint/schint.pro index 4c58a58..5657a41 100644 --- a/ch4/interpreter-cpp/schint/schint.pro +++ b/ch4/interpreter-cpp/schint/schint.pro @@ -5,14 +5,13 @@ CONFIG -= qt QMAKE_CXXFLAGS += -std=gnu++0x SOURCES += main.cpp \ - eval.cpp \ environment.cpp \ expression.cpp \ schemelist.cpp HEADERS += \ - eval.h \ environment.h \ expression.h \ - schemelist.h + schemelist.h \ + utils.h diff --git a/ch4/interpreter-cpp/schint/utils.h b/ch4/interpreter-cpp/schint/utils.h new file mode 100644 index 0000000..7d84f95 --- /dev/null +++ b/ch4/interpreter-cpp/schint/utils.h @@ -0,0 +1,72 @@ +/* + * utils.h + * + * Author: flamingo + * E-mail: epiforce57@gmail.com + */ + +#ifndef UTILS_H +#define UTILS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define nullexpr shared_ptr() + +using boost::shared_ptr; +using boost::make_shared; + +inline bool isDouble(const std::string &str) +{ + std::istringstream inpStream(str); + double inpValue = 0.0; + if (inpStream >> inpValue) + return true; + else + return false; +} + +inline double toDouble(const std::string &str) +{ + std::istringstream inpStream(str); + double inpValue = 0.0; + inpStream >> inpValue; + return inpValue; +} + +inline bool isInt(const std::string &str) +{ + std::istringstream inpStream(str); + int inpValue = 0.0; + if (inpStream >> inpValue) + return true; + else + return false; +} + +inline double toInt(const std::string &str) +{ + std::istringstream inpStream(str); + int inpValue = 0.0; + inpStream >> inpValue; + return inpValue; +} + +// Not an a list. Thus, without parentheses +inline bool isLispString(const std::string &str) +{ + return (str.find('(') == std::string::npos) && + (str.find(')') == std::string::npos); +} + +#endif // UTILS_H