TPL基础文法

 原文连接:http://blog.csdn.net/xushiweizh/article/details/2606892

操作符(规则组合)
R1 + R2
R1 + R2 表示顺序匹配:匹配 R1 成功后继续匹配 R2。编译原理中一般以 R1 R2 表示(很遗憾,C++没有operator空格)。这应该是使用最多的文法了。

例如:要匹配html标签开始,也就是<tag>,这样写:'<' + html_symbol() + '>'。

R1 | R2
R1 | R2 表示如果 R1 匹配不成功,则匹配 R2。两者只要一个匹配成功就表示成功。

例如:要匹配C++中的类/结构体声明,也就是:

class/struct ClassName;

我们可以这样写:

(str("class") | str("struct")) + ws() + c_symbol() + skipws() + ';'

这里,ws()表示匹配>=1个空白字符,skipws()表示匹配>=0个空白字符。class/struct关键字和类名之间空白 是必须的,所以用ws(),而类名和;之间空白不是必须的,故而用skipws()。另外,str("class") | str("struct")可以缩写为str("class", "struct"),不过这不是我们要讨论的话题。

+R
+R 表示匹配规则 R 1次以上。编译原理中习惯以 R+ 表示。

例如:要匹配一个无符号整数,我们这样写: +digit()。

当然,对于这个例子,你其实不需要用+,因为我们已经提供了 u_integer() 规则了。

!R
!R 表示匹配规则 R 1次或0次。编译原理中习惯以 R? 表示,不过C++没有operator?,很遗憾。

例如:要匹配一个带符号整数,我们这样写:!(ch('+') | ch('-')) + u_integer()。

同str一样,ch('+') | ch('-') 可缩写为 ch('+', '-')。故此本例可简写为 !ch('+', '-') + u_integer()。

当然,对于这个例子,你其实不需要用!,因为我们已经提供了 integer() 规则了。

*R
*R 表示匹配规则 R 0次以上。编译原理中习惯以 R* 表示。

R1 % R2
R1 % R2 匹配一个列表。它等价于 R1 + *(R2 + R1)。

例如:要匹配一个空格分割的浮点数列表,如“1.2 1.3 2.4 3 23.01",你只需要用 real() % ws() 即可。这里用了 ws(),这就允许中间的空白可以是一个或多个。如果只允许一个空格,那么用 real() % ' ' 即可。

~R
~R 表示匹配一个非R规则的字符。R规则要求是匹配单字符的规则。例如 ~(ch('+') | ch('-')) 表示匹配任一个非+或-的字符。

未完待续。。。

TPL的基础规则
ch(Char)
ch(Char) 规则用于匹配一个字符。例如ch('<')表示匹配单个字符'<'。当 ch(Char) 规则与其他规则连用时,可简写为 Char。

例如,我们前面介绍了匹配html标签开始,也就是<tag>,这样写:'<' + html_symbol() + '>'。其实它是 ch('<') + html_symbol() + ch('>') 的缩写。

ch(Char1, Char2), ch(Char1, Char2, Char3)
它只是 ch(Char1) | ch(Char2) 和 ch(Char1) | ch(Char2) | ch(Char3) 的简写。

ch_any()
ch_any() 规则匹配任意一个字符。除非当前已经到达文档结尾,否则该规则总返回成功。

ch_range<Char1, Char2>()
ch_range<Char1, Char2>() 规则表示一个字符区间。如 ch_range<'a', 'z'>() 表示所有小写字母。你可以理解ch_range<Char1, Char2>()为ch(Char)的组合。例如 ch_range<'0', '9'>() 等价于 ch('0') | ch('1') | ch('2') | ch('3') | ch('4') | ch('5') | ch('6') | ch('7') | ch('8') | ch('9')。当然这只是逻辑上的等价,性能后者会差很多。

peek(Char)
peek(Char) 规则用于向前看一个字符(但并不移动匹配的当前指针)。例如peek('<')表示要求文档当前位置的字符必须为'<'。

peek(CharSet), peek(Char1, Char2), peek(Char1, Char2, Char3)
peek规则也允许传入任意的匹配单字符的规则。例如,peek(~ch('+', '-')) 要求文档当前位置的字符必须为非'+'或'-'的字符。 peek(Char1, Char2) 是 peek(ch(Char1) | ch(Char2)) 的缩写。peek(Char1, Char2, Char3) 类似。

str(String)
str(String) 规则用于匹配一个常量字符串。你仍然可以理解为是 ch(Char) 的组合。例如 str("class") 等价于 ch('c') + ch('l') + ch('a') + ch('s') + ch('s')。同ch(Char)类似,当str(String)规则与其他规则连用时,可简写为 String。

