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
其簡潔程度完全不同。