命令行計算器

  在命令行下操作時,有時需要做一些計算。這時再打開圖形界面的計算器比較麻煩,而Linux下的bc只能做一些簡單的計算。使用C++實現命令行下計算器。

一、程序功能

  • 執行+,-,*,/,%(取兩個整數相除的餘數),^(乘方)運算
  • 程序可以執行的函數有
    sincostancotseccscexpasinacosatanlnloglog2log10sqrt(開二次方)abs(取絕對值)cbrt(開三次方)floorfixceilroundsum(求和)aver(求平均)min(取最小值)max(取最大值)rem(取兩個整數相除的商)
  • 程序默認使用弧度制,要使用角度制,執行angle=1;取消角度制,執行angle=0
  • 定義的常數有: pi, e
  • 使用方式
    直接命令行下執行calc expression,或者輸入calc進入程序後計算
  • 退出程序執行exitq

二、運行效果

在這裏插入圖片描述

三、程序代碼

  • main.cpp
#include "calculator.h"
#include <iostream>
#include <string>

bool set(slj::Calculator& calc, const std::string& str)
{
    if (str == "angle=0") {
        calc.set_angle(true);
        return true;
    }
    if (str == "angle=1") {
        calc.set_angle(false);
        return true;
    }
    return false;
}

int main(int argc, char* argv[])
{
    if (argc > 2) {
        std::cout << "Usage: calc or calc expression" << std::endl;
        return 0;
    }

    std::string eps;
    real result;
    slj::Calculator calc;
    if (argc == 2) {
        eps = argv[1];
        calc.set(eps);
        result = calc.calculate();
        if (calc.error(eps)) {
            std::cout << " ans \t = " << std::endl;
            std::cout << "\t\t" << result << std::endl;
            return 0;
        } else {
            std::cout << eps << std::endl;
            return 0;
        }
        return 0;
    }

    std::cout << "Command line calculator." << std::endl;
    std::cout << "Writen by Liangjin Song." << std::endl
              << std::endl;

    do {
        std::cout << "> ";
        std::cin >> eps;

        if (eps == "exit" || eps == "q") {
            break;
        }
        if (set(calc, eps)) {
            continue;
        }

        calc.set(eps);
        result = calc.calculate();
        if (calc.error(eps)) {
            std::cout << " ans \t = " << std::endl;
            std::cout << "\t\t" << result << std::endl;
        } else {
            std::cout << eps << std::endl;
        }
    } while (true);
    return 0;
}
  • calculator.h
/* the Calc class
 * writen by Liangjin Song on 20200209
*/
#ifndef CALCULATOR_H
#define CALCULATOR_H
#include "strcase.h"
#include <string>
#include <vector>
#define stor std::stold
using real = long double;
namespace slj {
class Calculator {
private:
    enum class Symbol {
        digit,
        add, // +
        sub, // -
        mult, // *
        div, // /
        power, // ^
        mod, // %
        lbrac, // (
        rbrac, // )
        point, // .
        sin,
        cos,
        tan,
        cot,
        sec,
        csc,
        exp,
        asin,
        acos,
        atan,
        e,
        pi,
        ln,
        sqrt,
        abs,
        cbrt,
        letter,
        err,

        floor,
        fix,
        ceil,
        round,

        log10,
        log2,

        sign,

        comma,
        sum,
        aver,
        log,
        min,
        max,
        rem
    };
    enum class Error {
        unable_to_identify,
        divide_zero,
        expression_error
    };

private:
    std::string eps, eps_bak; // the expression
    std::string err; // the error information
private:
    bool cont; // is continue
    bool radian; // radian or angle, default is ragian(true)
    real to_angle(const real radn) const { return 180 * radn / pi; }
    real to_radian(const real ang) const { return ang * pi / 180; }
    int call; // the deep of the recursion function
private:
    const real pi = 3.1415926535897932384626433832795028841971693993751;
    const real e = 2.718281828459045235360287471352662497757247093699959574966967627724;

private:
    void set_err(Error err, std::string str = ""); // set the error information
    void set_err(Error err, char ch);

private:
    Symbol resolve(std::string& dig); // resolve the expression
    Symbol resolve(const char ch);
    void digit(std::string& dig);
    Symbol letter(std::string& str);
    void remove(std::string& str);

private:
    bool is_digits(std::string& str);
    bool is_integer(std::string& str);
    bool is_real(std::string& str);

private:
    void apply(Symbol sym, std::vector<real>& val, std::vector<Symbol>& sign, std::string& str, real& rs);
    void apply(std::vector<real>& val, std::vector<Symbol>& sign, real v);
    void apply_last(std::vector<real>& val, std::vector<Symbol>& sign, real& rs);
    real calcall(std::vector<real>& val, std::vector<Symbol>& sign);

public:
    Calculator(const std::string& e = "");
    ~Calculator() = default;

public:
    void set(const std::string& e);
    real calculate();
    bool error(std::string& err);
    void set_angle(bool ang = true);

private:
    bool sum, aver;
    bool log;
    bool min, max;
    bool rem;
};
}
#endif // CALCULATOR_H
  • calculator.cpp
