Я написал компилятор, который работает в его текущей форме. Однако я чувствую, что чрезмерно использую динамическое приведение c при разграничении различных подклассов для узлов при посещении узлов в AST. Вот пример:
У меня есть рекурсивный метод с именем visit
, который динамически приводит параметр узла для каждого подкласса узла. Он проверит, если приведение прошло успешно, и затем предпримет соответствующие действия следующим образом:
VariableValue visit(Node *node) {
Num* num = dynamic_cast<Num*>(node);
if (num != NULL) {
return visit_Num(num);
}
delete num;
BinOp* binop = dynamic_cast<BinOp*>(node);
if (binop != NULL) {
return visit_BinOp(binop);
}
delete binop;
UnOp* unop = dynamic_cast<UnOp*>(node);
if (unop != NULL) {
return visit_UnaryOp(unop);
}
delete unop;
...
Проблема в том, что у меня много разных подклассов узлов, поэтому эти блоки операторов if go on для пока. Я чувствую, что этот подход не очень эффективен на процессоре и памяти, так как приведение будет создано для каждого подкласса узла и должно быть проверено для каждого из них. Я пытался улучшить это, используя delete
, когда произойдет сбой приведения.
Есть ли лучший способ достичь желаемых результатов в среде polymorphi c?
Для некоторого контекста здесь классы узлов, включая родительский:
class Node {
public:
virtual std::string toString() = 0;
virtual int getNodeAttribute() { return 0; }
Token token;
Node(){}
};
class BinOp : public Node{
public:
Node *left, *right;
Token op;
BinOp(Node *cleft, Token cop, Node *cright) {
left = cleft;
Node::token = cop;
op = cop;
right = cright;
}
std::string toString() {
return "BinOp Node";
}
};
class Num : public Node{
public:
TokenValue value;
Num(Token ctoken) {
Node::token = ctoken;
value = ctoken.value;
}
std::string toString() {
return "Num Node";
}
};
class UnOp : public Node {
public:
Node *expr;
UnOp(Token ctoken, Node *cexpr) {
Node::token = ctoken;
expr = cexpr;
}
std::string toString() {
return "UnOp Node";
}
};
...
А вот как генерируется узел в синтаксическом анализаторе (например, Num
узел)
Node* Parser::factor() {
...
else if (token.type == TOKENTYPE::INTEGER) {
eat(TOKENTYPE::INTEGER);
Num* numNode = new Num(token);
return numNode;
}
...