Boost Spirit X3 编译期已知解析器惰性解析实现问题求助
多进制数字面量X3惰性解析实现问题
实现背景
- 参考sehe在Stack Overflow发布的Boost Spirit X3惰性解析器相关回答,尝试将惰性解析方案适配到自身的多进制数字面量解析需求
- 目标语法支持2、8、10、16四种进制的数字字面量表达,已对参考方案做最小化简化
AST设计
- 设计思路:通过
x3::raw将数字的整数部分、小数部分、指数部分以boost::iterator_range<>形式保留供后续计算,仅基数字段使用无符号整型存储 - 考虑到暂未确定后续求值需求(不排除直接在解析器中完成整数/浮点数求值的可能,实际需求存在变数),简化示例中使用
std::string存储原始字面量内容,对应结构体定义如下:
struct number { unsigned base; std::string literal; };
- 由于基数和数字内容中可嵌入下划线分隔符,使用
range-v3库的views::filter()函数做过滤处理;sehe在另一篇X3解析规则编译问题的回答中,也曾给出过带下划线分隔数字的处理方案
核心实现逻辑
参考早年使用Boost Spirit Qi时的Nabialek trick编写核心代码,逻辑如下:
auto const char_set = [](auto&& char_range, char const* name) { return x3::rule<struct _, std::string>{ name } = x3::as_parser( x3::raw[ x3::char_(char_range) >> *(-lit("_") >> x3::char_(char_range)) ]); }; auto const bin_charset = char_set("01", "binary charset"); auto const oct_charset = char_set("0-7", "octal charset"); auto const dec_charset = char_set("0-9", "decimal charset"); auto const hex_charset = char_set("0-9a-fA-F", "hexadecimal charset"); using Value = ast::number; using It = std::string::const_iterator; using Rule = x3::any_parser<It, Value>; x3::symbols<Rule> const based_parser({ { 2, as<std::string>[ bin_charset ] }, { 8, as<std::string>[ oct_charset ] }, { 10, as<std::string>[ dec_charset ] }, { 16, as<std::string>[ hex_charset ] } }, "based character set" ); auto const base = x3::rule<struct _, unsigned>{ "base" } = dec_charset; // 简化实现 auto const parser = x3::with<Rule>(Rule{}) [ x3::lexeme[ set_lazy<Rule>[based_parser] >> '#' >> do_lazy<Rule> ] ]; auto const grammar = x3::skip[ x3::space ]( parser >> x3::eoi );
待解析输入示例
计划使用该解析器处理如下格式的输入:
for (std::string const input : { "2#0101", "8#42", "10#4711", "1_6#DEAD_BEEF", }) { // 解析逻辑 }
现存问题与扩展需求
- 上述代码目前无法通过编译,无法验证逻辑是否正确;该方案相比多分支可选匹配的旧实现更优雅
- 后续语法扩展需要新增前置数字位宽、
UB/UO等特殊基数标识,需要了解可支撑后续扩展的代码设计方式,例如通过eps[get<std_tag>(ctx) == x42]这类上下文判断方式实现分支逻辑 - 完整示例代码已上传至coliru
内容的提问来源于stack exchange,提问作者Olx
相关产品推荐
相关产品推荐