#include "calculator.h"
#include <algorithm>
#include <cmath>

namespace slj {
Calculator::Calculator(const std::string& e)
{
    set(e);
    radian = true;
}

void Calculator::set(const std::string& e)
{
    eps_bak = eps = e;
    call = 0;
    cont = true;
    err = "";

    sum = false;
    aver = false;
    this->log = false;
    min = max = false;
    rem = false;
}

void Calculator::set_err(Error err, std::string str)
{
    switch (err) {
    case Error::unable_to_identify:
        this->err = "Unable to identify: ";
        this->err += str;
        cont = false;
        break;
    case Error::divide_zero:
        this->err = "The divisor cannot not be 0! ";
        cont = false;
        break;
    case Error::expression_error:
        this->err = "Expression error!";
        cont = false;
        break;
    default:
        this->err = "";
        break;
    }
}

void Calculator::set_err(Error err, char ch)
{
    char s1[2] = { ch, 0 };
    set_err(err, s1);
}

real Calculator::calculate()
{
    Symbol sym;
    std::string sig;
    real result = 0;

    std::vector<real> val;
    std::vector<Symbol> sign;

    do {
        sym = resolve(sig);
        if (sym == Symbol::err) {
            break;
        }
        apply(sym, val, sign, sig, result);
        if (sym == Symbol::rbrac) {
            return result;
        }
    } while (cont && eps.size());

    if (!cont) {
        return 0;
    }
    return calcall(val, sign);
}

Calculator::Symbol Calculator::resolve(std::string& sig)
{
    char ch = eps[0];
    Symbol sym = resolve(ch);

    switch (sym) {
    case Symbol::digit:
        digit(sig);
        if (!is_real(sig)) {
            cont = false;
            sym = Symbol::err;
            set_err(Error::unable_to_identify, sig);
            return sym;
        }
        break;
    case Symbol::letter:
        sym = letter(sig);
        break;
    case Symbol::add:
        sig = "+";
        break;
    case Symbol::sub:
        sig = "-";
        break;
    case Symbol::mult:
        sig = "*";
        break;
    case Symbol::div:
        sig = "/";
        break;
    case Symbol::mod:
        sig = "%";
        break;
    case Symbol::power:
        sig = "^";
        break;
    case Symbol::lbrac:
        sig = "(";
        break;
    case Symbol::rbrac:
        sig = ")";
        break;
    case Symbol::comma:
        sig = ",";
        break;
    default:
        break;
    }

    if (sym != Symbol::err) {
        remove(sig);
    }

    return sym;
}

Calculator::Symbol Calculator::resolve(const char ch)
{
    Symbol sym = Symbol::err;

    switch (ch) {
    case '(':
        sym = Symbol::lbrac;
        break;
    case ')':
        sym = Symbol::rbrac;
        break;
    case '.':
        sym = Symbol::point;
        break;
    case '+':
        sym = Symbol::add;
        break;
    case '-':
        sym = Symbol::sub;
        break;
    case '*':
        sym = Symbol::mult;
        break;
    case '/':
        sym = Symbol::div;
        break;
    case '^':
        sym = Symbol::power;
        break;
    case '%':
        sym = Symbol::mod;
        break;
    case ',':
        sym = Symbol::comma;
        break;
    default:
        break;
    }

    if (ch >= 0x30 && ch <= 0x39) {
        sym = Symbol::digit;
    }
    if (ch >= 0x61 && ch <= 0x7a) {
        sym = Symbol::letter;
    }

    if (sym == Symbol::err) {
        cont = false;
        set_err(Error::unable_to_identify, ch);
    }

    return sym;
}

void Calculator::digit(std::string& dig)
{
    char ch = 0, s[2] = { 0, 0 };
    const size_t ns = eps.size();
    dig = "";

    for (size_t i = 0; i < ns; ++i) {
        ch = eps[i];
        if (!(resolve(ch) == Symbol::digit || resolve(ch) == Symbol::point)) {
            break;
        }
        s[0] = ch;
        dig += s;
    }
}

bool Calculator::is_digits(std::string& str)
{
    return std::all_of(str.begin(), str.end(), ::isdigit);
}

bool Calculator::is_integer(std::string& str)
{
    if (str.size() <= 0) {
        return false;
    }

    if (is_digits(str)) {
        return true;
    }

    if (str.size() > 1) {
        if (str[0] == '-' || str[0] == '+') {
            std::string tstr = str.substr(1, str.size() - 1);
            return is_digits(tstr);
        }

        return false;
    }

    return false;
}

bool Calculator::is_real(std::string& str)
{
    if (is_integer(str)) {
        return true;
    }

    size_t n1 = str.find_first_of('.');
    size_t n2 = str.find_last_of('.');

    if (n1 != n2 || n1 == str.size() - 1) {
        return false;
    }

    std::string inte = str.substr(0, n1);
    std::string frac = str.substr(n1 + 1, str.size() - n1);

    return is_integer(inte) && is_digits(frac);
}

Calculator::Symbol Calculator::letter(std::string& str)
{
    char ch = eps[0], s[2] = { ch, 0 };
    const size_t ns = eps.size();
    str = s;

    if (ch == 'e') {
        if (ns == 1) {
            return Symbol::e;
        }

        ch = eps[1];

        if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^' || ch == ')' || ch == '%') {
            return Symbol::e;
        } else {
            cont = false;
            set_err(Error::unable_to_identify, ch);
            return Symbol::err;
        }
    }

    if (ch == 'p') {
        if (ns == 1) {
            cont = false;
            set_err(Error::unable_to_identify, ch);
            return Symbol::err;
        }

        ch = eps[1];

        if (ch == 'i') {
            if (ns == 2) {
                str = "pi";
                return Symbol::pi;
            }

            ch = eps[2];

            if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^' || ch == ')' || ch == '%') {
                str = "pi";
                return Symbol::pi;
            } else {
                cont = false;
                str = "pi";
                s[0] = ch;
                str += s;
                set_err(Error::unable_to_identify, str);
                return Symbol::err;
            }
        } else {
            cont = false;
            s[0] = ch;
            str += s;
            set_err(Error::unable_to_identify, str);
            return Symbol::err;
        }
    }

    if (ns < 5) {
        cont = false;
        set_err(Error::unable_to_identify, eps);
        return Symbol::err;
    }

    str = eps.substr(0, 3);

    if (str == "ln(") {
        str = "ln";
        return Symbol::ln;
    }

    Symbol sym = Symbol::err;
    str = eps.substr(0, 4);

    switch (hash_(str.c_str())) {
    case "sin("_hash:
        str = "sin";
        sym = Symbol::sin;
        break;
    case "cos("_hash:
        str = "cos";
        sym = Symbol::cos;
        break;
    case "tan("_hash:
        str = "tan";
        sym = Symbol::tan;
        break;
    case "cot("_hash:
        str = "cot";
        sym = Symbol::cot;
        break;
    case "sec("_hash:
        str = "sec";
        sym = Symbol::sec;
        break;
    case "csc("_hash:
        str = "csc";
        sym = Symbol::csc;
        break;
    case "log("_hash:
        str = "log";
        sym = Symbol::log;
        break;
    case "abs("_hash:
        str = "abs";
        sym = Symbol::abs;
        break;
    case "exp("_hash:
        str = "exp";
        sym = Symbol::exp;
        break;
    case "fix("_hash:
        str = "fix";
        sym = Symbol::fix;
        break;
    case "sum("_hash:
        str = "sum";
        sym = Symbol::sum;
        break;
    case "min("_hash:
        str = "min";
        sym = Symbol::min;
        break;
    case "max("_hash:
        str = "max";
        sym = Symbol::max;
        break;
    case "rem("_hash:
        str = "rem";
        sym = Symbol::rem;
        break;
    default:
        break;
    }

    if (sym != Symbol::err) {
        return sym;
    }

    if (ns < 7) {
        cont = false;
        set_err(Error::unable_to_identify, eps);
        return Symbol::err;
    }

    str = eps.substr(0, 5);

    switch (hash_(str.c_str())) {
    case "sqrt("_hash:
        str = "sqrt";
        sym = Symbol::sqrt;
        break;
    case "cbrt("_hash:
        str = "cbrt";
        sym = Symbol::cbrt;
        break;
    case "asin("_hash:
        str = "asin";
        sym = Symbol::asin;
        break;
    case "acos("_hash:
        str = "acos";
        sym = Symbol::acos;
        break;
    case "atan("_hash:
        str = "atan";
        sym = Symbol::atan;
        break;
    case "ceil("_hash:
        str = "ceil";
        sym = Symbol::ceil;
        break;
    case "aver("_hash:
        str = "aver";
        sym = Symbol::aver;
        break;
    case "log2("_hash:
        str = "log2";
        sym = Symbol::log2;
        break;
    case "sign("_hash:
        str = "sign";
        sym = Symbol::sign;
        break;
    default:
        break;
    }

    if (sym != Symbol::err) {
        return sym;
    }

    if (ns < 8) {
        cont = false;
        set_err(Error::unable_to_identify, eps);
        return Symbol::err;
    }

    str = eps.substr(0, 6);
    switch (hash_(str.c_str())) {
    case "floor("_hash:
        str = "floor";
        sym = Symbol::floor;
        break;
    case "round("_hash:
        str = "round";
        sym = Symbol::round;
        break;
    case "log10("_hash:
        str = "log10";
        sym = Symbol::log10;
        break;
    default:
        break;
    }

    return sym;
}

