问题描述
我试图解析以下格式的文件:
//注释喇嘛喇嘛
[sectionname]
键=值
键2 =值
//注释
键=值[anothersection]
...
使用以下code
。不幸的是,报告的最后EOL为错误虽然最后都EOLS应该被接受:
(*补气:: EOL> - (sectionGrammar> *(+气:: EOL> sectionGrammar))> *补气:: EOL),
此外,我真的不知道如何正确地分析评论不考虑这是需要下一个键值对是我没有放置在船长的原因(仅ASCII ::空白)的EOL。
最后一个问题我已经是我不知道如何节添加到一个boost :: ptr_vector不复制它们。
这是我的code:
的#include<升压/精神/有/ qi.hpp>
#包括LT&;升压/精神/有/ support_multi_pass.hpp>
#包括LT&;升压/精神/有/ classic_position_iterator.hpp> //获取更详细的错误信息#包括LT&;升压/融合/调整/ std_pair.hpp>
#包括LT&;升压/融合/调整/结构/ adapt_struct.hpp>
#包括LT&;升压/融合/有/ adapt_struct.hpp>#包括LT&;升压/ bind.hpp>
#包括LT&;升压/精神的/ home /凤凰/核心/ argument.hpp>#包括LT&;升压/ foreach.hpp>#包括txt.hpp//只有在全局命名空间使用!
BOOST_FUSION_ADAPT_STRUCT(
wc3lib ::地图:: TXT ::科,
(wc3lib ::字符串名称)
(wc3lib ::地图:: TXT ::对,项)
)命名空间wc3lib
{命名空间地图
{命名空间客户端
{ 使用空间boost ::精神;
//使用空间boost ::精神::补气;
使用气:: double_;
使用气:: phrase_parse;
使用标准::空间;
使用boost ::凤凰::参考;// typedef的BOOST_TYPEOF(空间|亮(//)>> *(标准:: char_ - 齐:: EOL)GT;>气虚:: EOL)SkipperType;/ *
*不跳过EOLS因为值对被分开,因此它可以在规则中指定容易面向行
* /
模板< typename的迭代器>
结构CommentSkipper:公共补气::语法<&迭代器GT; { 齐::规则<&迭代器GT;跳跃; CommentSkipper():CommentSkipper :: base_type(跳过,PL / 0)
{
跳过= ASCII ::空白|点亮(//)>> *(标准:: char_ - 齐:: EOL)GT;>补气:: EOL;
}
};模板< typename的迭代器,类型名船长= CommentSkipper<&迭代器GT; >
结构KeyValueSquence:补气::语法<迭代器,TXT ::对(),船长>
{
// TXT ::双:: VALUE_TYPE
齐::规则<迭代器,TXT ::对(),船长>查询; //注用作参数base_type不总是需要语法的队长类型第一条规则
齐::规则<迭代器,性病::对<字符串,字符串>(),船长>对;
齐::规则<迭代器,串()>键,值; KeyValueSquence():KeyValueSquence :: base_type(查询)
{
查询=对> *(对); //只&GT使用;回溯
对= +补气:: EOL>关键>点燃('=')> -值; // - ('='>>值)
关键=标准::字符_(A-ZA-Z_)> *标准::字符_(A-ZA-Z_0-9);
值= +(标准:: char_ - 齐:: EOL); //值可以为空或EOL以外的所有字符它表示和值
}
};模板< typename的迭代器,类型名船长= CommentSkipper<&迭代器GT; >
结构SectionRule:补气::语法<迭代器,TXT ::科(),船长>
{
齐::规则<迭代器,TXT ::科(),船长>查询;
齐::规则<迭代器,串()>名称;
齐::规则<迭代器,TXT ::对(),船长>条目; KeyValueSquence<迭代器,船长> keyValueSequence; SectionRule():SectionRule :: base_type(查询)
{
查询=名称> -entries;
名称=亮起('[')>标准::字符_(A-ZA-Z_)> *标准::字符_(A-ZA-Z_0-9)>点亮(']');
项= keyValueSequence;
}
};模板< typename的迭代器>
布尔解析(迭代器第一,去年的Iterator,TXT ::第&安培;部分)
{
SectionRule<&迭代器GT; sectionGrammar;
CommentSkipper<&迭代器GT; commentSkipper;
的std ::矢量< TXT ::节> tmpSections; BOOL R =的boost ::精神::气:: phrase_parse(
第一,
持续,
(*补气:: EOL> - (sectionGrammar> *(+气:: EOL> sectionGrammar))> *补气:: EOL)
//注释队长
commentSkipper,
tmpSections //部分存入节!
); 如果(第一!=最后一个)//如果我们没有拿到全场比赛失败
{
返回false;
} // TODO临时的解决方法,直接从堆添加部分矢量
BOOST_FOREACH(性病::矢量< TXT ::节> :: REF为const_reference,tmpSections){
性病:: auto_ptr的< TXT ::节> S(新TXT ::第());
S-GT&;名称= ref.name;
S-GT&;项= ref.entries;
sections.push_back(多个);
} 返回ř;
}}
< / code>
从注释
//只使用>回溯
我得到你理解这个错误的IM pression。 >
居然会的 prevent 的回溯过去的这一点,因为它的任务的下一个标记
在为present一些技巧,我嘲笑了presumed缺少的头:
//的#includetxt.hpp
//最小的样机
命名空间wc3lib {
使用std :: string的; 命名地图{空间TXT {
的typedef的std ::地图<字符串,字符串>对; 结构部分
{
字符串名称;
对条目;
}; 的typedef的std ::矢量<节>段;
}}
}
现在,我已经固定你的code,以显示该怎么办
- 调试
- 错误处理
- 预期(我已经选择了非严格的解决方案,因为我没有时间去密切关注为其期望的意义)
看它住在<一个href=\"http://coliru.stacked-crooked.com/view?id=cd1d516ae0b19bd6f9af1e3f1b132211-0d2159870a1c6cb0cd1457b292b97230\"相对=nofollow> Coliru
请注意
-
请不使用命名空间在命名空间内
做的。相反,使用便捷的命名空间的别名:
命名空间补气=的boost ::精神::补气;
命名空间ASCII =的boost ::精神:: ASCII; -
请不要(的不的)使用
的auto_ptr&LT;&GT;
。这是容易出错的,过时的,德precated,不灵活:/使用的unique_ptr
来代替,如果您必须对堆的部分(为什么?)。 - 期望流的末尾,以及
EOL
终止您的线... -
小心命名的。
-
查询
被双作为规则名称 - 你解析部分或疑问或
KeyValueSquence
S' - 考虑使用
section_header
而不是名称
等
我有这种感觉有些混乱会发生不小心的命名。
-
-
考虑合并文法为一体,除非
- 您真正的语法方式比较复杂(在这个层面上,这似乎是无关紧要的,因为你仍然可以组三个语法为一个子文法)
- 您绝对需要跨翻译单元的语法分割
事不宜迟:
的#define BOOST_SPIRIT_DEBUG
#包括LT&;升压/精神/有/ qi.hpp&GT;#包括LT&;升压/融合/ adapted.hpp&GT;
#包括LT&;升压/ foreach.hpp&GT;
#包括LT&;地图和GT;//#包括txt.hpp
//最小的样机
命名空间wc3lib {
使用std :: string的; 命名地图{空间TXT {
的typedef的std ::地图&LT;字符串,字符串&GT;对; 结构部分
{
字符串名称;
对条目;
}; 的typedef的std ::矢量&lt;节&gt;段;
}}
}//只有在全局命名空间使用!
BOOST_FUSION_ADAPT_STRUCT(
wc3lib ::地图:: TXT ::科,
(wc3lib ::字符串名称)
(wc3lib ::地图:: TXT ::对,项)
)命名空间wc3lib {命名地图{命名空间客户端{ 命名空间补气=的boost ::精神::补气;
命名空间ASCII =的boost ::精神:: ASCII; / *
*不跳过EOLS因为值对被分开,因此它可以在规则中指定容易面向行
* /
模板&LT; typename的迭代器&GT;
结构CommentSkipper:公共补气::语法&LT;&迭代器GT; { 齐::规则&LT;&迭代器GT;跳跃; CommentSkipper():CommentSkipper :: base_type(跳过,PL / 0)
{
使用命名空间补气;
跳过= ASCII ::空白| (亮(//)&GT;&GT; *(标准:: char_ - EOL)GT;&GT; EOL); BOOST_SPIRIT_DEBUG_NODES((略));
}
}; 模板&LT; typename的迭代器,类型名船长= CommentSkipper&LT;&迭代器GT; &GT;
结构KeyValueSquence:补气::语法&LT;迭代器,TXT ::对(),船长&GT;
{
齐::规则&LT;迭代器,TXT ::对(),船长&GT;对; //注用作参数base_type不总是需要语法的队长类型第一条规则
齐::规则&LT;迭代器,性病::对&LT;字符串,字符串&GT;(),船长&GT;对;
齐::规则&LT;迭代器,串()&GT;键,值; KeyValueSquence():KeyValueSquence :: base_type(对)
{
使用命名空间补气; 对= +对; //只&GT使用;回溯 //这些曾与回溯(在节结束失败的规则)中的问题
对= + EOL&GT;关键&GT;点燃('=')&GT;值; // - ('='&GT;&GT;值)
关键=标准::字符_(A-ZA-Z_)&GT; *标准::字符_(A-ZA-Z_0-9); //使用这个移除的问题:
对= + EOL&GT;&GT;关键&GT;&GT;点燃('=')&GT;&GT;值; // - ('='&GT;&GT;值)
关键=标准::字符_(A-ZA-Z_)&GT;&GT; *标准::字符_(A-ZA-Z_0-9); 值= *(标准:: char_ - (EOL | EOI)); //值可以为空或EOL以外的所有字符,表示该值的末尾 BOOST_SPIRIT_DEBUG_NODES((对)(对)(密钥)(值));
}
}; 模板&LT; typename的迭代器,类型名船长= CommentSkipper&LT;&迭代器GT; &GT;
结构SectionRule:补气::语法&LT;迭代器,TXT ::科(),船长&GT;
{
齐::规则&LT;迭代器,TXT ::科(),船长&GT;查询;
齐::规则&LT;迭代器,串()&GT;名称; KeyValueSquence&LT;迭代器,船长&GT; keyValueSequence; SectionRule():SectionRule :: base_type(查询)
{
使用命名空间补气; 名称=亮起('[')&GT;标准::字符_(A-ZA-Z_)&GT; *标准::字符_(A-ZA-Z_0-9)&GT;点亮(']');
查询=名称&gt; -keyValueSequence; BOOST_SPIRIT_DEBUG_NODES((查询)(名));
}
}; 模板&LT; typename的迭代器&GT;
布尔解析(迭代器第一,去年的Iterator,TXT ::第&安培;部分)
{
SectionRule&LT;&迭代器GT; sectionGrammar;
CommentSkipper&LT;&迭代器GT; commentSkipper;
的std ::矢量&lt; TXT ::节&gt; tmpSections; 尝试
{
BOOL R =气:: phrase_parse(
第一个,最后,
(sectionGrammar%+补气:: EOL)GT;&GT; *补气:: EOL&GT;齐:: EOI,
//注释队长
commentSkipper,
tmpSections //部分存入节!
); 如果(第一!=最后一个)//如果我们没有拿到全场比赛失败
{
的std :: CERR&LT;&LT; DEBUG:非解析:'&LT;&LT;标准::字符串(第一,最后)LT;&LT; \\ n;
返回false;
}
// TODO临时的解决方法,直接从堆添加部分矢量
部分= tmpSections; 返回ř;
}赶上(气:: expectation_failure&LT;&迭代器GT;常量与评估)
{
的std :: CERR&LT;&LT; 意外的:&LT;&LT; e.what()&所述;&下; 在'&LT;&LT;标准::字符串(e.first,e.last)LT;&LT; \\ n;
返回false;
}
}}}}诠释的main()
{
的std :: cin.unsetf(性病:: IOS :: skipws);
提振精神:: :: istream_iterator F(的std :: CIN),L; wc3lib ::地图:: TXT ::章节解析;
布尔OK = wc3lib ::地图::客户::解析(F,L,解析);
如果(OK)
{
性病::法院LT&;&LT; 经分析&LT;&LT; parsed.size()&所述;&下; 部分的\\ n;
为(自动&安培;部分:解析)
{
性病::法院LT&;&LT; 一节[&LT;&LT; section.name&LT;&LT; ]有&LT;&LT; section.entries.size()&所述;&下; 对的\\ n;
}
}
}
它打印
解析的2节
节[sectionname]有3对
节[anothersection]有1对
在/随着解析器的调试跟踪:
&LT;&查询GT;
&LT;尽量&GT; //注释喇嘛喇嘛\\ n [&LT; /&尝试GT;
&LT;&跳过GT;
&LT;尽量&GT; //注释喇嘛喇嘛\\ n [&LT; /&尝试GT;
&LT;成功与GT; [sectionname] \\ nkey =&LT; /成功&GT;
&LT;&属性GT;&LT; /属性&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; [sectionname] \\ nkey =&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;名称&gt;
&LT;尽量&GT; [sectionname] \\ nkey =&LT; /&尝试GT;
&LT;成功与GT; \\ nkey =值\\ nkey2 = VA&LT; /成功&GT;
&LT;&属性GT; [S,E,C,T,I,O,N,N,A,M,E]]&LT; /属性&GT;
&LT; /名称&gt;
&LT;对GT&;
&LT;尽量&GT; \\ nkey =值\\ nkey2 = VA&LT; /&尝试GT;
&LT;对GT&;
&LT;尽量&GT; \\ nkey =值\\ nkey2 = VA&LT; /&尝试GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ nkey =值\\ nkey2 = VA&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;的key = value \\ nkey2 = VAL&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;的key = value \\ nkey2 = VAL&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;密钥GT;
&LT;尽量&GT;的key = value \\ nkey2 = VAL&LT; /&尝试GT;
&LT;成功与GT; =值\\ nkey2 =数值2&LT; /成功&GT;
&LT;&属性GT; [K,E,Y]]&LT; /属性&GT;
&LT; /键&GT;
&LT;&跳过GT;
&LT;尽量&GT; =值\\ nkey2 =数值2&LT; /&尝试GT;
&LT;&成功GT =值\\ nkey2 =值2 \\ n&LT; /成功&GT;
&LT;&属性GT;&LT; /属性&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; =值\\ nkey2 =值2 \\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;值\\ nkey2 =值2 \\ n \\ n&LT; /&尝试GT;
&LT;成功与GT;值\\ nkey2 =值2 \\ n \\ n \\ n&LT; /成功&GT;
&LT;&属性GT;&LT; /属性&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;值\\ nkey2 =值2 \\ n \\ n \\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT; VALUE&GT;
&LT;尽量&GT;值\\ nkey2 =值2 \\ n \\ n \\ n&LT; /&尝试GT;
&LT;成功与GT; \\ nkey2 =值2 \\ n \\ n \\ n // CO&LT; /成功&GT;
&LT;&属性GT; [V,A,L,U,E]]&LT; /属性&GT;
&LT; /值&GT;
&LT;成功与GT; \\ nkey2 =值2 \\ n \\ n \\ n // CO&LT; /成功&GT;
&LT;&属性GT; [[[K,E,Y],[V,A,L,U,E]]]&LT; /属性&GT;
&LT; /双&GT;
&LT;对GT&;
&LT;尽量&GT; \\ nkey2 =值2 \\ n \\ n \\ n // CO&LT; /&尝试GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ nkey2 =值2 \\ n \\ n \\ n // CO&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;键2 =值\\ n \\ n \\ n // COM&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;键2 =值\\ n \\ n \\ n // COM&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;密钥GT;
&LT;尽量&GT;键2 =值\\ n \\ n \\ n // COM&LT; /&尝试GT;
&LT;&成功GT; 2 =值2 \\ n \\ n \\ n //注释&LT; /成功&GT;
&所述;属性&GT; [K,E,Y,2]]下; /属性&GT;
&LT; /键&GT;
&LT;&跳过GT;
&LT;尽量&GT; 2 =值2 \\ n \\ n \\ n //注释&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;值2 \\ n \\ n \\ n //注释\\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT; VALUE&GT;
&LT;尽量&GT;值2 \\ n \\ n \\ n //注释\\ n&LT; /&尝试GT;
&LT;成功与GT; \\ n \\ n \\ n //注释\\ nkey3 =&LT; /成功&GT;
&所述;属性&GT; [V,A,L,U,E,2]]下; /属性&GT;
&LT; /值&GT;
&LT;成功与GT; \\ n \\ n \\ n //注释\\ nkey3 =&LT; /成功&GT;
&所述;属性&GT; [[[K,E,Y,2],[V,A,L,U,E,2]]]下; /属性&GT;
&LT; /双&GT;
&LT;对GT&;
&LT;尽量&GT; \\ n \\ n \\ n //注释\\ nkey3 =&LT; /&尝试GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ n \\ n \\ n //注释\\ nkey3 =&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ n \\ n //注释\\ nkey3 =&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ n //注释\\ nkey3 = V&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; //注释\\ nkey3 = VA&LT; /&尝试GT;
&LT;成功与GT; KEY3 =值3 \\ n \\ n [ANOT&LT; /成功&GT;
&LT;&属性GT;&LT; /属性&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; KEY3 =值3 \\ n \\ n [ANOT&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; KEY3 =值3 \\ n \\ n [ANOT&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;密钥GT;
&LT;尽量&GT; KEY3 =值3 \\ n \\ n [ANOT&LT; /&尝试GT;
&LT;成功与GT; =值3 \\ n \\ n [anothers&LT; /成功&GT;
&所述;属性&GT; [K,E,Y,3]]下; /属性&GT;
&LT; /键&GT;
&LT;&跳过GT;
&LT;尽量&GT; =值3 \\ n \\ n [anothers&LT; /&尝试GT;
&LT;&成功GT =值3 \\ n \\ n [anotherse&LT; /成功&GT;
&LT;&属性GT;&LT; /属性&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; =值3 \\ n \\ n [anotherse&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;值3 \\ n \\ n [anothersec&LT; /&尝试GT;
&LT;成功与GT; VALUE3 \\ n \\ n [anothersect&LT; /成功&GT;
&LT;&属性GT;&LT; /属性&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; VALUE3 \\ n \\ n [anothersect&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT; VALUE&GT;
&LT;尽量&GT; VALUE3 \\ n \\ n [anothersect&LT; /&尝试GT;
&LT;成功与GT; \\ n \\ n [anothersection] \\ NK&LT; /成功&GT;
&所述;属性&GT; [V,A,L,U,E,3]]下; /属性&GT;
&LT; /值&GT;
&LT;成功与GT; \\ n \\ n [anothersection] \\ NK&LT; /成功&GT;
&LT;&属性GT; [[[K,E,Y,3],[V,A,L,U,E,3]]]&LT; /属性&GT;
&LT; /双&GT;
&LT;对GT&;
&LT;尽量&GT; \\ n \\ n [anothersection] \\ NK&LT; /&尝试GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ n \\ n [anothersection] \\ NK&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ N [anothersection] \\ NKE&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; anothersection] \\ nkey&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; anothersection] \\ nkey&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;密钥GT;
&LT;尽量&GT; anothersection] \\ nkey&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /键&GT;
&LT;失败/&GT;
&LT; /双&GT;
&LT;成功与GT; \\ n \\ n [anothersection] \\ NK&LT; /成功&GT;
&LT;属性&GT; [[[[K,E,Y],[V,A,L,U,E],[K,E,Y,2],[V,A,L,U,E, 2],[K,E,Y,3],[v,A,L,U,E,3]]]]&LT; /属性&GT;
&LT; /对&GT;
&LT;成功与GT; \\ n \\ n [anothersection] \\ NK&LT; /成功&GT;
&LT;属性&GT; [[[S,E,C,T,I,O,N,N,A,M,E],[[[K,E,Y],[V,A,L,U,E ]],[[K,E,Y,2],[v,A,L,U,E,2],[K,E,Y,3],[v,A,L,U,E ,3]]]]]下; /属性&GT;
&LT; /查询&GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ n \\ n [anothersection] \\ NK&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ N [anothersection] \\ NKE&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; anothersection] \\ nkey&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&查询GT;
&LT;尽量&GT; anothersection] \\ nkey&LT; /&尝试GT;
&LT;&跳过GT;
&LT;尽量&GT; anothersection] \\ nkey&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;名称&gt;
&LT;尽量&GT; anothersection] \\ nkey&LT; /&尝试GT;
&LT;成功与GT; \\ nkey =值\\ n&LT; /成功&GT;
&LT;&属性GT; [A,N,O,T,H,E,R,S,E,C,T,I,O,N]]&LT; /属性&GT;
&LT; /名称&gt;
&LT;对GT&;
&LT;尽量&GT; \\ nkey =值\\ n&LT; /&尝试GT;
&LT;对GT&;
&LT;尽量&GT; \\ nkey =值\\ n&LT; /&尝试GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ nkey =值\\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;的key = value \\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;的key = value \\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;密钥GT;
&LT;尽量&GT;的key = value \\ n&LT; /&尝试GT;
&LT;成功与GT; =值\\ n&LT; /成功&GT;
&LT;&属性GT; [K,E,Y]]&LT; /属性&GT;
&LT; /键&GT;
&LT;&跳过GT;
&LT;尽量&GT; =值\\ n&LT; /&尝试GT;
&LT;&成功GT =值\\ n&LT; /成功&GT;
&LT;&属性GT;&LT; /属性&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT; =值\\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;值\\ n&LT; /&尝试GT;
&LT;成功与GT;值\\ n&LT; /成功&GT;
&LT;&属性GT;&LT; /属性&GT;
&LT; /跳过&GT;
&LT;&跳过GT;
&LT;尽量&GT;值\\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT; VALUE&GT;
&LT;尽量&GT;值\\ n&LT; /&尝试GT;
&LT;成功与GT; \\ n&LT; /成功&GT;
&LT;&属性GT; [V,A,L,U,E]]&LT; /属性&GT;
&LT; /值&GT;
&LT;成功与GT; \\ n&LT; /成功&GT;
&LT;&属性GT; [[[K,E,Y],[V,A,L,U,E]]]&LT; /属性&GT;
&LT; /双&GT;
&LT;对GT&;
&LT;尽量&GT; \\ n&LT; /&尝试GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;密钥GT;
&LT;尽量&GT;&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /键&GT;
&LT;失败/&GT;
&LT; /双&GT;
&LT;成功与GT; \\ n&LT; /成功&GT;
&LT;&属性GT; [[[[K,E,Y],[V,A,L,U,E]]]]&LT; /属性&GT;
&LT; /对&GT;
&LT;成功与GT; \\ n&LT; /成功&GT;
&LT;属性&GT; [[[A,N,O,T,H,E,R,S,E,C,T,I,O,N],[[[K,E,Y],[V,A ,L,U,E]]]]]&LT; /属性&GT;
&LT; /查询&GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
&LT;&查询GT;
&LT;尽量&GT;&LT; /&尝试GT;
&LT;名称&gt;
&LT;尽量&GT;&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /名称&gt;
&LT;失败/&GT;
&LT; /查询&GT;
&LT;&跳过GT;
&LT;尽量&GT; \\ n&LT; /&尝试GT;
&LT;失败/&GT;
&LT; /跳过&GT;
I am trying to parse files of the following form:
// comment bla bla
[sectionname]
key = value
key2=value2
// comment
key = value
[anothersection]
...
using the following code. Unfortunately, it reports the last eol as an error although all eols at the end should be accepted by: (*qi::eol > -(sectionGrammar > *(+qi::eol > sectionGrammar)) > *qi::eol),
Besides I really don't know how to parse comments properly without taking the eol which is required for the next key-value pair which is the reason I didn't placed in in the Skipper (only ascii::blank).
The last issue I have is that I don't know how to add sections to a boost::ptr_vector without copying them.
This is my code:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp> // for more detailed error information
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/bind.hpp>
#include <boost/spirit/home/phoenix/core/argument.hpp>
#include <boost/foreach.hpp>
#include "txt.hpp"
// Only use in global namespace!
BOOST_FUSION_ADAPT_STRUCT(
wc3lib::map::Txt::Section,
(wc3lib::string, name)
(wc3lib::map::Txt::Pairs, entries)
)
namespace wc3lib
{
namespace map
{
namespace client
{
using namespace boost::spirit;
//using namespace boost::spirit::qi;
using qi::double_;
using qi::phrase_parse;
using standard::space;
using boost::phoenix::ref;
//typedef BOOST_TYPEOF(space | lit("//") >> *(standard::char_ - qi::eol) >> qi::eol) SkipperType;
/*
* Doesn't skip eols since value pairs are separated linewise which therefore can be specified easier in the rules
*/
template<typename Iterator>
struct CommentSkipper : public qi::grammar<Iterator> {
qi::rule<Iterator> skip;
CommentSkipper() : CommentSkipper::base_type(skip, "PL/0")
{
skip = ascii::blank | lit("//") >> *(standard::char_ - qi::eol) >> qi::eol;
}
};
template <typename Iterator, typename Skipper = CommentSkipper<Iterator> >
struct KeyValueSquence : qi::grammar<Iterator, Txt::Pairs(), Skipper>
{
//Txt::Pairs::value_type
qi::rule<Iterator, Txt::Pairs(), Skipper> query; // NOTE first rule used as parameter for base_type does always need the skipper type of the grammar
qi::rule<Iterator, std::pair<string, string>(), Skipper> pair;
qi::rule<Iterator, string()> key, value;
KeyValueSquence() : KeyValueSquence::base_type(query)
{
query = pair > *(pair); // use only > for backtracking
pair = +qi::eol > key > lit('=') > -value; // -('=' >> value)
key = standard::char_("a-zA-Z_") > *standard::char_("a-zA-Z_0-9");
value = +(standard::char_ - qi::eol); // values can be empty or all characters except eol which indicates the and of the value
}
};
template <typename Iterator, typename Skipper = CommentSkipper<Iterator> >
struct SectionRule : qi::grammar<Iterator, Txt::Section(), Skipper>
{
qi::rule<Iterator, Txt::Section(), Skipper> query;
qi::rule<Iterator, string()> name;
qi::rule<Iterator, Txt::Pairs(), Skipper> entries;
KeyValueSquence<Iterator, Skipper> keyValueSequence;
SectionRule() : SectionRule::base_type(query)
{
query = name > -entries;
name = lit('[') > standard::char_("a-zA-Z_") > *standard::char_("a-zA-Z_0-9") > lit(']');
entries = keyValueSequence;
}
};
template <typename Iterator>
bool parse(Iterator first, Iterator last, Txt::Sections §ions)
{
SectionRule<Iterator> sectionGrammar;
CommentSkipper<Iterator> commentSkipper;
std::vector<Txt::Section> tmpSections;
bool r = boost::spirit::qi::phrase_parse(
first,
last,
(*qi::eol > -(sectionGrammar > *(+qi::eol > sectionGrammar)) > *qi::eol),
// comment skipper
commentSkipper,
tmpSections //sections store into "sections"!
);
if (first != last) // fail if we did not get a full match
{
return false;
}
// TODO temporary workaround, add sections directly from heap to vector
BOOST_FOREACH(std::vector<Txt::Section>::const_reference ref, tmpSections) {
std::auto_ptr<Txt::Section> s(new Txt::Section());
s->name = ref.name;
s->entries = ref.entries;
sections.push_back(s);
}
return r;
}
}
</code>
From the comment
// use only > for backtracking
I get the impression that you're understanding this wrong. >
will actually prevent backtracking past that point, because it mandates the next token.
In order to present some techniques, I've mocked up the presumed missing header:
// #include "txt.hpp"
// minimal mockup
namespace wc3lib {
using std::string;
namespace map { namespace Txt {
typedef std::map<string, string> Pairs;
struct Section
{
string name;
Pairs entries;
};
typedef std::vector<Section> Sections;
} }
}
Now, I've "fixed" up your code to show how to do
- debugging
- error handling
- expectations (I've opted for the 'non-strict' solution, because I don't have time to watch closely for which expectations make sense)
See it live at Coliru
Note
please don't
using namespace
at namespace scope. Instead, use convenient namespace aliases:namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii;
please don't (don't) use
auto_ptr<>
. It's error-prone, obsolete, deprecated, inflexible :/ Useunique_ptr
instead if you must have the sections on the heap (why?).- expect the end of the stream as well as
eol
to terminate your lines... be careful of naming.
query
was double used as a rule name- are you parsing sections or queries or
KeyValueSquence
s? - consider using
section_header
instead ofname
etc.
I do have the feeling some confusion would not have occurred with more careful naming.
consider merging the grammars into one, unless
- your real grammar is way more complicated (at this level, that seems to be irrelevant, since you could still group these three grammars into one subgrammar)
- you absolutely need to split the grammars across translation units
Without further ado:
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/foreach.hpp>
#include <map>
// #include "txt.hpp"
// minimal mockup
namespace wc3lib {
using std::string;
namespace map { namespace Txt {
typedef std::map<string, string> Pairs;
struct Section
{
string name;
Pairs entries;
};
typedef std::vector<Section> Sections;
} }
}
// Only use in global namespace!
BOOST_FUSION_ADAPT_STRUCT(
wc3lib::map::Txt::Section,
(wc3lib::string, name)
(wc3lib::map::Txt::Pairs, entries)
)
namespace wc3lib { namespace map { namespace client {
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
/*
* Doesn't skip eols since value pairs are separated linewise which therefore can be specified easier in the rules
*/
template<typename Iterator>
struct CommentSkipper : public qi::grammar<Iterator> {
qi::rule<Iterator> skip;
CommentSkipper() : CommentSkipper::base_type(skip, "PL/0")
{
using namespace qi;
skip = ascii::blank | (lit("//") >> *(standard::char_ - eol) >> eol);
BOOST_SPIRIT_DEBUG_NODES((skip));
}
};
template <typename Iterator, typename Skipper = CommentSkipper<Iterator> >
struct KeyValueSquence : qi::grammar<Iterator, Txt::Pairs(), Skipper>
{
qi::rule<Iterator, Txt::Pairs(), Skipper> pairs; // NOTE first rule used as parameter for base_type does always need the skipper type of the grammar
qi::rule<Iterator, std::pair<string, string>(), Skipper> pair;
qi::rule<Iterator, string()> key, value;
KeyValueSquence() : KeyValueSquence::base_type(pairs)
{
using namespace qi;
pairs = +pair; // use only > for backtracking
// these had a problem with backtracking (failing the rule at the end of a section)
pair = +eol > key > lit('=') > value; // -('=' >> value)
key = standard::char_("a-zA-Z_") > *standard::char_("a-zA-Z_0-9");
// using this removes that problem:
pair = +eol >> key >> lit('=') >> value; // -('=' >> value)
key = standard::char_("a-zA-Z_") >> *standard::char_("a-zA-Z_0-9");
value = *(standard::char_ - (eol|eoi)); // values can be empty or all characters except eol which indicates the end of the value
BOOST_SPIRIT_DEBUG_NODES((pairs)(pair)(key)(value));
}
};
template <typename Iterator, typename Skipper = CommentSkipper<Iterator> >
struct SectionRule : qi::grammar<Iterator, Txt::Section(), Skipper>
{
qi::rule<Iterator, Txt::Section(), Skipper> query;
qi::rule<Iterator, string()> name;
KeyValueSquence<Iterator, Skipper> keyValueSequence;
SectionRule() : SectionRule::base_type(query)
{
using namespace qi;
name = lit('[') > standard::char_("a-zA-Z_") > *standard::char_("a-zA-Z_0-9") > lit(']');
query = name > -keyValueSequence;
BOOST_SPIRIT_DEBUG_NODES((query)(name));
}
};
template <typename Iterator>
bool parse(Iterator first, Iterator last, Txt::Sections §ions)
{
SectionRule<Iterator> sectionGrammar;
CommentSkipper<Iterator> commentSkipper;
std::vector<Txt::Section> tmpSections;
try
{
bool r = qi::phrase_parse(
first, last,
(sectionGrammar % +qi::eol) >> *qi::eol > qi::eoi,
// comment skipper
commentSkipper,
tmpSections //sections store into "sections"!
);
if (first != last) // fail if we did not get a full match
{
std::cerr << "DEBUG: Unparsed: '" << std::string(first,last) << "\n";
return false;
}
// TODO temporary workaround, add sections directly from heap to vector
sections = tmpSections;
return r;
} catch(qi::expectation_failure<Iterator> const& e)
{
std::cerr << "Unexpected: " << e.what() << " at '" << std::string(e.first,e.last) << "\n";
return false;
}
}
} } }
int main()
{
std::cin.unsetf(std::ios::skipws);
boost::spirit::istream_iterator f(std::cin), l;
wc3lib::map::Txt::Sections parsed;
bool ok = wc3lib::map::client::parse(f, l, parsed);
if (ok)
{
std::cout << "Parsed " << parsed.size() << " sections\n";
for(auto& section : parsed)
{
std::cout << "section [" << section.name << "] has " << section.entries.size() << " pairs\n";
}
}
}
Which prints
Parsed 2 sections
section [sectionname] has 3 pairs
section [anothersection] has 1 pairs
After/along with the debug trace of the parsers:
<query>
<try>// comment bla bla\n[</try>
<skip>
<try>// comment bla bla\n[</try>
<success>[sectionname]\nkey = </success>
<attributes>[]</attributes>
</skip>
<skip>
<try>[sectionname]\nkey = </try>
<fail/>
</skip>
<name>
<try>[sectionname]\nkey = </try>
<success>\nkey = value\nkey2=va</success>
<attributes>[[s, e, c, t, i, o, n, n, a, m, e]]</attributes>
</name>
<pairs>
<try>\nkey = value\nkey2=va</try>
<pair>
<try>\nkey = value\nkey2=va</try>
<skip>
<try>\nkey = value\nkey2=va</try>
<fail/>
</skip>
<skip>
<try>key = value\nkey2=val</try>
<fail/>
</skip>
<skip>
<try>key = value\nkey2=val</try>
<fail/>
</skip>
<key>
<try>key = value\nkey2=val</try>
<success> = value\nkey2=value2</success>
<attributes>[[k, e, y]]</attributes>
</key>
<skip>
<try> = value\nkey2=value2</try>
<success>= value\nkey2=value2\n</success>
<attributes>[]</attributes>
</skip>
<skip>
<try>= value\nkey2=value2\n</try>
<fail/>
</skip>
<skip>
<try> value\nkey2=value2\n\n</try>
<success>value\nkey2=value2\n\n\n</success>
<attributes>[]</attributes>
</skip>
<skip>
<try>value\nkey2=value2\n\n\n</try>
<fail/>
</skip>
<value>
<try>value\nkey2=value2\n\n\n</try>
<success>\nkey2=value2\n\n\n// co</success>
<attributes>[[v, a, l, u, e]]</attributes>
</value>
<success>\nkey2=value2\n\n\n// co</success>
<attributes>[[[k, e, y], [v, a, l, u, e]]]</attributes>
</pair>
<pair>
<try>\nkey2=value2\n\n\n// co</try>
<skip>
<try>\nkey2=value2\n\n\n// co</try>
<fail/>
</skip>
<skip>
<try>key2=value2\n\n\n// com</try>
<fail/>
</skip>
<skip>
<try>key2=value2\n\n\n// com</try>
<fail/>
</skip>
<key>
<try>key2=value2\n\n\n// com</try>
<success>=value2\n\n\n// comment</success>
<attributes>[[k, e, y, 2]]</attributes>
</key>
<skip>
<try>=value2\n\n\n// comment</try>
<fail/>
</skip>
<skip>
<try>value2\n\n\n// comment\n</try>
<fail/>
</skip>
<value>
<try>value2\n\n\n// comment\n</try>
<success>\n\n\n// comment\nkey3 =</success>
<attributes>[[v, a, l, u, e, 2]]</attributes>
</value>
<success>\n\n\n// comment\nkey3 =</success>
<attributes>[[[k, e, y, 2], [v, a, l, u, e, 2]]]</attributes>
</pair>
<pair>
<try>\n\n\n// comment\nkey3 =</try>
<skip>
<try>\n\n\n// comment\nkey3 =</try>
<fail/>
</skip>
<skip>
<try>\n\n// comment\nkey3 = </try>
<fail/>
</skip>
<skip>
<try>\n// comment\nkey3 = v</try>
<fail/>
</skip>
<skip>
<try>// comment\nkey3 = va</try>
<success>key3 = value3\n\n[anot</success>
<attributes>[]</attributes>
</skip>
<skip>
<try>key3 = value3\n\n[anot</try>
<fail/>
</skip>
<skip>
<try>key3 = value3\n\n[anot</try>
<fail/>
</skip>
<key>
<try>key3 = value3\n\n[anot</try>
<success> = value3\n\n[anothers</success>
<attributes>[[k, e, y, 3]]</attributes>
</key>
<skip>
<try> = value3\n\n[anothers</try>
<success>= value3\n\n[anotherse</success>
<attributes>[]</attributes>
</skip>
<skip>
<try>= value3\n\n[anotherse</try>
<fail/>
</skip>
<skip>
<try> value3\n\n[anothersec</try>
<success>value3\n\n[anothersect</success>
<attributes>[]</attributes>
</skip>
<skip>
<try>value3\n\n[anothersect</try>
<fail/>
</skip>
<value>
<try>value3\n\n[anothersect</try>
<success>\n\n[anothersection]\nk</success>
<attributes>[[v, a, l, u, e, 3]]</attributes>
</value>
<success>\n\n[anothersection]\nk</success>
<attributes>[[[k, e, y, 3], [v, a, l, u, e, 3]]]</attributes>
</pair>
<pair>
<try>\n\n[anothersection]\nk</try>
<skip>
<try>\n\n[anothersection]\nk</try>
<fail/>
</skip>
<skip>
<try>\n[anothersection]\nke</try>
<fail/>
</skip>
<skip>
<try>[anothersection]\nkey</try>
<fail/>
</skip>
<skip>
<try>[anothersection]\nkey</try>
<fail/>
</skip>
<key>
<try>[anothersection]\nkey</try>
<fail/>
</key>
<fail/>
</pair>
<success>\n\n[anothersection]\nk</success>
<attributes>[[[[k, e, y], [v, a, l, u, e]], [[k, e, y, 2], [v, a, l, u, e, 2]], [[k, e, y, 3], [v, a, l, u, e, 3]]]]</attributes>
</pairs>
<success>\n\n[anothersection]\nk</success>
<attributes>[[[s, e, c, t, i, o, n, n, a, m, e], [[[k, e, y], [v, a, l, u, e]], [[k, e, y, 2], [v, a, l, u, e, 2]], [[k, e, y, 3], [v, a, l, u, e, 3]]]]]</attributes>
</query>
<skip>
<try>\n\n[anothersection]\nk</try>
<fail/>
</skip>
<skip>
<try>\n[anothersection]\nke</try>
<fail/>
</skip>
<skip>
<try>[anothersection]\nkey</try>
<fail/>
</skip>
<query>
<try>[anothersection]\nkey</try>
<skip>
<try>[anothersection]\nkey</try>
<fail/>
</skip>
<name>
<try>[anothersection]\nkey</try>
<success>\nkey = value\n</success>
<attributes>[[a, n, o, t, h, e, r, s, e, c, t, i, o, n]]</attributes>
</name>
<pairs>
<try>\nkey = value\n</try>
<pair>
<try>\nkey = value\n</try>
<skip>
<try>\nkey = value\n</try>
<fail/>
</skip>
<skip>
<try>key = value\n</try>
<fail/>
</skip>
<skip>
<try>key = value\n</try>
<fail/>
</skip>
<key>
<try>key = value\n</try>
<success> = value\n</success>
<attributes>[[k, e, y]]</attributes>
</key>
<skip>
<try> = value\n</try>
<success>= value\n</success>
<attributes>[]</attributes>
</skip>
<skip>
<try>= value\n</try>
<fail/>
</skip>
<skip>
<try> value\n</try>
<success>value\n</success>
<attributes>[]</attributes>
</skip>
<skip>
<try>value\n</try>
<fail/>
</skip>
<value>
<try>value\n</try>
<success>\n</success>
<attributes>[[v, a, l, u, e]]</attributes>
</value>
<success>\n</success>
<attributes>[[[k, e, y], [v, a, l, u, e]]]</attributes>
</pair>
<pair>
<try>\n</try>
<skip>
<try>\n</try>
<fail/>
</skip>
<key>
<try></try>
<fail/>
</key>
<fail/>
</pair>
<success>\n</success>
<attributes>[[[[k, e, y], [v, a, l, u, e]]]]</attributes>
</pairs>
<success>\n</success>
<attributes>[[[a, n, o, t, h, e, r, s, e, c, t, i, o, n], [[[k, e, y], [v, a, l, u, e]]]]]</attributes>
</query>
<skip>
<try>\n</try>
<fail/>
</skip>
<query>
<try></try>
<name>
<try></try>
<fail/>
</name>
<fail/>
</query>
<skip>
<try>\n</try>
<fail/>
</skip>
这篇关于提振精神语法EOL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!