shared_ptr<Expr> のラッパークラス ExprRef を作成しました。ChatGPT の提案では Ref<T> でしたが、これはこのままでは使えないので書き直しました。Expr の外部からは ExprRef を使うことができます。これを shared_ptr<Expr> を使わない形に書き直すこともできます。X68000 用としてはその方が良いかもしれないので、今後それもやっていきます。
#include <iostream> #include <sstream> #include <string> #include <map> #include <memory> #include <cctype> #include <vector> #include <stdexcept> #include <optional> using namespace std; class Expr; class ExprRef; using ExprPtr = shared_ptr<Expr>; using Exprs = vector<ExprRef>; using Env = map<string, ExprRef>; // ポインターのラッパークラス class ExprRef { ExprPtr ptr; public: ExprRef() {} ExprRef(ExprPtr p) : ptr(std::move(p)) {} ExprRef(Expr* raw) : ptr(raw) {} ExprRef(double number); ExprRef(string name); ExprRef(char op, ExprRef expr); ExprRef(char op, ExprRef left, ExprRef right); operator ExprPtr() { return ptr; } double eval(const Env& env) const; string to_string(int& pos) const; void collect_subexpressions(Exprs& out); ExprRef evaluate_once(Env& env); ExprRef replace_subexpression( int index_to_replace, const ExprRef& new_subexpr, int& current_index); ExprRef replace_subexpression( int index_to_replace, const ExprRef& new_subexpr); }; // 式の型定義 class Expr : public enable_shared_from_this<Expr> { public: virtual ~Expr() = default; virtual double eval(const Env& env) const = 0; virtual string to_string(int& pos) const = 0; string pos_string(int& pos) const { return "#" + std::to_string(pos++); } virtual void collect_subexpressions(Exprs& out) = 0; virtual ExprRef evaluate_once(Env& env) = 0; virtual ExprRef replace_subexpression( int index_to_replace, const ExprRef& new_subexpr, int& current_index) = 0; }; class Number : public Expr { double value; public: Number(double v) : value(v) {} double eval(const Env& env) const override { return value; } string to_string(int& pos) const override { std::ostringstream oss; oss << value; return oss.str() + pos_string(pos); } // 番号付きの部分式取得 void collect_subexpressions(Exprs& out) override { out.push_back(shared_from_this()); } // 部分式評価(定数なら簡約、変数なら展開) ExprRef evaluate_once(Env& env) override { return shared_from_this(); } ExprRef replace_subexpression( int index_to_replace, const ExprRef& new_subexpr, int& current_index) override { if (current_index == index_to_replace) { current_index++; return new_subexpr; } int this_index = current_index; current_index++; // Number や Variable は子を持たないのでそのまま返す return shared_from_this(); } }; class Variable : public Expr { string name; public: Variable(string n) : name(std::move(n)) {} double eval(const Env& env) const override { if (env.count(name)) return env.at(name).eval(env); throw runtime_error("Undefined variable: " + name); } string to_string(int& pos) const override { return name + pos_string(pos); } // 番号付きの部分式取得 void collect_subexpressions(Exprs& out) override { out.push_back(shared_from_this()); } // 部分式評価(定数なら簡約、変数なら展開) ExprRef evaluate_once(Env& env) override { if (env.count(name)) return env[name]; return shared_from_this(); } ExprRef replace_subexpression( int index_to_replace, const ExprRef& new_subexpr, int& current_index) override { if (current_index == index_to_replace) { current_index++; return new_subexpr; } int this_index = current_index; current_index++; // Number や Variable は子を持たないのでそのまま返す return shared_from_this(); } }; class UnaryOp : public Expr { char op; ExprRef expr; public: UnaryOp(char o, ExprRef e) : op(o), expr(e) {} double eval(const Env& env) const override { double a = expr.eval(env); switch (op) { case '-': return -a; } throw runtime_error("Unknown operator"); } string to_string(int& pos) const override { string pos_str = pos_string(pos); return "(" + string(1, op) + expr.to_string(pos) + ")" + pos_str; } // 番号付きの部分式取得 void collect_subexpressions(Exprs& out) override { out.push_back(shared_from_this()); expr.collect_subexpressions(out); } // 部分式評価(定数なら簡約、変数なら展開) ExprRef evaluate_once(Env& env) override { auto sub = expr.evaluate_once(env); if (auto subnum = dynamic_pointer_cast<Number>(ExprPtr(sub))) { double result = UnaryOp(op, ExprRef(subnum)).eval(env); return result; } return shared_from_this(); } ExprRef replace_subexpression( int index_to_replace, const ExprRef& new_subexpr, int& current_index) override { if (current_index == index_to_replace) { current_index++; return new_subexpr; } int this_index = current_index; current_index++; auto new_expr = expr.replace_subexpression(index_to_replace, new_subexpr, current_index); return ExprRef(op, new_expr); } }; class BinaryOp : public Expr { char op; ExprRef lhs, rhs; public: BinaryOp(char o, ExprRef l, ExprRef r) : op(o), lhs(l), rhs(r) {} double eval(const Env& env) const override { double a = lhs.eval(env), b = rhs.eval(env); switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } throw runtime_error("Unknown operator"); } string to_string(int& pos) const override { string pos_str = pos_string(pos); string left_str = lhs.to_string(pos); string right_str = rhs.to_string(pos); return "(" + left_str + " " + op + " " + right_str + ")" + pos_str; } // 番号付きの部分式取得 void collect_subexpressions(Exprs& out) override { out.push_back(shared_from_this()); lhs.collect_subexpressions(out); rhs.collect_subexpressions(out); } // 部分式評価(定数なら簡約、変数なら展開) ExprRef evaluate_once(Env& env) override { auto left = lhs.evaluate_once(env); auto right = rhs.evaluate_once(env); auto lnum = dynamic_pointer_cast<Number>(ExprPtr(left)); auto rnum = dynamic_pointer_cast<Number>(ExprPtr(right)); if (lnum && rnum) { double result = BinaryOp(op, left, right).eval(env); return result; } return shared_from_this(); } ExprRef replace_subexpression( int index_to_replace, const ExprRef& new_subexpr, int& current_index) override { if (current_index == index_to_replace) { current_index++; return new_subexpr; } int this_index = current_index; current_index++; auto new_lhs = lhs.replace_subexpression(index_to_replace, new_subexpr, current_index); auto new_rhs = rhs.replace_subexpression(index_to_replace, new_subexpr, current_index); return ExprRef(op, new_lhs, new_rhs); } }; // ポインターのラッパークラスの実装 ExprRef::ExprRef(double number) { ptr = make_shared<Number>(number); } ExprRef::ExprRef(string name) { ptr = make_shared<Variable>(name); } ExprRef::ExprRef(char op, ExprRef expr) { ptr = make_shared<UnaryOp>(op, expr.ptr); } ExprRef::ExprRef(char op, ExprRef left, ExprRef right) { ptr = make_shared<BinaryOp>(op, left.ptr, right.ptr); } double ExprRef::eval(const Env& env) const { return ptr->eval(env); } string ExprRef::to_string(int& pos) const { return ptr->to_string(pos); } void ExprRef::collect_subexpressions(Exprs& out) { return ptr->collect_subexpressions(out); } ExprRef ExprRef::evaluate_once(Env& env) { return ptr->evaluate_once(env); } ExprRef ExprRef::replace_subexpression( int index_to_replace, const ExprRef& new_subexpr, int& current_index) { return ptr->replace_subexpression(index_to_replace, new_subexpr, current_index); } ExprRef ExprRef::replace_subexpression( int index_to_replace, const ExprRef& new_subexpr) { int current_index = 0; return replace_subexpression(index_to_replace, new_subexpr, current_index); } // トークンの型 enum TokenType { NUMBER, IDENT, OP, LPAREN, RPAREN, END, INVALID, HASH, EQUAL, SEMICOLON, KEYWORD }; struct Token { TokenType type; string text; }; // 字句解析器 class Tokenizer { stringstream ss; char curr; public: explicit Tokenizer(const string& input) : ss(input) { next(); } void next() { curr = ss.get(); } Token getToken() { while (isspace(curr)) next(); if (isdigit(curr)) { string num; while (isdigit(curr) || curr == '.') { num += curr; next(); } return { NUMBER, num }; } if (isalpha(curr)) { string ident; while (isalnum(curr)) { ident += curr; next(); } if (ident == "var" || ident == "print" || ident == "eval" || ident == "exit") return { KEYWORD, ident }; return { IDENT, ident }; } if (curr == '+' || curr == '-' || curr == '*' || curr == '/') { char c = curr; next(); return { OP, string(1, c) }; } if (curr == '(') { next(); return { LPAREN, "(" }; } if (curr == ')') { next(); return { RPAREN, ")" }; } if (curr == '=') { next(); return { EQUAL, "=" }; } if (curr == '#') { next(); string num; while (isdigit(curr)) { num += curr; next(); } return { HASH, num }; } if (curr == ';') { next(); return { SEMICOLON, ";" }; } if (curr == EOF) return { END, "" }; next(); return { INVALID, string(1, curr) }; } }; // 再帰下降構文解析器 class Parser { Tokenizer tokenizer; Token curr; void eat(TokenType type) { if (curr.type != type) throw runtime_error("Unexpected token: " + curr.text); curr = tokenizer.getToken(); } ExprRef parsePrimary() { if (curr.type == NUMBER) { double val = stod(curr.text); eat(NUMBER); return val; } if (curr.type == IDENT) { string name = curr.text; eat(IDENT); return name; } if (curr.type == OP && curr.text == "-") { char op = curr.text[0]; eat(OP); return ExprRef(op, parsePrimary()); } if (curr.type == LPAREN) { eat(LPAREN); auto expr = parseExpr(); eat(RPAREN); return expr; } throw runtime_error("Invalid primary expression"); } ExprRef parseTerm() { auto left = parsePrimary(); while (curr.type == OP && (curr.text == "*" || curr.text == "/")) { char op = curr.text[0]; eat(OP); auto right = parsePrimary(); left = ExprRef(op, left, right); } return left; } ExprRef parseExpr() { auto left = parseTerm(); while (curr.type == OP && (curr.text == "+" || curr.text == "-")) { char op = curr.text[0]; eat(OP); auto right = parseTerm(); left = ExprRef(op, left, right); } return left; } public: explicit Parser(const string& input) : tokenizer(input) { curr = tokenizer.getToken(); } ExprRef parseExpression() { return parseExpr(); } optional<string> parseCommand(Env& env) { if (curr.type == KEYWORD) { string cmd = curr.text; eat(KEYWORD); if (cmd == "print" || cmd == "eval") { string varname = "_"; int index = 0; if (curr.type == IDENT) { varname = curr.text; eat(IDENT); } if (curr.type == HASH) { index = stoi(curr.text); eat(HASH); } if (curr.type != END && curr.type != SEMICOLON) { throw runtime_error("Expected command"); } if (!env.count(varname)) throw runtime_error("Undefined variable: " + varname); auto root = env[varname]; Exprs subs; root.collect_subexpressions(subs); if (index >= 0 && index < subs.size()) { if (cmd == "print") { int pos = index; return subs[index].to_string(pos); } else { auto evaluated = subs[index].evaluate_once(env); env[varname] = env[varname].replace_subexpression(index, evaluated); int pos = 0; return env[varname].to_string(pos); } } else { throw runtime_error("Invalid subexpression index"); } } if (cmd == "var") { string varname = "_"; if (curr.type == IDENT) { varname = curr.text; eat(IDENT); } if (curr.type == EQUAL) eat(EQUAL); auto expr = parseExpression(); if (curr.type != END && curr.type != SEMICOLON) { throw runtime_error("Expected command"); } env[varname] = expr; return "Defined"; } if (cmd == "exit") { return nullopt; } throw runtime_error("Unknown command: " + cmd); } throw runtime_error("Expected command"); } }; // メインループ int main() { Env variables; string line; cout << "sub-eval-print> "; while (getline(cin, line)) { try { Parser parser(line); optional<string> result = parser.parseCommand(variables); if (!result) { break; } cout << *result << endl; } catch (exception& e) { cerr << "Error: " << e.what() << endl; } cout << "sub-eval-print> "; } return 0; }