void Calculator::remove(std::string& str)
{
    const size_t ns = str.size();
    const size_t ne = eps.size();
    if (ns == ne) {
        eps = "";
        return;
    }
    eps = eps.substr(ns, ne - ns);
}

void Calculator::apply(Symbol sym, std::vector<real>& val,
    std::vector<Symbol>& sign, std::string& str, real& rs)
{
    real v = 0;
    switch (sym) {
    case Symbol::digit:
        v = stor(str);
        apply(val, sign, v);
        break;
    case Symbol::e:
        v = e;
        apply(val, sign, v);
        break;
    case Symbol::pi:
        v = pi;
        apply(val, sign, v);
        break;
    case Symbol::lbrac:
        ++call;
        rs = this->calculate();
        apply_last(val, sign, rs);
        break;
    case Symbol::rbrac:
        --call;
        rs = calcall(val, sign);
        break;
    case Symbol::sum:
        sum = true;
        sign.push_back(sym);
        break;
    case Symbol::aver:
        aver = true;
        sign.push_back(sym);
        break;
    case Symbol::log:
        this->log = true;
        sign.push_back(sym);
        break;
    case Symbol::min:
        min = true;
        sign.push_back(sym);
        break;
    case Symbol::max:
        max = true;
        sign.push_back(sym);
        break;
    case Symbol::rem:
        rem = true;
        sign.push_back(sym);
        break;
    default:
        sign.push_back(sym);
        break;
    }
}

