??xml version="1.0" encoding="utf-8" standalone="yes"?> q是使用Xpressive动态语义定义的例子Q其中sregex::compile函数~译一个表C正则文法的Ԍq返回一个正则对象sregex 如果惛_一个串中查扄合该文法的子Ԍ可以使用regex_searchQ用法和regex_match一P此外q可以用regex_replace来进行替换?br> q将定义一个表C金额的Ԍ其中_d表示一个数字,相当于串 $\d+.\d\d q样s表示为用括号括v来的re expression定义了一个四则表辑ּQ注意其中group的定义?br>q里必须使用by_ref是因为Xpressive默认是值拷贝,如果q里使用默认的方式,那么会造成一个无限@环?br>
我们先来看一个例子:
#include <boost/xpressive/xpressive.hpp>
using namespace boost::xpressive;
int main()
{
std::string hello( "hello world!" );
sregex rex = sregex::compile( "(\\w+) (\\w+)!" );
smatch what;
if( regex_match( hello, what, rex ) )
{
std::cout << what[0] << '\n'; // whole match
std::cout << what[1] << '\n'; // first capture
std::cout << what[2] << '\n'; // second capture
}
return 0;
}
使用regex_match来用这个正则对象匹配一个串。结果储存在what?br>其中what[0]q回整个Ԍwhat[1]~what[n]q回文法中用于标记的部分(用小括号括v来的部分)
最后将输出
hello world!
hello
world
静态文法:
Xpressive除了可以用compile来分析一个文法串之外Q还可以用类gSpirit的方式来静态的指定文法Q?br>sregex re = '$' >> +_d >> '.' >> _d >> _d;
q样定义文法比之前的动态定义更加高效,q且q有一个附加的好处Q?br>分定义Q?/p>
sregex re = '$' >> +_d >> '.' >> _d >> _d;
sregex s = '(' >> re >> ')';
通过分定义Q文法能被表C的更加清楚?br>更加的是,分定义q可以向后引用,因此能够分析EBNFsregex group, factor, term, expression;
group = '(' >> by_ref(expression) >> ')';
factor = +_d | group;
term = factor >> *(('*' >> factor) | ('/' >> factor));
expression = term >> *(('+' >> term) | ('-' >> term));
Xpressive可以在这里下?br>http://boost-consulting.com/vault/index.php?PHPSESSID=f1d4af8b742cfa7adae7aab373cfc535&direction=0&order=&directory=Strings%20-%20Text%20Processing&PHPSESSID=f1d4af8b742cfa7adae7aab373cfc535
内有详细的文?/p>
]]>
]]>
group ::='('exp ')'
factor ::=integer| group
term ::=factor(('*'factor)|('/'factor ))*
exp ::=term(('+'term)|('-'term ))*
q是一个整数表辑ּ的EBNF。该D|q用spirit在C++中的实现则是Q?br>
q里使用=代替::=, ?gt;>代替I格q接。ƈ且由于C++语法所限,EBNF中后|的*在spirit中改为前|?br>{式左边的单词被UCؓ一个ruleQ等式右边ؓrule的定义。我们可以看Z个group是一个exp加上一ҎP一个factor是一个整数或者一个group,一个term是一个或多个factor?/q接Q一个exp是一个或多个term?-q接。处于最端的exp可以据此识别Z下表辑ּ
得到一个rule之后Q我们就可以?/font> parse函数对一个串q行识别了。例?br>
该函数返回一个结构parse_infoQ可以通过讉K其中的full成员来判断是否成功识别,也可以访问stop成员来获知失败的位置。这里要特别提一点,关于各个W号之间的空|spirit的文档的正文说的是给parse再传一个参数space_pQ通知parse跌所有的I格Q然而在FAQ中又提到Q如果用以上方法定义ruleQ第三个参数传space_p会失败。原因是使用rule默认定义的规则被UCؓcharacter level parsingQ即字符U别解析Q而parse的第3个参C适用于phrase level parsingQ即语法U别解析。要使用W?个参数可以有几种Ҏ?br> 1。在parse的第二个参数直接传入一个EBNF表达式,不创建rule对象?br>
2。以rule<phrase_scanner_t>创徏rule?br>
注意虽然可以用这两个办法屏蔽I格Q但是这样可能完全改变EBNF文法的语义,其是在语言本n需要识别空格的时候。对于这U情况,可以不用第三个参数Qƈ在需要出现空格的地方加上space_p,或?space_p?space_pQ其??分别表示后面的符可l出Cơ以上和0ơ以上。例如一个以I格分隔的整数列表可以写成int_p >> *(+space_p >> int_p)
如上使用parse可以识别一个串Q但q不能做更多的操作,例如语法里的各个成分提取出来。对于这L需求,可以通过actor实现。下面是使用actor的一个简单例?br>
注意?span class=identifier>real_p后面的[]Q中括号里面是一个仿函数Q函数指针或者函数对象)Q该仿函数具有如下调用型?br>
一旦spase发现了匹?span class=identifier>real_p的子Ԍ׃调用该functor。不同的rule可能会对应不同的调用型别?/span>
W一个型别针对一般规则,first和lastZ个指向字W的q代器(一般ؓchar*Q?匚w的子串ؓ[first, last)
W二个型别针Ҏ字型规则Q如real_p和int_p, 参数val是一个数字类型?br>W三个性别针对单字W型规则Q如space_p, 参数ch是一个字W类型?br>real_p[push_back_a(v)]中的push_back_a是一个spirit已经定义好的functorQ它会将匚w好的内容依照匚w到的旉序调用v的push_back函数加入到v中?br>
到此spirit的常用功能就都介l完了。要详细深入了解可以参考spirit的文?br>
最后在题一个注意要炏Vspirit的各UEBNFq接都是指针q接Q因此才能在expression被赋值前在group的定义里面用。所以在使用EBNF的时候一定要心不要局部变量的rule提供l全局或者类成员变量使用Q例如:
如果真想使用局部作用域Q可以在局部的rule前面加上static.