随笔-341  评论-2670  文章-0  trackbacks-0
    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 

    其简洁程度完全不同。
posted on 2011-06-13 23:01 陈梓瀚(vczh) 阅读(2946) 评论(0)  编辑 收藏 引用 所属分类: VL++3.0开发纪事

评论:
# re: Vczh Library++3.0之如何把C#属性parse出来的超长pair链表赋值到语法书上 2011-06-13 23:17 | 空明流转
你何苦呢,C++11就可以了。  回复  更多评论
  
# re: Vczh Library++3.0之如何把C#属性parse出来的超长pair链表赋值到语法书上 2011-06-13 23:34 | 陈梓瀚(vczh)
@空明流转
0x也解决不了这个问题。  回复  更多评论
  
# re: Vczh Library++3.0之如何把C#属性parse出来的超长pair链表赋值到语法书上 2011-06-14 01:17 | bennycen
Orz<Orz<Orz<Orz<Orz<Orz<Orz> > > > > >  回复  更多评论
  
# re: Vczh Library++3.0之如何把C#属性parse出来的超长pair链表赋值到语法书上 2011-06-14 04:41 | 空明流转
@空明流转
pair list, 可以换做varadic template...  回复  更多评论
  
# re: Vczh Library++3.0之如何把C#属性parse出来的超长pair链表赋值到语法书上 2011-06-15 01:07 | 陈梓瀚(vczh)
@空明流转

tuple<a, b, ...> -> tuple<pair<a, b>, ...>
tuple<a, b> -> pair<a, b>

?  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理