void Calculator::apply(std::vector<real>& val, std::vector<Symbol>& sign, real v)
{
    if (sign.size() == 0) {
        val.push_back(v);
        return;
    }

    if (val.size() == 0) {
        if (sign.back() == Symbol::sub) {
            sign.pop_back();
            val.push_back(-v);
            return;
        } else {
            cont = false;
        }
    }

    real v2;
    switch (sign.back()) {
    case Symbol::mult:
        v2 = val.back();
        val.pop_back();
        sign.pop_back();
        val.push_back(v * v2);
        break;
    case Symbol::div:
        if (v == 0) {
            cont = false;
            set_err(Error::divide_zero, "");
        }
        v2 = val.back();
        val.pop_back();
        sign.pop_back();
        val.push_back(v2 / v);
        break;
    case Symbol::power:
        v2 = val.back();
        val.pop_back();
        sign.pop_back();
        val.push_back(powl(v2, v));
        break;
    case Symbol::mod:
        if ((size_t)v == 0) {
            cont = false;
            set_err(Error::divide_zero, "");
        }
        v2 = val.back();
        val.pop_back();
        sign.pop_back();
        val.push_back((size_t)v2 % (size_t)v);
        break;
    // case Symbol::sub:
    //     sign[sign.size() - 1] = Symbol::add;
    //     val.push_back(-v);
    //     break;
    default:
        val.push_back(v);
        break;
    }
}

