增强变体类型碰撞

2024-01-03

后续问题 https://stackoverflow.com/questions/34229428/how-to-get-around-matching-boost-variant-return-types

所以,我一直在玩

Boost Mini C 教程 https://stackoverflow.com/questions/34022066/boost-mini-c-tutorial

我所做的是添加一条规则来解析字符串文字。目的是让我可以解析和编译类似的程序(功能已经内置):

int ret(int x) {
    return x;
}

int main() {
   int x = 5;
   return ret(x)*2;
}

也 (want添加此功能),

string print(string s) {
   return s;
}

int main() {
   string foo = "bar";
   print(foo);
   return 0;
}

最后两个示例是否使用 gcc 进行编译并不重要。

所以,我添加的要点如下:

文件内表达式_def.hpp(已添加生产规则“quoted_string”):

quoted_string = '"' >> *('\\' >> char_ | ~char_('"')) >> '"'; // ADDED THIS

            primary_expr =
            uint_ 
            |   quoted_string // ADDED THIS
            |   function_call
            |   identifier
            |   bool_
            |   '(' > expr > ')'
            ;

within ast.hpp,已添加变体类型“std:string”:

typedef boost::variant<
            nil
            , bool
            , unsigned int
            , std::string // ADDED THIS
            , identifier
            , boost::recursive_wrapper<unary>
            , boost::recursive_wrapper<function_call>
            , boost::recursive_wrapper<expression>
        >
        operand;

这是添加的规则声明,以及它所冲突的规则:

qi::rule<Iterator, std::string(), skipper<Iterator> > identifier;
qi::rule<Iterator, std::string()> quoted_string; // declaring this without the skipper 
                             // lets us avoid the lexeme[] incantation (thanks @sehe).

现在的问题是,编译器混淆了“quoted_string”的“标识符”,或者实际上只是一个 std::string。

我的猜测是,它们都有 std::string 签名返回类型这一事实是问题的原因,但我不知道这里有什么好的解决方法。此外,“identifier”结构有一个用于初始化的 std::string 类型的数据成员,因此编译器实际上无法区分两者,并且变体 std::string 最终成为更好的匹配。

现在,如果我将 std::string 更改为 char* ,如下所示:

typedef boost::variant<
                nil
                , bool
                , unsigned int
                , char* // CHANGED, YET AGAIN
                , identifier
                , boost::recursive_wrapper<unary>
                , boost::recursive_wrapper<function_call>
                , boost::recursive_wrapper<expression>
            >
            operand;

它将编译并使用整数,我打赌然后我无法解析字符串(事实上,VS 将调用 abort()) 应该注意的是,因为每个变体都需要重载,所以我的代码中包含以下内容:

bool compiler::operator()(std::string const& x)
    {
        BOOST_ASSERT(current != 0);
        current->op(op_string, x);
        return true;
    }

and

 void function::op(int a, std::string const& b)
        {
            code.push_back(a);
            code.push_back(b.size());
            for (uintptr_t ch : b)
            {
                code.push_back(ch);
            }
            size_ += 2 + b.size();
        }

当我需要解析字符串时,这两种方法都可以顺利工作(当然会牺牲处理整数的能力)。

它们的整数等价物是(并且可以在编译器.cpp)

bool compiler::operator()(unsigned int x)
        {
            BOOST_ASSERT(current != 0);
            current->op(op_int, x);
            return true;
        }

而且当然:

  void function::op(int a, int b)
        {
            code.push_back(a);
            code.push_back(b);
            size_ += 2;
        }

如果我必须将变体类型从 std::string 更改为 char*,那么我必须更新重载,并且由于 C 遗留问题,它看起来有点难看。

我知道这可能有点令人畏惧,并且没有真正吸引人去梳理源代码,但我向你保证事实并非如此。本编译器教程只是将字节码推入向量中,该向量在设计上仅处理整数。我正在尝试修改它以处理字符串,因此添加和重载,以及需要unintptr_t。任何熟悉该材料和/或 Boost 的人都可能确切地知道他们在看什么(呃,@sehe,呃!)。


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

增强变体类型碰撞 的相关文章

随机推荐