引言
有了对《TPL基础文法》的了解后,你就可以用TPL去做些事情了。例如,你可以用TPL来验证数据的合法性。
using namespace tpl; std::string str; std::cin >> str; if (str == real()) std::cout << str << " is a real value.\n"; else std::cout << str << " isn't a valid real value. Please input again.";
这个例子是用TPL验证一个输入的字符串是不是合法浮点数。但是这对TPL来说,是牛刀小试(注意我不是说用TPL做这样的事情性能不好,事实上它有很好的性能)。
如果没有本文要介绍的标记(Mark)和动作(Action)(这样我没有提约束(Restriction),是因为它和前两者的目的不同),不足以释放TPL的能量。下面我们一一说明。
为什么这三者会一起说明,原因其实在于它们都用TPL的同一个算符:operator/。operator/具有多种含义,包括:
- 标记(Mark)
- 动作(Action):包括赋值(Assignment)和其他类型的动作
- 约束(Restriction)
本文的主旨就在于给大家展示operator/的多种用途。
标记(Mark)
如果你了解过正则表达式(regex,我希望你了解过,因为这是理解TPL库的基础),应该听说过捕获(Capture)一词。捕获(Capture)其实就是这里的标记(Mark)。它本身不属于正则匹配的语法之一。但是如果一个语法只能匹配,没有办法做标记(Mark)── 捕获有意义的数据,那么显然其能力就有限(可能真的就象前面一样,只能做输入合法性的验证了)。
我们来看下标记(Mark)的具体实例。本样例的代码参见:tpl/examples/json-print/Simplest.cpp。
typedef DOM<> dom;
const char source[] = "\
class Foo // Foo comment\n\
: public Base1, Base2\n\
{};\
";
dom::Mark tagName("name");
dom::NodeMark tagBase("base", true);
dom::Mark tagAccess("access");
//dom::Mark tagName("name");
dom::Allocator alloc;
dom::Document doc(alloc);
source >> cpp_skip_
[
gr(c_symbol_("class")) + c_symbol()/tagName +
!(':' +
(
!gr(c_symbol_("public")/tagAccess) +
c_symbol()/tagName
)/tagBase % ','
) +
'{' + '}' + ';'
]/doc;
std::OutputLog log;
json_print(alloc, log, doc);
这是一个蛮复杂的例子。其中包含了我还没有展开讲的Grammar(语法)的成分。输出结果:
{
"name": "Foo",
"base":
[
{
"access": "public",
"name": "Base1"
},
{
"name": "Base2"
}
]
}
动作(Action)
标记和动作(Mark and Action)是达到同一个目的的两种手段。
引入动作(Action)从哲学上来说是一种无奈之举(虽然有了动作之后,确实很强大)。TPL我多次称之为Text Processing Language,而不是Text Process Library,因为我认为它是一种新的语言。虽然它用C++实现,但是它的理念和C++不同。这是一种描述性的语言,你只需要描述事实,而不是执行命令。但是动作(Action)一定程度上打破了这一哲学。