real Calculator::calcall(std::vector<real>& val, std::vector<Symbol>& sign)
{
    const size_t nval = val.size();

    if (sign.size() == 0) {
        if (nval == 1) {
            return val.back();
        } else {
            set_err(Error::expression_error, "");
            return 0;
        }
    }
    real v1 = 0, v2 = 0;

    if (this->log) {
        if ((nval != 2) && (sign.size() != 1)) {
            set_err(Error::expression_error);
            return 0;
        }
        return log10l(val[1]) / log10l(val[0]);
    }

    if (this->rem) {
        if ((nval != 2) && (sign.size() != 1)) {
            set_err(Error::expression_error);
            return 0;
        }
        if (val[1] == 0) {
            set_err(Error::divide_zero);
            return 0;
        }
        return (long long)val[0] / (long long)val[1];
    }

    if (sum || aver) {
        if (sign.size() != nval - 1) {
            set_err(Error::expression_error, "");
            return 0;
        }
        v1 = 0;
        for (auto& i : val) {
            v1 += i;
        }
        if (sum) {
            return v1;
        }
        if (aver) {
            return v1 / nval;
        }
    }

    if (min || max) {
        if (sign.size() != nval - 1) {
            set_err(Error::expression_error, "");
            return 0;
        }
        v1 = v2 = val[0];
        for (auto& i : val) {
            if (v1 > i) {
                v1 = i;
            }
            if (v2 < i) {
                v2 = i;
            }
        }
        if (min) {
            return v1;
        }
        if (max) {
            return v2;
        }
    }

    if (sign.size() != nval - 1) {
            set_err(Error::expression_error, "");
            return 0;
    }

    for(size_t i=0; i<sign.size();++i){
        v1=val[i];
        v2=val[i+1];
        switch (sign[i])
        {
        case Symbol::add:
            val[i+1]=v1+v2;
            break;
        case Symbol::sub:
            val[i+1]=v1-v2;
            break;
        default:
            break;
        }
    }

    /*
    do {
        switch (sign.front()) {
        case Symbol::add:
            if (nval < 2) {
                set_err(Error::expression_error, "");
                return 0;
            }
            v1 = val.front();
            val.pop_back();
            v2 = val.front();
            val.pop_back();
            val.push_back(v1 + v2);
            break;
        case Symbol::sub:
            if (nval < 2) {
                set_err(Error::expression_error, "");
                return 0;
            }
            v1 = val.back();
            val.pop_back();
            v2 = val.back();
            val.pop_back();
            val.push_back(v2 - v1);
            break;
        default:
            set_err(Error::expression_error, "");
            break;
        }
        sign.pop_back();
    } while (sign.size() != 0);
    */
    return val.back();
}

