I have written a compiler that works in its current form. However I feel like I am overusing dynamic casting when differentiating different sub classes for the nodes while visiting nodes on the AST. Here is an example:
I have a recursive method called visit
that dynamically casts a node parameter for each node sub class. It will check if the cast was successful and then take appropriate action as such:
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;
...
The issue is I have a lot of different node sub classes, so these blocks of if statements go on for a while. I feel this approach is not very efficient on CPU and memory as a cast will be created for each node sub class and will have to be checked against each one. I have attempted to improve this by using delete
when a cast fails.
Is there a better way to achieve my desired results within a polymorphic environment?
For some context here are the node classes including the parent:
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";
}
};
...
And here is how a node is generated within the parser (Num
node for example)
Node* Parser::factor() {
...
else if (token.type == TOKENTYPE::INTEGER) {
eat(TOKENTYPE::INTEGER);
Num* numNode = new Num(token);
return numNode;
}
...