find<bEat>(CharSet)
find<bEat>(CharSet) 规则用于查找头一个存在于CharSet中的字符。如果bEat为true,那么find规则同时匹配该字符(匹配的当前位置将指向该字符的后一个位 置)。如果bEat为false,那么find匹配到该字符所在位置。默认bEat=false。也就是说find(CharSet)等价于 find<false>(CharSet)。

find规则同样可以用ch规则实现。例如,find<true>(ch('+', '-')) 等价于 *~ch('+', '-') + ch('+', '-')。不过 find<false>(ch('+', '-')) 与 *~ch('+', '-') 并不等同,区别在于如果找不到'+'或'-'字符,find<false>(ch('+', '-')) 将匹配失败,而 *~ch('+', '-') 将匹配到文档尾并匹配成功。所以需要注意的是,find<false>(ch('+', '-')) 等同于 *~ch('+', '-') + peek('+', '-'),不是 *~ch('+', '-')。

find<bEat>(String)
find<bEat>(String) 规则用于在文档中查找字符串的第一次出现位置(从当前匹配位置开始算)。例如,要匹配C语言的注释/* … */,你可以用 "/*' + find<true>("*/")。

规则的组合
以上介绍的ch, peek, str, find操作是TPL的基础规则。有了他们,你可以做出非常复杂的匹配模式。这里举一些例子进行说明。

integer()
匹配一个整数。它等价于: !ch('+', '-') + (+ch_range<'0', '9'>())。

c_symbol()
匹配一个C符号(变量名)。它等价于:(ch_range<'a', 'z'>() | ch_range<'A', 'Z'>() | '_') + *(ch_range<'a', 'z'>() | ch_range<'A', 'Z'>() | ch_range<'0', '9'>() | '_')。

其他
我们提供了很多很多的现成的规则,而且它们确确实实是这些基础规则的组合得到的,而不是通过实现一个自定义的匹配函数完成。虽然所有的匹配规则你都可以通过写匹配函数完成,但是那样的话就放弃了TPL最强悍的武器了。

目前已经提供的组合规则如下(不断更新中):

