From 782f182f2c2b839d03aeb4960818d825cc2e7a47 Mon Sep 17 00:00:00 2001 From: Hisashi Horikawa Date: Wed, 2 Oct 2024 22:00:06 +0900 Subject: [PATCH] for v0.6 release --- Makefile | 41 ++++++++++++++++++++++++++++++++++++++++ builtin-functions.cpp | 19 +++++++++++++++++++ eval.h | 21 ++++++++++++++++++++ main.cpp | 26 +++++++++++++++++++++++++ object_print.cpp | 14 +++++++++++--- s_expr.h | 6 +++--- test/block_test.cpp | 8 +------- test/evaluation_test.cpp | 9 +-------- test/macro_test.cpp | 13 +------------ test/tco_test.cpp | 27 +------------------------- 10 files changed, 125 insertions(+), 59 deletions(-) create mode 100644 Makefile create mode 100644 eval.h create mode 100644 main.cpp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bc0a409 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ + +.PHONY: all clean + +TARGETS = mylisp + +all: $(TARGETS) + +# コンパイラオプション: +# https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++ +# 英語版のほうが更新されている。 + +# GDB でデバグする場合, `-g` オプションよりも `-g3` のほうが便利. +# リリースビルド = -DNDEBUG +DEBUG = -g3 -D_DEBUG + +# _FORTIFY_SOURCE は副作用がありうる +CXXFLAGS = -Wall -Wextra -Wno-unused-parameter -Wno-format-extra-args \ + -O2 -Wformat -Wformat=2 -Wimplicit-fallthrough -Werror=format-security \ + $(DEBUG) \ + -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ + -D_GLIBCXX_ASSERTIONS \ + -fstrict-flex-arrays=3 \ + -fstack-clash-protection -fstack-protector-strong \ + -Wl,-z,nodlopen -Wl,-z,noexecstack \ + -Wl,-z,relro -Wl,-z,now \ + -Wl,--as-needed -Wl,--no-copy-dt-needed-entries \ + -fPIE -pie + +mylisp: main.o edit_line.o reader.o object_print.o environment.o evaluation.o macros.o builtin-functions.o + $(CXX) $^ $(LDFLAGS) $(LDLIBS) -lstdc++ -licuuc -licuio -ledit -o $@ + +reader.o: reader.cpp s_expr.h +object_print.o: object_print.cpp s_expr.h +s_expr.h: my_debug.h +environment.o: environment.cpp environment.h s_expr.h +evaluation.o: evaluation.cpp environment.h s_expr.h +builtin-functions.o: builtin-functions.cpp environment.h s_expr.h + +clean: + rm -f *.o $(TARGETS) + diff --git a/builtin-functions.cpp b/builtin-functions.cpp index 67077d8..f48fd5f 100644 --- a/builtin-functions.cpp +++ b/builtin-functions.cpp @@ -73,6 +73,20 @@ value_t do_multiply(EnvPtr args) return xv * yv; } +my::value_t do_1minus(my::EnvPtr args) { + my::value_t x = args->find_value("X"); + double v = std::get(x); + + return v - 1; +} + +// @return T or NIL +my::value_t do_gt(my::EnvPtr args) { + double x = std::get(args->find_value("X")); + double y = std::get(args->find_value("Y")); + return x > y ? trueValue : nilValue; +} + ////////////////////////////////////////////////////////////////////////// // @@ -112,12 +126,17 @@ static const BuiltinFunc funcs[] = { // {"+", "(x y)", my::do_add }, {"*", "(x y)", my::do_multiply }, + {"1-", "(x)", my::do_1minus }, + {">", "(x y)", my::do_gt }, // {"MAPCAR", "(func list)", do_mapcar }, }; void setup_functions() { + my::globalEnv->set_value("T", my::trueValue, true); + my::globalEnv->set_value("NIL", my::nilValue, true); + for (const auto& f : funcs) define_function(f.name, f.params, f.func); } diff --git a/eval.h b/eval.h new file mode 100644 index 0000000..ab39149 --- /dev/null +++ b/eval.h @@ -0,0 +1,21 @@ + +#ifndef MYLISP_EVAL_H +#define MYLISP_EVAL_H + +#include "s_expr.h" +#include "environment.h" + +namespace my { + +extern value_t EVAL1(value_t ast, EnvPtr env); +extern bool value_isTrue(const value_t& value) ; + +extern void setup_functions(); + +extern void define_macro(const icu::UnicodeString& name, + const icu::UnicodeString& params, + ListPtr body); + +} // namespace my + +#endif // !MYLISP_EVAL_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..a086e8a --- /dev/null +++ b/main.cpp @@ -0,0 +1,26 @@ + +#include "edit_line.h" +#include "environment.h" +#include "s_expr.h" +#include "eval.h" +#include +#include +using namespace icu; + +int main() +{ + my::EditLine editLine("~/my-lisp.history"); + + my::EnvPtr toplevel = std::make_shared(); + my::setup_functions(); + + UnicodeString line; + bool f; + while ( editLine.get("* ", &line) ) { + my::value_t astv = my::read_from_string(line); + my::value_t r = my::EVAL1(astv, toplevel); + PRINT(r, std::cout); std::cout << "\n"; + } + + return 0; +} diff --git a/object_print.cpp b/object_print.cpp index 93daa63..c5fdccd 100644 --- a/object_print.cpp +++ b/object_print.cpp @@ -9,7 +9,7 @@ namespace my { // TODO: 定数リストに格納 const std::shared_ptr nilValue = std::make_shared(); -const std::shared_ptr trueValue = std::make_shared("T"); +const std::shared_ptr trueValue = std::make_shared(); static void indent(std::ostream& out, int level) { @@ -26,6 +26,10 @@ void object::write_indented(std::ostream& out, int level) const { out << s; } +UnicodeString object::print() const { + return "T"; +} + //////////////////////////////////////////////////////// // class symbol @@ -138,10 +142,14 @@ void cons::write_indented(std::ostream& out, int level) const throw std::out_of_range("empty"); WriteVisitor v = WriteVisitor(out, level + 1); + PrintVisitor p = PrintVisitor(); - indent(out, level); out << "(\n"; + indent(out, level); out << "("; for (auto i = list_.begin(); i != list_.end(); ++i) { - std::visit(v, *i); + if (i == list_.begin()) + out << std::visit(p, *i); + else + std::visit(v, *i); out << '\n'; } diff --git a/s_expr.h b/s_expr.h index a0596dd..e8e78e9 100644 --- a/s_expr.h +++ b/s_expr.h @@ -35,7 +35,7 @@ No direct slots. */ class object //: public RefCounted { -protected: +public: object() { TRACE_OBJECT("Creating object %p\n", this); } @@ -55,7 +55,7 @@ class object //: public RefCounted // 数値には function =, 文字には char=, 文字列には string= 関数を使え. //bool isEqualTo(const malValue* rhs) const; public: - virtual icu::UnicodeString print() const = 0; + virtual icu::UnicodeString print() const ; virtual void write_indented(std::ostream& out, int level) const ; }; @@ -144,7 +144,7 @@ typedef std::variant< bool, int64_t, double, ObjectPtr > value_t; extern bool value_isa(const value_t& , const icu::UnicodeString& klass); extern const std::shared_ptr nilValue; -extern const std::shared_ptr trueValue; +extern const std::shared_ptr trueValue; extern value_t READ(std::istream& stream); extern value_t read_from_string(const icu::UnicodeString& str); diff --git a/test/block_test.cpp b/test/block_test.cpp index 5a798cf..eef85e4 100644 --- a/test/block_test.cpp +++ b/test/block_test.cpp @@ -3,14 +3,8 @@ #include #include #include +#include "../eval.h" -namespace my { -extern value_t EVAL1(value_t ast, EnvPtr env); -extern bool value_isTrue(const value_t& value) ; - -extern void setup_functions(); - -} // namespace my int main() { my::setup_functions(); diff --git a/test/evaluation_test.cpp b/test/evaluation_test.cpp index 7e544d7..dccbe6b 100644 --- a/test/evaluation_test.cpp +++ b/test/evaluation_test.cpp @@ -3,14 +3,7 @@ #include #include #include - -namespace my { -extern value_t EVAL1(value_t ast, EnvPtr env); -extern bool value_isTrue(const value_t& value) ; - -extern void setup_functions(); - -} // namespace my +#include "../eval.h" my::value_t func1(my::EnvPtr args) { diff --git a/test/macro_test.cpp b/test/macro_test.cpp index 08142d9..7a6b77d 100644 --- a/test/macro_test.cpp +++ b/test/macro_test.cpp @@ -2,18 +2,7 @@ // マクロのテスト #include "../environment.h" #include - -namespace my { - -extern value_t EVAL1(value_t ast, EnvPtr env); - -extern void define_macro(const icu::UnicodeString& name, - const icu::UnicodeString& params, - ListPtr body); - -extern void setup_functions(); - -} // namespace my +#include "../eval.h" // quasiquote の呼び出し diff --git a/test/tco_test.cpp b/test/tco_test.cpp index 55761ea..10256c6 100644 --- a/test/tco_test.cpp +++ b/test/tco_test.cpp @@ -3,28 +3,7 @@ #include #include #include - -namespace my { -extern value_t EVAL1(value_t ast, EnvPtr env); -extern bool value_isTrue(const value_t& value) ; - -extern void setup_functions(); - -my::value_t do_1minus(my::EnvPtr args) { - my::value_t x = args->find_value("X"); - double v = std::get(x); - - return v - 1; -} - -// @return T or NIL -my::value_t do_gt(my::EnvPtr args) { - double x = std::get(args->find_value("X")); - double y = std::get(args->find_value("Y")); - return x > y ? trueValue : nilValue; -} - -} // namespace my +#include "../eval.h" int main() @@ -32,10 +11,6 @@ int main() my::EnvPtr env = std::make_shared(); my::setup_functions(); - my::define_function("1-", "(x)", my::do_1minus); - my::define_function(">", "(x y)", my::do_gt); - my::globalEnv->set_value("T", my::trueValue, true); - my::globalEnv->set_value("NIL", my::nilValue, true); // 偶数 = true icu::UnicodeString ast = "(defun iseven (n) (if (> n 0) (isodd (1- n)) t))";