提升变体类型碰撞

时间:2015-12-08 22:13:31

标签: c++ boost compiler-construction boost-variant

Follow-Up Question

所以,我一直在玩

Boost Mini C Tutorial

我所做的是添加了一个解析字符串文字的规则。我的目的是解析和编译程序,如(已经内置的功能):

int ret(int x) {
    return x;
}

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

以及(想要添加此功能),

string print(string s) {
   return s;
}

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

最后两个例子是否用gcc编译,是无关紧要的。

所以,我添加的内容如下:

expression_def.hpp 文件中(已添加生产规则'quoted_string'):

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

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

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;
    }

 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();
        }

当我需要解析字符串时(当然牺牲处理整数的能力),这些都可以游泳。

它们的等价整数(在 compiler.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,ehem!)。

0 个答案:

没有答案