因此,我一直在使用Boost Spirit Compiler教程。目前,它非常适合整数。我正在研究一种扩展它以处理字符串的方法。这是源代码的链接。
http://www.boost.org/doc/libs/1_57_0/libs/spirit/example/qi/compiler_tutorial/mini_c/
对于熟悉Boost的人来说,以下内容应该看起来很熟悉-这是主要表达式的生产规则:
primary_expr =
uint_
| function_call
| identifier
| bool_
| '(' > expr > ')'
;
uint_可以为primary_expr分配一个int值。通常,我们可以通过创建一些生产规则,或者使用正则表达式来标识引号等类似的简单文本解析器,为char或字符串添加一些简单功能。如果您备份我发送的链接的根,则有很多示例。
真正的问题来自以下事实:要实现编译器,代码会将字节码操作推入向量。在此处推送单个字符很简单,因为所有字符都有一个附带的ASCII代码,它将被隐式转换为该字符,但对于一个字符数组却不是这种情况,因为它们在处理过程中会作为较大字符串的一部分丢失上下文(例如,构成一个句子)。
我能想到的最好的选择是更改
vector<int>
至
vector<uintptr_t>
据我了解,这种类型的指针可以指向整数和字符。不过,在上述生产规则内将'uint_'更改为'uintptr_t'并不是简单的问题。编译器告诉我在此特定实例中这是非法使用。
顺便说一句,您将看到我们的向量的实现,该向量将字节码保存在compiler.cpp / .hpp文件中。
任何帮助将不胜感激,如果您需要更多信息,请询问。谢谢。
最佳答案
通常,我们可以通过创建更多生产规则,或者使用正则表达式来标识引号或类似内容的简单文本解析器,为char或字符串添加一些简单功能。
不支持正则表达式。您可以在Boost Spirit Lex模式中使用正则表达式语法的子集(可以在token_def
中使用),但这会使画面复杂得多。
真正的问题来自以下事实:要实现编译器,代码会将字节码操作推入向量。在此处推送单个字符很简单,因为所有字符都有一个附带的ASCII代码,它将被隐式转换为该字符,但对于一个字符数组却不是这种情况,因为它们在处理过程中会作为较大字符串的一部分丢失上下文(例如,构成一个句子)。
用术语来说:AST不包含非整数值。
最简单的方法是为操作数扩展AST:
typedef boost::variant<
nil
, bool
, unsigned int
, identifier
, std::string // ADDED
, boost::recursive_wrapper<unary>
, boost::recursive_wrapper<function_call>
, boost::recursive_wrapper<expression>
>
operand;
(注意:这也是
primary_expr
和unary_expr
公开的属性的类型)现在让我们扩展规则:
quoted_string = '"' >> *('\\' >> char_ | ~char_('"')) >> '"';
primary_expr =
uint_
| function_call
| identifier
| quoted_string
| bool_
| ('(' > expr > ')')
;
请注意,我们声明了
quoted_string
而不用使其跳过,因此我们不必进行lexeme[]
咒语(Boost spirit skipper issues)。编译器支持
接下来,编译时发现
compiler
访问者尚不知道字符串。因此,我们添加 op_string, // push constant string into the stack
和
bool compiler::operator()(std::string const& x)
{
BOOST_ASSERT(current != 0);
current->op(op_string, x);
return true;
}
在各个地方。
(仍然使用https://www.livecoding.tv/sehe/编码,推送了答案,以便您可以提前阅读)