Vczh Library++3.0的ManagedX(山寨C#)语法分析器写好了。将近1000行的语法树声明,使用了ParserCombinator还有93k的语法分析器。写了好久。其中遇到了一些问题,譬如说C#的语法实在太复杂,parse一个method也好property也好都会有一大堆东西。举个例子,一个method的文法如下:
1 (attributeInfo + opt(genericInfo) + accessor + memberType + inheritation + internalExternal +
2 type +
3 opt(type << COLON(NeedColon) << COLON(NeedColon)) + ID(NeedId) +
4 (OPEN_EXP_BRACE(NeedOpenExpBrace) >> plist(opt(parameter + *(COMMA >> parameter))) << CLOSE_EXP_BRACE(NeedCloseExpBrace)) +
5 statement
6 )[ToMethodMember]
7
最顶级的operator+一共有10个,也就是说这个东西的返回结果是pair<pair<pair<pair<pair<pair<pair<pair<pair<pair<a, b>, c>, d>, e>, f>, g>, f>, i>, j>, k>。因此ToMethodMember函数的参数也是这个类型。这显然很令人讨厌。
再举一个例子,property的文法如下:
1 (attributeInfo + accessor + memberType + inheritation + type + opt(type << COLON(NeedColon) << COLON(NeedColon)) + ID(NeedId) +
2 (OPEN_DECL_BRACE(NeedOpenDeclBrace) >> (
3 opt(GET >> statement) +
4 opt(opt(setterAccessor) + (SET >> statement))
5 ) << CLOSE_DECL_BRACE(NeedCloseDeclBrace))
6 )[ToPropertyMember]
7
这个东西的返回结果是pair<pair<pair<pair<pair<a, b>, c>, d>, e>, pair<list<f>, list<list<pair<g, h>>>>。写起来也很令人发疯。因此这几天就想了一种方法来解决这种问题。
首先,我们一定要采取一种方法来让这种火箭一样的代码给平坦化。由于operator+的左结合特性,实际上我们无法去掉这些pair,因此只能换一种方法,譬如说让pair<pair<pair<a, b>, c>, d>总是等价于tuple<a, b, c, d>。这显然是可能的,只需要重载足够数量的tuple类型,就可以让typename tuple<a, b, c, d>::ResultType等于pair<pair<pair<a, b>, c>, d>。
其次,当我们面对这些pair<pair<pair<a, b>, c>, d>的时候,如何将他赋值到一个struct呢?假设struct的声明如下:
1 struct s
2 {
3 a _a;
4 b _b;
5 c _c;
6 d _d;
7 };
我们可以用下面的代码:
1 struct s;
2
3 auto x = ref(s._a)
4 .ref(s._b)
5 .ref(s._c)
6 .ref(s._d)
7 ;
来让x等于pair<pair<pair<*a, *b>, *c>, *d>。因为“点”也是左结合的。后面只需要再用模板元编程就可以把pair<pair<pair<a, b>, c>, d>赋值给pair<pair<pair<*a, *b>, *c>, *d>了。
让我们看看
Vczh Library++3.0源代码(Library\Scripting\Languages\ManagedX\ManagedXParser_Declaration.cpp)在使用了这个构造之前和之后的代码。首先是直接使用和读取pair的:
1 Ptr<ManagedMember> ToPropertyMember(const ParsingPair<ParsingPair<ParsingPair<ParsingPair<ParsingPair<ParsingPair<ParsingPair<
2 Ptr<ManagedAttributeInfo>,
3 declatt::Accessor>,
4 declatt::MemberType>,
5 declatt::Inheritation>,
6 Ptr<ManagedType>>,
7 ParsingList<Ptr<ManagedType>>>,
8 RegexToken>,
9 ParsingPair<
10 ParsingList<Ptr<ManagedStatement>>,
11 ParsingList<ParsingPair<ParsingList<declatt::Accessor>, Ptr<ManagedStatement>>>
12 >>& input)
13 {
14 Ptr<ManagedProperty> member=CreateNode<ManagedProperty>(input.First().Second());
15 CopyAttributeInfo(member->attributeInfo, input.First().First().First().First().First().First().First());
16 member->accessor=input.First().First().First().First().First().First().Second();
17 member->memberType=input.First().First().First().First().First().Second();
18 member->inheritation=input.First().First().First().First().Second();
19 member->type=input.First().First().First().Second();
20 if(input.First().First().Second().Head())
21 {
22 member->implementedInterfaceType=input.First().First().Second().Head()->Value();
23 }
24 member->name=ConvertID(WString(input.First().Second().reading, input.First().Second().length));
25
26 member->setterAccessor=member->accessor;
27 if(input.Second().First().Head())
28 {
29 member->getter=input.Second().First().Head()->Value();
30 }
31 if(input.Second().Second().Head())
32 {
33 if(input.Second().Second().Head()->Value().First().Head())
34 {
35 member->setterAccessor=input.Second().Second().Head()->Value().First().Head()->Value();
36 }
37 member->setter=input.Second().Second().Head()->Value().Second();
38 }
39 return member;
40 }
41
其次是用tuple和ref来赋值的:
1 Ptr<ManagedMember> ToPropertyMember(const x::tp<
2 Ptr<ManagedAttributeInfo>,
3 declatt::Accessor,
4 declatt::MemberType,
5 declatt::Inheritation,
6 Ptr<ManagedType>,
7 x::opt<Ptr<ManagedType>>,
8 RegexToken,
9 x::tp<
10 x::opt<Ptr<ManagedStatement>>,
11 x::opt<x::tp<x::opt<declatt::Accessor>, Ptr<ManagedStatement>>>
12 >
13 >::ResultType& input)
14 {
15 Ptr<ManagedProperty> member=CreateNode<ManagedProperty>(input.First().Second());
16 x::Fill(
17 x::ref(member->attributeInfo)
18 .ref(member->accessor)
19 .ref(member->memberType)
20 .ref(member->inheritation)
21 .ref(member->type)
22 .ref(member->implementedInterfaceType)
23 .ref(member->name)
24 .ref(
25 x::ref(member->getter)
26 .ref(
27 x::ref(member->setterAccessor)
28 .ref(member->setter)
29 )
30 )
31 , input);
32 member->name=ConvertID(member->name);
33 return member;
34 }
35
其简洁程度完全不同。