首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c++中的一个简单标记器,它只创建一个令牌向量

c++中的一个简单标记器,它只创建一个令牌向量
EN

Code Review用户
提问于 2023-03-16 14:00:42
回答 1查看 125关注 0票数 1
代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <memory>


#define IS_DIGIT(x) x >= 48 && x <= 67 


static unsigned int allocated = 0;
void* operator new(size_t size) 
{
    allocated += size;
    void* mem = malloc(size);
    //std::cout << "allocating: " << mem << " with size: " << size << std::endl;
    return mem;

}
static unsigned int deleted = 0;
void operator delete(void* ptr, size_t size)
{
    deleted += size;
    //std::cout << "deleting: " << ptr << " with size: " << size << std::endl;
    free(ptr);
}

enum class Type 
{
    None, Number, Operator
};


std::ostream& operator<<(std::ostream& os, Type& type)
{
    switch (type)
    {
        case Type::None:
            os << "None";
            break;
        case Type::Number:
            os << "Number";
            break;
        case Type::Operator:
            os << "Operator";
            break;
        default:
            std::cout << "Unknown type for: " << &type << std::endl;
            break;
    }

    return os;
}
class Token 
{
public:
    Type type = Type::None;

    virtual void Fn() {};
};

class Number : public Token 
{
public:
    int value;

    Number(int _value)
        : value(_value) {
        type = Type::Number;
    }
};

class Operator : public Token 
{
public:
    Operator() 
    {
        type = Type::Operator;
    }

    virtual Number Operate(const Number& num1, const Number& num2) = 0;
};


class Plus : public Operator 
{
public:
    Number Operate(const Number& num1, const Number& num2) override
    {
        return Number(num1.value + num2.value);
    }
};

class Minus : public Operator 
{
public:
    Number Operate(const Number& num1, const Number& num2) override
    {
        return Number(num1.value - num2.value);
    }
};

void Tokenize(const std::string& input, std::vector<std::unique_ptr<Token>>& vec)
{
    std::string number;

    for (auto& c : input)
    {
        if (c == '\n' || c == ' ' || !c) continue;
        std::cout << "char: " << c << std::endl;
        if (IS_DIGIT(c)) number.push_back(c);

        else 
        {
            vec.push_back(std::move(std::make_unique<Number>(std::stoi(number.c_str()))));
            number.clear();

            switch (c)
            {
                case '+':
                    vec.push_back(std::move(std::make_unique<Plus>()));
                    break;
                case '-':
                    vec.push_back(std::move(std::make_unique<Minus>()));
                    break;
                default:
                    std::cout << "Unknown operator: " << c << std::endl;
                    break;

            }

        }
    }
    // for last digit
    if (!number.empty())
        vec.push_back(std::move(std::make_unique<Number>(std::stoi(number.c_str()))));
}

int main() 
{

// main scope
{
    std::vector<std::unique_ptr<Token>> tokens;
    Tokenize(" 78 + 1  *5-3", tokens);

    for (auto& i : tokens)
    {
        std::cout << "type: " << i.get()->type;
        Number* op = dynamic_cast<Number*>(i.get());
        if (op)
            std::cout << " num: " << op->value; 
        std::cout << std::endl;

    }
}

    std::cout << "total allocated: " << allocated << std::endl;
    std::cout << "total deleted: " << allocated << std::endl;

    return 0;
}

能不能有人聪明,请检查我的代码无效率和更好的优化?而且,我甚至不确定我是否做得对。提前感谢

EN

回答 1

Code Review用户

发布于 2023-03-16 14:35:06

小心宏。如果IS_DIGIT()在算术运算符旁边展开,您将得到令人惊讶的结果,因为它不像函数调用。

代码语言:javascript
复制
#define IS_DIGIT(x) ((x) >= 48 && (x) <= 67)

它仍然不是一个很好的宏,因为它不止一次地扩展x,这会导致它的副作用重复发生。让它成为一个函数--或者只使用std::isdigit(),它无缝地适应执行字符集,而不是假设输入总是ASCII。

我们不应该声明我们自己的newdelete。如果我们发现有必要,我们应该正确地实现new

代码语言:javascript
复制
if (!mem) throw std::bad_alloc();

我们需要包括<cstdlib>来声明std::malloc()std::free()

错误消息应该转到错误流,而不是输出流:

代码语言:javascript
复制
        default:
            std::cerr << "Unknown type for: " << &type << '\n';

Token是一个基类,应该有一个虚拟析构函数。

声明Token::Fn() = 0 (有或没有身体)使其成为纯粹的抽象可能是个好主意。或者只是移除它,因为它似乎从未被使用过。

Number构造函数应该是explicit

在适当的情况下很好地使用override

缺少的包括<string>

这看起来像日志记录:

std::cout << "char: " << c << std::endl;

因此,它应该转到std::clog

当应用于rvalue时,std::move()是没有操作的,所以在Tokenise()中调用它的地方并不有用。我们错过了它的包含(<utility>)。

如果我们不打算修改值,请使用const

代码语言:javascript
复制
    for (auto const& i : tokens)

考虑使用std::shared_ptr,这样我们就可以使用dynamic_pointer_cast()而不是dynamic_cast(get())

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/283993

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档