void Calculator::apply_last(std::vector<real>& val, std::vector<Symbol>& sign, real& rs)
{
    if (sign.size() == 0) {
        return;
    }
    switch (sign.back()) {
    case Symbol::power:
        if (val.size() == 0) {
            set_err(Error::expression_error, "");
            return;
        }
        sign.pop_back();
        val[val.size() - 1] = powl(val.back(), rs);
        break;
    case Symbol::sin:
        if (!radian) {
            rs = to_radian(rs);
        }
        sign.pop_back();
        val.push_back(sinl(rs));
        break;
    case Symbol::cos:
        if (!radian) {
            rs = to_radian(rs);
        }
        sign.pop_back();
        val.push_back(cosl(rs));
        break;
    case Symbol::tan:
        if (!radian) {
            rs = to_radian(rs);
        }
        sign.pop_back();
        val.push_back(tanl(rs));
        break;
    case Symbol::cot:
        if (!radian) {
            rs = to_radian(rs);
        }
        sign.pop_back();
        val.push_back((real)1 / tanl(rs));
        break;
    case Symbol::sec:
        if (!radian) {
            rs = to_radian(rs);
        }
        sign.pop_back();
        val.push_back((real)1 / cosl(rs));
        break;
    case Symbol::csc:
        if (!radian) {
            rs = to_radian(rs);
        }
        sign.pop_back();
        val.push_back((real)1 / sinl(rs));
        break;
    case Symbol::exp:
        sign.pop_back();
        val.push_back(expl(rs));
        break;
    case Symbol::asin:
        sign.pop_back();
        rs = asinl(rs);
        if (!radian) {
            rs = to_angle(rs);
        }
        val.push_back(rs);
        break;
    case Symbol::acos:
        sign.pop_back();
        rs = acosl(rs);
        if (!radian) {
            rs = to_angle(rs);
        }
        val.push_back(rs);
        break;
    case Symbol::atan:
        sign.pop_back();
        rs = atanl(rs);
        if (!radian) {
            rs = to_angle(rs);
        }
        val.push_back(rs);
        break;
    case Symbol::ln:
        sign.pop_back();
        val.push_back(logl(rs));
        break;
    case Symbol::log:
        sign.pop_back();
        val.push_back(rs);
        this->log = false;
        break;
    case Symbol::sqrt:
        sign.pop_back();
        val.push_back(sqrtl(rs));
        break;
    case Symbol::abs:
        sign.pop_back();
        val.push_back(fabsl(rs));
        break;
    case Symbol::cbrt:
        sign.pop_back();
        val.push_back(cbrtl(rs));
        break;
    case Symbol::floor:
        sign.pop_back();
        val.push_back(floorl(rs));
        break;
    case Symbol::fix:
        sign.pop_back();
        val.push_back((long long)rs);
        break;
    case Symbol::ceil:
        sign.pop_back();
        val.push_back(ceill(rs));
        break;
    case Symbol::round:
        sign.pop_back();
        val.push_back(roundl(rs));
        break;
    case Symbol::sum:
        sign.pop_back();
        val.push_back(rs);
        sum = false;
        break;
    case Symbol::aver:
        sign.pop_back();
        val.push_back(rs);
        aver = false;
        break;
    case Symbol::log10:
        sign.pop_back();
        val.push_back(log10l(rs));
        break;
    case Symbol::log2:
        sign.pop_back();
        val.push_back(log2l(rs));
        break;
    case Symbol::max:
        sign.pop_back();
        val.push_back(rs);
        max = false;
        break;
    case Symbol::min:
        sign.pop_back();
        val.push_back(rs);
        min = false;
        break;
    case Symbol::rem:
        sign.pop_back();
        val.push_back(rs);
        rem = false;
        break;
    case Symbol::sign:
        sign.pop_back();
        if (rs > 0) {
            rs = 1;
        } else if (rs < 0) {
            rs = -1;
        } else {
            rs = 0;
        }
        val.push_back(rs);
        break;
    default:
        apply(val, sign, rs);
        break;
    }
}

bool Calculator::error(std::string& err)
{
    if (call != 0) {
        set_err(Error::expression_error, "");
    }
    err = this->err;
    return cont;
}

void Calculator::set_angle(bool radn)
{
    radian = radn;
}
}
  • strcase.h
/* using the string to the switch
 * writen by Liangjin Song on 20200210
*/
#ifndef STRCASE_H
#define STRCASE_H
#include <cstdint>
namespace slj {
typedef std::uint64_t hash_t;
constexpr hash_t prime = 0x100000001B3ull;
constexpr hash_t basis = 0xCBF29CE484222325ull;

hash_t hash_(char const* str);

constexpr hash_t hash_compile_time(char const* str, hash_t last_value = basis)
{
    return *str ? hash_compile_time(str + 1,
                      (*str ^ last_value) * prime)
                : last_value;
}

constexpr hash_t operator"" _hash(char const* p, size_t)
{
    return hash_compile_time(p);
}
}
#endif  // STRCASE_H
  • strcash.cpp
#include "strcase.h"
namespace slj {
hash_t hash_(char const* str)
{
    hash_t ret{ basis };
    while (*str) {
        ret ^= *str;
        ret *= prime;
        str++;
    }
    return ret;
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章