gpt4 book ai didi

C++ - 为此寻找合适的设计

转载 作者:行者123 更新时间:2023-11-28 06:31:33 25 4
gpt4 key购买 nike

我正在编写一个脚本解释器,我首先需要标记一个包含源代码的字符串。为此,我确定了不同的东西:

  • 标识符(变量名);
  • 符号(+、- 等...包括“字母”运算符,例如“return”);
  • 文字值(true、false、1、3.14、“foo”)。

为了表示这一点,我考虑了两种不同的方式:创建类层次结构:

class Token
{
public:
enum type_e { E_IDENTIFIER, E_SYMBOL, E_LITTERAL }
const type_e type;
};
class Identifier : public Token
{
public:
const string name
}
class Symbol : public Token
{
public:
const symbol_e symbol;
}
class Litteral : public Token
{
public:
const Value value;
}

我会以这种方式使用向下转换:

bla bla parseStatement( bla bla )
{
// ...
Token * curTok = tokens[ curPos ];
if( curTok->type == E_SYMBOL && dynamic_cast< Symbol * >( curTok )->symbol == E_PLUS )
{
// ...
}
// ...
}

但有人告诉我,向下类型转换意味着我的设计可能存在缺陷。而且也违反了多态性原则。

然后我想到了第二种方法,使用某种包含所有内容的变体类:

class Token
{
private:
type_e _type;
public:
type_e getType()
bool isIdentifier()
bool isSymbol()
bool isLitteral()
string getName() // If is an identifier, else exception
symbol_e getSymbol() // If is a symbol, else exception
Value getValue() // If is a litteral, else exception
}

我会这样使用:

bla bla parseStatement( bla bla )
{
// ...
Token curTok = tokens[ curPos ];
if( curTok.isSymbol() && curTok.getSymbol() == E_PLUS )
{
// ...
}
// ...
}

但在我看来,它并没有变得更干净。基本上是一样的,只是写起来短了一点。

有人建议我使用访问者设计模式,但我想不出使用这种模式来解决我的问题的方法。 我想将语法分析逻辑保留在标记之外。逻辑将位于将操纵这些标记的语法分析类中。我还需要标记具有相同类型或具有公共(public)基类,以便我可以将它们存储在单个数组中。

你知道我该如何设计吗?谢谢:)

最佳答案

这是一个带有访问者模式的版本

#include <iostream>
using namespace std;

class Value { };
class Identifier;
class Symbol;
class Literal;
class ParseVisitor {
public:
virtual void VisitAndParseFor(Identifier& d1) = 0;
virtual void VisitAndParseFor(Symbol& d2) = 0;
virtual void VisitAndParseFor(Literal& d1) = 0;
};

class Token {
public:
virtual void ParseWith(ParseVisitor& v) = 0;
};

class Identifier : public Token {
public:
virtual void ParseWith(ParseVisitor& v) {
v.VisitAndParseFor(*this);
}
const string name;
};

class Symbol : public Token {
public:
enum symbol_e {
E_PLUS, E_MINUS
};
virtual void ParseWith(ParseVisitor& v) {
v.VisitAndParseFor(*this);
}
symbol_e symbol;
};

class Literal : public Token {
public:
virtual void ParseWith(ParseVisitor& v) {
v.VisitAndParseFor(*this);
}
Value value;
};


// Implementing custom ParseVisitor
class Parser : public ParseVisitor {
virtual void VisitAndParseFor(Identifier& identifier) {
std::printf("Parsing Identifier\n");
}
virtual void VisitAndParseFor(Symbol& symbol) {
std::printf("Parsing Symbol\n");
switch (symbol.symbol) {
case Symbol::symbol_e::E_PLUS: std::printf("Found plus symbol\n"); break;
case Symbol::symbol_e::E_MINUS: std::printf("Found minus symbol\n"); break;
}
}
virtual void VisitAndParseFor(Literal& literal) {
std::printf("Parsing Literal\n");
}
};

int main() {
Parser p;

Identifier identifier;
Symbol symbol;
symbol.symbol = Symbol::symbol_e::E_PLUS;
Literal literal;

identifier.ParseWith(p);
symbol.ParseWith(p);
literal.ParseWith(p);

return 0;
}

如果在解析时需要上下文数据,则将参数添加到 Token::ParseWithParseVisitor::VisitAndParseFor。同样,如果您需要传回状态/数据,您可以更改返回签名。

关于C++ - 为此寻找合适的设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27440884/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com