匹配单字符的规则
non_eol_space()    匹配一个非行结束的空白字符。
space()    匹配一个空白字符。
alpha()    匹配一个字母。即[A-Za-z]。
lower()    匹配一个小写字母。即[a-z]。
upper()    匹配一个大写字母。即[A-Z]。
digit()    匹配一个10进制数字。即[0-9]。
xdigit()    匹配一个16进制数字。即[0-9a-fA-F]。
oct_digit()    匹配一个8进制数字。即[0-7]。
bin_digit()    匹配一个2进制数字。即[01]。
匹配多字符的规则
ws()    匹配>=1个空白字符。
skipws()    匹配>=0个空白字符。
non_eol_ws()    匹配>=1个非行结束的空白字符。
skip_non_eol_ws()    匹配>=0个非行结束的空白字符。
strict_eol()    匹配一个行结束。行结束不一定是单字符的。可以是/r/n, /r, /n等情况。
eol()    匹配一个行结束或文档结束。即 strict_eol() | eos()。
xml_symbol()    匹配一个XML的符号。
u_integer()    匹配一个无符号整数。
hex_integer()    匹配一个16进制无符号整数。注意,它并不匹配C/C++中的16进制数0xXXXX的前缀0x。如果你希望这样,应该用c_hex_integer() 而不是 hex_integer()。
oct_integer()    匹配一个8进制无符号整数。
bin_integer()    匹配一个2进制无符号整数。
integer()    匹配一个有符号整数。
u_strict_real()    匹配一个无符号的实数/浮点数。该实数是严格的浮点数,不能是整数。
strict_real()    匹配一个有符号的实数/浮点数。该实数是严格的浮点数,不能是整数。
u_real()    匹配一个无符号的实数/浮点数。即 u_strict_real() | u_integer()。
real()    匹配一个有符号的实数/浮点数。即 strict_real() | integer()。
t_year()    匹配年份。即yyyy或者yy。其中y是[0-9]。
t_month()    匹配月份。即mm或者m。其中m是[0-9]。目前我们并不限定其取值范围必须为1~12。但不排除以后可能会这样去限制。
t_day()    匹配天。
t_hour()    匹配小时。
t_minute()    匹配分钟。
t_second()    匹配秒。
C/C++文法
c_symbol()    匹配一个C/C++的符号。即 [A-Za-z_][A-Za-z0-9_]*。
cpp_single_line_comment<bEatEol>()    匹配C++的//风格的注释。bEatEol为true时匹配行结束符,否则保留行结束符。和前面的find规则类似,默认bEatEol为false。
c_comment()    匹配C的/* … */风格的注释。
cpp_comment<bEatEol>()    匹配C/C++的注释。即c_comment() | cpp_single_line_comment<bEatEol>()。
c_skip()    忽略空白或C风格注释。即 *(ws() | c_comment())。
c_skip_non_eol()    忽略非行结束的空白字符或注释。即 *(non_eol_ws() | c_comment())。该规则适合于C预处理指令的匹配。
cpp_skip()    忽略空白或C/C++注释。即 *(ws() | cpp_comment<true>()。
c_string()    匹配C/C++的字符串常量。即 "…"。注意并不包括L"…"中的L。
c_char()    匹配C/C++的字符常量。即 '…'。注意并不包括 L'…'中的L。
c_string_or_char()    即c_string() | c_char()。
c_hex_integer()    C/C++中的16进制数常量。即0xXXXX。注意并不包括0xXXXXL中的L。
c_oct_integer()    C/C++中的8进制数常量。即0XXXX。注意并不包括0XXXXL中的L。
c_u_integer()    C/C++中的无符号整数。即 c_hex_integer() | c_oct_integer() | u_integer()。
c_integer()    C/C++中的带符号整数。即 c_hex_integer() | c_oct_integer() | integer()。
HTML文法
html_space()    匹配一个HTML中的空白字符。
html_ws()    即+html_space()。
html_skipws()    即*html_space()。
html_symbol()    匹配一个HTML的符号。
html_value()    匹配HTML的属性值。
html_property()    匹配HTML的属性。包括名和值的对。注意值是可选的,HTML中可能出现一个属性有名无值。如 <div clear> 这样的标签。
html_u_integer()    匹配HTML的无符号整数。即#xXXXX(16进制)或者 #XXXX(10进制)。
html_entity()    匹配HTML的一个实体。如&lt; &nbsp; 等命名实体。注意它也可以匹配非命名的实体。如&#63; 等。
html_comment()    匹配一个HTML的注释。即 <!— … >。
html_uncommented_script_code()    未被<! … >注释的script代码。
html_commented_script_code()    被<!— … >注释的script代码。注意不包含注释开始<!和结尾>。
html_script_code()    匹配一个HTML的script段。即:html_uncommented_script_code() | "<!" + html_commented_script_code() + ">"。
html_script_codes()    匹配多个HTML的script段。即 *html_script_code()。
关于 html script code。有些复杂的东西需要解释。看这样一段HTML代码:

<script>
    var hello="Hello, <script>!";
    alert(hello);
<!--
    var hello='Hello, </script>-->!';
    alert(hello);
-->
</script> 
这里包含了两段html script code。一段是未注释的,一段是被<!— … ->注释的。要匹配这段文本,可以用"<script>" + html_script_codes() + "</script>"。注意我们用的是html_script_codes(),不是html_script_code()。也就是说, <script>标签中可以包含多个html script code,而不是一个。

一些特殊的规则
这些规则是少数的哪些非组合出来的规则。它们都极其简单,并在一些特殊的场合中使用。

eps(), nothing()
eps() 规则不进行任何匹配,直接返回成功。nothing()类似于eps(),也不进行任何匹配,但返回匹配失败。后文介绍它们的典型用例。

虽然我们没有这么做,但是用前面的基础规则组合出 eps() 和 nothing() 是可能的。实际上 eps() 等价于 peek(ch_any() | EOF),而 nothing() 则等价于 peek(~(ch_any() | EOF))。

eos(), eof()
eos(), eof() 是同一个规则的两个名字。当匹配的当前位置已经到达文档结束位置,eos()/eof() 返回匹配成功。

之所以有两个名字,是因为当你把待匹配的文档看作一个流(stream),那么文档结束就是eos(end of stream)。当你把文档看作是一个文件,那么文档结束就是eof(end of file)。

虽然我们没有这么做,但是同样地,eos()/eof()可以被组合出来。实际上 eos()/eof() 就等价于 peek(EOF)。

eos()/eof() 非常有用。例如,integer() + eos() 表示整个文档只包含一个整数。而规则 integer() 则仅仅表示文档的开始有一个整数。

not_eos(), not_eof()
与eos()/eof() 相反,如果当前位置不是文档尾,not_eos()/not_eof() 匹配成功。

done()
done() 规则的作用是将当前匹配指针移动到文档尾,并返回匹配成功。你可能需要一个fail()规则类表示相反的事情:匹配失败。但是我们目前没有这样的函数。要达到这样的目的。我建议你这样做:

bool bFail = false;
 
... + done()/assign(bFail, true) // 在需要返回失败的时候置bFail为false。关于operator/和assign动作,参阅后文。 
done() 规则也是可以被组合的。它等价于 find(EOF)。但这种等价只是逻辑上的,find(EOF) 的性能会比 done() 慢许多。

 

猜你喜欢

转载自blog.csdn.net/mzr122/article/details/89918001