Как мне решить этот std :: bad_cast с помощью antlrcpp :: Any?

Я пытаюсь разобрать выражение с ANTLR4. Поэтому я использую шаблон посетителей и создаю абстрактное синтаксическое дерево.

Результатом может быть выражение или что-то другое (что я удалил из этого примера кода). Посетитель ожидает возврата типа antlrcpp::Any поэтому элементы абстрактного синтаксического дерева преобразуются вantlrcpp::Any,

Но я получаю std::bad_cast если я пытаюсь преобразовать результат обратно из antlrcpp::Any в std::shared_ptr<Expression>,

#include <iostream>
#include <string>
#include <memory>

#include "antlr4-runtime.h"#include "Parser/SimpleLangLexer.h"#include "Parser/SimpleLangParser.h"#include "Parser/SimpleLangBaseVisitor.h"
struct Expression;

struct Node {
virtual ~Node() { }
};

struct Expression: public Node {
int constValue;
Expression(int constValue) : constValue(constValue) { }
virtual ~Expression() override { }
};

struct AstVisitor: public SimpleLangBaseVisitor {

virtual antlrcpp::Any visitTopLevelElement(SimpleLangParser::TopLevelElementContext *ctx) override {
std::shared_ptr<Expression> expression = ctx->expression()->accept(this);
return std::dynamic_pointer_cast<Node>(expression);
}

virtual antlrcpp::Any visitIntExpr(SimpleLangParser::IntExprContext *ctx) override {

std::string strInteger = ctx->INTEGER()->getSymbol()->getText();
int constValue = std::stoi(strInteger);

auto intExpr = std::make_shared<Expression>(constValue);
return intExpr;
}
};

int main() {

std::string line = "123;";
antlr4::ANTLRInputStream input(line);
SimpleLangLexer lexer(&input);
antlr4::CommonTokenStream tokens(&lexer);
SimpleLangParser parser(&tokens);

antlr4::tree::ParseTree *tree = parser.start();
// Prints:
// > (start (topLevelElement (expression 123) ;) <EOF>)
std::cout << std::endl << tree->toStringTree(&parser) << std::endl;

AstVisitor astVisitor;
antlrcpp::Any result = tree->accept(&astVisitor);

// Prints:
// > Dn
// std::cout << result.get_typeinfo().name() << std::endl;

// Error:
// > terminate called after throwing an instance of 'std::bad_cast'
//     what():  std::bad_cast
std::shared_ptr<Node> node = result;
std::shared_ptr<Expression> iexpr = std::dynamic_pointer_cast<Expression>(node);

// Expected:
// > 123
std::cout << iexpr->constValue << std::endl;
return 0;
}

Реализация antlrcpp :: Any

Моя грамматика:

grammar SimpleLang;

start
: topLevelElement* EOF
;

topLevelElement
: expression ';'
;

expression
: IDENTIFIER #identifierExpr
| INTEGER #intExpr
;

IDENTIFIER
: [_a-zA-Z][_a-zA-Z0-9]*
;

INTEGER
: [0-9]+
;

WS: [ \r\n\t] -> skip;

Примечание. Я значительно сократил свой код для этого вопроса и надеюсь, что он по-прежнему имеет смысл.

1

Решение

antlrcpp::Any result = tree->accept(&astVisitor);
// Error:
// > terminate called after throwing an instance of 'std::bad_cast'
//     what():  std::bad_cast

std::shared_ptr<Node> node = tree->accept(result);

здесь вы звоните tree->accept сначала с указателем на astVisitor,

Затем вы берете результат этого и передаете его tree->acceptкоторый, вероятно, ожидает указатель на SimpleLangBaseVisitor, Но первый tree->accept звонок вернулся Any что, вероятно, не содержит указатель на SimpleLangBaseVisitor,

Так что выдает ошибку.


В сторону, что Any вы используете отсутствует std::typeinfo const& get_typeinfo() const, Если бы у вас было это, вы могли бы сделать некоторые get_typeinfo().name() отладка printf, чтобы понять, что происходит не так.

Если у вас есть доступ к исходному коду, добавьте:

struct Base {
virtual ~Base();
virtual Base* clone() const = 0;
std::typeinfo const& get_typeinfo() const = 0;
};

template<typename T>
struct Derived : Base {
// ...
std::typeinfo const& get_typeinfo() const override {
return typeid(T);
}
};

и к Any сам:

std::typeinfo const& get_typeinfo() const {
if (!_ptr) return typeid(std::nullptr_t);
return ptr->get_typeinfo();
}

как только ты это получишь, std::cerr << some_any.get_typeinfo().name() << std::endl; решит многие «почему я получаю bad_cast ?!» боли. Но для этого требуется, чтобы и ваш код, и код, генерирующий Any, были созданы с этим измененным Any,

2

Другие решения

Других решений пока нет …