从Antlrcpp :: any中检索基类

Retrieving Base class from antlrcpp::Any

本文关键字:检索 基类 any Antlrcpp      更新时间:2023-10-16

我目前正在使用ANTL4的C#版本到C 目标的某些代码进行移植,目前我遇到了一些问题。我在C#中构建AST的方式是创建一个基类(我们称其为base),并使用虚拟函数派生的类(我们称其为派生),我可以用来实现该类别。

但是,尝试将此代码转换为C ,我一直在获得Bad_cast例外我将其缩小到Antlrcpp ::任何无法正确地将派生的类扔到其基类中的任何人。例如:

class Base {
public:
    virtual std::string ToString() const { return "Basen"; }
};
class Derived : public Base {
public:
    std::string ToString() const override { return "Derivedn"; }
};
int main() {
    Derived value;
    std::cout << value.ToString(); //Obviously prints out Derived
    Base& base_value = value;
    std::cout << base_value.ToString(); //Still works exactly as expected and prints Derived
    auto any = antlrcpp::Any(value);
    auto derived = any.as<Base>(); //internally uses a dynamic_cast and throws a bad_cast 
    std::cout << derived.ToString(); //never gets to here
}

我最初认为这可能是因为它仅适用于指针,但是

auto any = antlrcpp::Any(new Derived());
std::cout << any.as<Base*>()->ToString(); //throws bad_cast

我将dynamic_cast更改为标题内的static_cast,并将施放,但是它会打印出"基础"。当任何数据成员访问任何数据成员时

我如何确切使用antlrcpp::Any获得基类?我很明显吗?

,如果不可能,我该如何确切地解决这个问题?有.is()方法,但是有很多情况下,检查访问者的返回值是某种类型的情况是不可行的(例如表达式,可以有30-40个操作员)。

<</p>

antlrcpp::any类不是为这种情况制作的。这不是通用变体实现。

如果您需要使用联合用于各种类型等的联合等方面的变体实现。

在这种情况下,唯一的指针可能不是一个好主意,因为它们不支持复制语义(您在这里需要)。为了与访问者进行评估,最好使用shared_ptr

这就是我使它起作用的方式:

有点背景 - 我正在创建一个whizzbang优化的"函数应用程序",将其复杂函数应用于传递的数据记录的类。我不想每次获得新的记录数据,因此我创建了我的优化的whizzbang树,就像对象一样,将功能应用于数据。

现在,此对象和所有派生类的基类都将具有.apply(some_data)函数,因此它们都源自基本类型,但是当调用.apply()时,所有函数都会执行不同的函数,其中包括调用.apply .apply。()属于它们的子对象。

我正在创建的最基本的函数应用对象返回常数数据结构,并在传递数据记录时,用双重表示恒定整数所以:

 applier_instance.apply(some_data)

返回:

 {23.0, ...}

不管传递了什么数据。通过它{"CAT","DOG","FOO"}它将返回{23.0, ...}

我希望在Antlr Parser看到字符串" 23"。

现在,如果您走了很远,您将意识到我需要通过多个访问者将该对象传递给,并且在很多时候,这将通过antlrcpp::Any对象和多次调用非常相似的默认访问者方法这样的调用作为以下ANTLR生成的访客代码中的一个,该代码访问了解析树的"表达式"节点:

virtual antlrcpp::Any visitP_expression(MyParser::P_expressionContext *ctx) override {
  return visitChildren(ctx);
}

..最终不在我的"开始"规则中...

virtual antlrcpp::Any visitStart(MyParser::StartContext *ctx) override {
  return visitChildren(ctx);
}

就像您一样,我遇到了一个问题,试图通过默认功能移动独特的指针。

我的答案是在我的访问者功能中这样做,以在解析树上处理整数文字:

antlrcpp::Any visitP_NUMBER(MyParser::P_NUMBERContext *ctx) {
    IFunctionApplier* fa = new IntegerLiteralApplier(stoi(ctx->getText()));
    return fa;
}

我创建了我的原始指针,指向IfunctionApplier接口(已定义了Virtual .Apply(some_data)方法),并创建了一个新的InteGerLiteralApplier对象,该对象从该接口继承。

我听到的代码上的上一个代码块中的 delete 在哪里?

没有一个 - 我将原始指针变成了一个唯一的指针,一旦它从Antlr生成的函数呼叫的顶部弹出:

...
AttributeMapParser                      parser(&tokens);
//Get 'start' rule of the parser to make a parse tree (Abstract Syntax Tree)
AttributeMapParser::StartContext*       tree =      parser.start();

////Walk and visit the tree returning a raw pointer to a function applier
auto fa_raw = visitor.visitStart(tree).as<IFunctionApplier*>();
//convert pointer fa_raw to a unique pointer 
auto fa = std::unique_ptr<IFunctionApplier>(fa_raw);
//Clear up the parser and tree
parser.reset();
//start using the unique pointer
auto result = fa->apply(some_input_data);

现在,我警告您,我是C 的初学者,在Python代码上移植了鸭型。

  1. 它有效
  2. 一个有25年经验C 经验的人之后看着我的肩膀,说它看上去,我引用"好"
  3. 网络上的Antlr C 运行时很少,所以我想我会分享我的经验

祝你好运!

P.S。编辑2019/11/13

要展示如何,当上树时,我然后使用在树底部创建的指针:

//For 'not' atom
        virtual antlrcpp::Any visitAtom_not(MyParser::Atom_notContext *ctx) override {
            auto raw_exp = visit(ctx->atm).as<IFunctionApplier*>();
            auto unique_exp = std::unique_ptr<IFunctionApplier>(raw_exp);
            IFunctionApplier* fa = new NotApplier(std::move(unique_exp));
            return fa;          
        }

请查看我如何将antlrcpp::Any施放到界面ifunctionApplier的原始指针,然后将其转换为独特的指针并将其移动到我的父对象中(因此,在这里,字面整数'functionApplier'被传递到"不"应用程序",已成为一个独特的指针。

RAW指针fa从访问中返回,并将传递到下一个ctx调用。