1. 程式人生 > >Vczh Library++3.0之如何把C#屬性parse出來的超長pair連結串列賦值到語法書上

Vczh Library++3.0之如何把C#屬性parse出來的超長pair連結串列賦值到語法書上

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