所以,我一直在玩
我所做的是添加了一个解析字符串文字的规则。我的目的是解析和编译程序,如(已经内置的功能):
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!)。