随笔 - 31  文章 - 128  trackbacks - 0
<2006年7月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

常用链接

留言簿(5)

随笔分类(38)

随笔档案(31)

收藏夹(4)

College

High School

最新随笔

搜索

  •  

积分与排名

  • 积分 - 54989
  • 排名 - 411

最新评论

  • 1. re: [yc]详解link
  • 面试的时候面试官就问过我什么是编译和链接,我说编译就是把代码文件生成目标文件,链接就是把目标文件生成可执行文件,他说不对,又问我什么是动态链接,还问我预编译都做什么处理。。。都在这里找到了答案!!!!
  • --王至乾
  • 2. re: [yc]详解link
  • @刘伟
    我是说博主,不是叫你啊
  • --溪流
  • 3. re: [yc]详解link
  • 谁是石老师,我不是哈@溪流
  • --刘伟
  • 4. re: [yc]详解link
  • 石老师?我是溪流~
  • --溪流
  • 5. re: [yc]详解link
  • 期待楼主下文啊,多谢楼主了
  • --刘伟

阅读排行榜

评论排行榜

     摘要:   1。符号查找(对于函数此时只看名字,不看参数)    大致顺序是    (1)如果有限定名( XXX:: )那么就直接在XXX里查找    (2)函数局部名字空间    (3)(如果是成员)类名字空间    (4)递归向上至所有基类的...  阅读全文
posted @ 2006-12-27 11:04 shifan3 阅读(2096) | 评论 (8)编辑 收藏


发信人: shifan (学习浮云技术), 板面: C++
标  题: 伪typeof
发信站: 飘渺水云间 (Tue Dec 19 16:38:45 2006), 转信
 1 /*
 2 用标准C++实现typeof是不可能的
 3 这个是我写的一个approached typeof
 4 所有需要被静态反射出来的类型必须先用DECL_TYPE注册
 5 模板如果仅仅带有1个参数可以用DECL_TEMPLATE_1注册
 6 多个参数的模板还不支持。。
 7 主要是没想好编码
 8 
 9 总共能注册64个类型
10 可以通过MAX_TYPE_NUMBER设置
11 
12 支持的模板嵌套层数大约为32 / log2(MAX_TYPE_NUMBER)
13 MAX_TYPE_NUMBER必须为2的整次数幂
14 */
15 namespace my_typeof
16 {
17 
18   const int MAX_TYPE_NUMBER = 64;
19 
20   template <int N>
21   struct dummy
22   {
23     int a[N];
24   };
25 
26 
27   template <int N, typename Arg1>
28   struct select_by_number_1;
29 
30   template <int N>
31   struct select_by_number
32   {
33     typedef typename select_by_number_1<% MAX_TYPE_NUMBER, typename
34 select_by_number</ MAX_TYPE_NUMBER>::type>::type type;
35   };
36 
37 
38   template <typename T>
39   struct number_of
40   {
41     static const int v = sizeof(generic_f(*(T*)0)) / sizeof(int);
42   };
43 
44 
45 #define DECL_TYPE(T, N) \
46   namespace my_typeof{  \
47   template<>\
48   struct select_by_number<N> \
49   {\
50     typedef T type;\
51   };\
52   dummy <N> generic_f(const T&);}
53 
54 
55 #define DECL_TEMPLATE_1(T, N) \
56   namespace my_typeof{        \
57   template<typename Arg1>\
58   struct select_by_number_1<N, Arg1>\
59   {\
60     typedef T<Arg1> type;\
61   };\
62   template <typename Arg1>\
63   dummy<+ number_of<Arg1>::v * MAX_TYPE_NUMBER > generic_f(const T<Arg1>&);}
64 
65 
66 
67 #define TYPE_OF(x) my_typeof::select_by_number<sizeof(my_typeof::generic_f(x)) /
68 sizeof (int)>::type
69 
70 }
71 
72 
73 //sample
74 #include <iostream>
75 #include <vector>
76 #include <list>
77 
78 
79 DECL_TYPE(int1);
80 DECL_TEMPLATE_1(std::vector, 2);
81 DECL_TEMPLATE_1(std::list, 3);
82 DECL_TYPE(double4)
83 
84 using namespace std;
85 int main(intchar*[])
86 {
87   vector<list<vector<list<double> > > > v1;
88   TYPE_OF(v1) v2;
89   v1 = v2;
90   return 0;
91 }
92 
93 


--
You well 撒法!You well all 撒法!

※ 内容修改:·shifan 于 Dec 21 14:21:57 修改本文内容·[FROM: shifan]
※ 来源:·飘渺水云间 freecity.cn·[FROM: shifan]
posted @ 2006-12-21 14:29 shifan3 阅读(2631) | 评论 (8)编辑 收藏

真令人伤感,每过几年就是离别时。

我站在窗前,无奈的看着朋友们为了工作奔走,
而不能帮上哪怕一点忙。
就像十年前,就像六年前,就像三年前
就像每一次与人擦肩而过却故意目不斜视。
但这一次也许好一点,毕竟我们以后可能还能时常相聚,
而不像现在只能看着从前的好友的博客独自伤感。
那种陌生,令人心碎。

 

posted @ 2006-11-01 00:31 shifan3 阅读(579) | 评论 (4)编辑 收藏

boost的integer/integer_mask.hpp仅仅做了单个位的bit mask
要多个位必须写很多遍high_bit_mask_t
使用low_bits_mask_t也不能完全解决问题
所以自己用Typelist的那种写法写了一个

用法举例
bit_mask<INT_LIST_2(2, 3)>::value返回一个值,该值的第2、3位被置为1
其余位为0

 

  1 
  2 namespace multi_bit_mask
  3 {
  4     namespace details
  5     {
  6 
  7         template <typename T>
  8         struct get_size
  9         {
 10             enum {size = sizeof(T)}; 
 11         };
 12 
 13         template <int Bit>
 14         struct bit_storage
 15         {
 16             typedef typename bit_storage<Bit - 1>::storage_type storage_type;
 17         };
 18 
 19         //---------platform dependency-----------------------
 20 
 21         typedef unsigned int smallest_storage_type;
 22         typedef unsigned long long largest_storage_type;
 23 
 24         
 25 
 26         template <>
 27         struct bit_storage<0>
 28         {
 29             typedef smallest_storage_type storage_type;
 30         };
 31 
 32         template <>
 33         struct bit_storage<get_size<smallest_storage_type>::size * 8>
 34         {
 35             typedef largest_storage_type storage_type;
 36         };
 37 
 38         //disable the 65th bit
 39         template <>
 40         struct bit_storage<get_size<largest_storage_type>::size * 8>
 41         {
 42             typedef void storage_type;
 43         };
 44         
 45         //---------end of platform dependency----------------
 46 
 47 
 48         template <unsigned int N, typename Next>
 49         struct int_list
 50         {
 51             typedef typename bit_storage<N>::storage_type storage_type;
 52             static const storage_type value = N;
 53             typedef Next next;
 54         };
 55 
 56         struct null_type{};
 57 
 58         template<typename T1, typename T2, bool is_first>
 59         struct selector
 60         {
 61             typedef T1 type;
 62         };
 63 
 64         template<typename T1, typename T2>
 65         struct compare_type
 66         {
 67             const static bool is_larger = sizeof(T1) > sizeof(T2);
 68             typedef typename selector<T1, T2, is_larger>::type large_type;
 69             typedef typename selector<T1, T2, !is_larger>::type small_type;
 70         };
 71 
 72 
 73 
 74         template<typename T1, typename T2>
 75         struct selector<T1, T2, false>
 76         {
 77             typedef T2 type;
 78         };
 79 
 80         template <typename List>
 81         class find_largest_storage
 82         {
 83             typedef typename find_largest_storage<typename List::next>::storage_type T1;
 84             typedef typename bit_storage<List::value>::storage_type T2;
 85         public:
 86             typedef typename compare_type<T1, T2>::large_type storage_type;
 87         };
 88 
 89         template <>
 90         class find_largest_storage<null_type>
 91         {
 92         public:
 93             typedef smallest_storage_type storage_type;
 94         };    
 95 
 96         
 97     }
 98 
 99 
100         
101 
102 
103     template <int N>
104     struct single_bit_mask
105     {
106         typedef typename details::bit_storage<N>::storage_type storage_type;
107         static const storage_type value 
108             = static_cast<storage_type>(single_bit_mask<- 1>::value) * 2;
109     };
110 
111     template <>
112     struct single_bit_mask<0>
113     {
114         typedef details::bit_storage<0>::storage_type storage_type;
115         static const storage_type value = 1;
116     };
117 
118     
119     typedef details::null_type null_type;
120 
121     template <int N, typename Next>
122     struct int_list_t : public details::int_list<N, Next> {};
123 
124     template <typename List>
125     struct bit_mask
126     {
127     public:
128 
129         typedef typename details::find_largest_storage<List>::storage_type storage_type;
130     
131         static const storage_type value 
132             = static_cast<storage_type>(single_bit_mask<List::value>::value) 
133             | static_cast<storage_type>(bit_mask<typename List::next>::value);
134     };
135 
136     template <>
137     struct bit_mask<null_type>
138     {
139         typedef details::bit_storage<0>::storage_type storage_type;
140         static const storage_type value = 0;
141     };
142 
143     
144 
145     
146 
147     #define INT_LIST_1(n1) multi_bit_mask::int_list_t<n1, multi_bit_mask::null_type>
148     #define INT_LIST_2(n1, n2) multi_bit_mask::int_list_t<n1, INT_LIST_1(n2) > 
149     #define INT_LIST_3(n1, n2, n3) multi_bit_mask::int_list_t<n1, INT_LIST_2(n2, n3) > 
150     #define INT_LIST_4(n1, n2, n3, n4) multi_bit_mask::int_list_t<n1, INT_LIST_3(n2, n3, n4) > 
151     #define INT_LIST_5(n1, n2, n3, n4, n5) multi_bit_mask::int_list_t<n1, INT_LIST_4(n2, n3, n4, n5) > 
152     #define INT_LIST_6(n1, n2, n3, n4, n5, n6) multi_bit_mask::int_list_t<n1, INT_LIST_5(n2, n3, n4, n5, n6) > 
153     #define INT_LIST_7(n1, n2, n3, n4, n5, n6, n7) multi_bit_mask::int_list_t<n1, INT_LIST_6(n2, n3, n4, n5, n6, n7) > 
154     #define INT_LIST_8(n1, n2, n3, n4, n5, n6, n7, n8) multi_bit_mask::int_list_t<n1, INT_LIST_7(n2, n3, n4, n5, n6, n7, n8) > 
155     
156 }
157 
158 
159 


sample

#include  < iostream >
#include 
" multi_bit_mask.h "
using   namespace  std;
int  main()
{
    cout 
<<  multi_bit_mask::bit_mask < INT_LIST_1( 1 ) > ::value  <<  endl;
    cout 
<<  multi_bit_mask::bit_mask < INT_LIST_5( 0 1 2 3 4 ) > ::value  <<  endl;
    cout 
<<  multi_bit_mask::bit_mask < INT_LIST_7( 0 1 2 3 4 4 2 ) > ::value  <<  endl;
    
posted @ 2006-10-26 23:37 shifan3 阅读(1435) | 评论 (2)编辑 收藏

    近日在学校bbs上与人讨论C++的typeid关键字的实现问题,有人提到type_info的地址是存放在虚表的第一个位置上,颇觉得不妥,于是我在vc2003下实验了一番

    在vc下,使用typeid的时候,如果typeid施加给的类型是没有vptr的class或者根本不是class
那么汇编是
mov  dword ptr [addr],offset A `RTTI Type Descriptor' (42AD40h)
也就是编译器生成一个简单的type_info对象的表,并且在编译期静态决定下标,做一个简单查表操作。

如果typeid的操作对象是具有vptr的class,但是并不是一个引用或者指针的解引用形式,例如

A a;
typeid(a);


那么仍然仅仅会做查表操作


如果typeid的操作对象是具有vptr的class,并且是引用或者指针的解引用形式,例如

* =   new  A;
A
&  r  =   * p;
typeid(
* p);
typeid(r);


那么就会调用一个叫___RTtypeid的函数,并通过某种方法来获取type_info对象
下面是___RTtypeid的反汇编,这里只列出关键的几条指令

0041213E  mov         ecx,dword ptr [inptr]    ;inptr是对象的地址
00412141   mov         edx,dword ptr [ecx] 
00412143   mov         eax,dword ptr [edx - 4
0041215F  mov         ecx,dword ptr [eax
+ 0Ch] 
00412162   mov         dword ptr [ebp - 48h],ecx 
0041216C  mov         eax,dword ptr [ebp
- 48h] 


基本上等价于C语言的

int  a1  =  ( int )p;  // p是对象的地址
int  a2  =   * ( int * )a1  -   4 ;
int  a3  =   * ( int * )a2  +   12 ;
int  a4  =   * ( int * )a3;

 

那么从这段代码可以看出vc下type_info对象的存放位置[如下图]



也就虚表下标为-1的位置上存放了一个指向一个未知的表的指针(暂且将此表命名为runtime_info_table)
runtime_info_table的第4格上存放了type_info对象的地址
至于runtime_info_table里前3格上存放的是什么, 还需要再研究研究
一般来说它们全是0, 但是对于多重虚继承的类, 第二格上会是4, 可能和指针的偏移量有关.

posted @ 2006-10-26 10:46 shifan3 阅读(3330) | 评论 (5)编辑 收藏
Xpressive是一个C++的正则表达式库,目前是Boost的候选库。
Xpressive和Boost.Regex的区别很大。首先,Xpressive是一个纯头文件的库,也是说,在使用之前不需要预先编译。其次,Xpressive支持类似于Spirit的静态语义定义。

我们先来看一个例子:

 

#include <iostream>
#include 
<boost/xpressive/xpressive.hpp>

using namespace boost::xpressive;

int main()
{
    std::
string hello( "hello world!" );

    sregex rex 
= sregex::compile( "(\\w+) (\\w+)!" );
    smatch what;

    
if( regex_match( hello, what, rex ) )
    {
        std::cout 
<< what[0<< '\n'// whole match
        std::cout << what[1<< '\n'// first capture
        std::cout << what[2<< '\n'// second capture
    }

    
return 0;
}

这是使用Xpressive动态语义定义的例子,其中sregex::compile函数编译一个表示正则文法的串,并返回一个正则对象sregex
使用regex_match来使用这个正则对象匹配一个串。结果储存在what内
其中what[0]返回整个串,what[1]~what[n]返回文法中用于标记的部分(用小括号括起来的部分)
最后将输出
     hello world!
     hello
     world

如果想在一个串中查找符合该文法的子串,可以使用regex_search,用法和regex_match一样,此外还可以用regex_replace来进行替换。

 


静态文法:
Xpressive除了可以用compile来分析一个文法串之外,还可以用类似于Spirit的方式来静态的指定文法:

sregex re = '$' >> +_d >> '.' >> _d >> _d;

这将定义一个表示金额的串,其中_d表示一个数字,相当于串 $\d+.\d\d
这样定义文法将比之前的动态定义更加高效,并且还有一个附加的好处:
分级定义:

sregex re = '$' >> +_d >> '.' >> _d >> _d;
sregex s 
= '(' >> re >> ')';

这样s表示为用括号括起来的re
通过分级定义,文法能被表示的更加清楚。
更加棒的是,分级定义还可以向后引用,因此能够分析EBNF

sregex group, factor, term, expression;
group       
= '(' >> by_ref(expression) >> ')';
factor      
= +_d | group;
term        
= factor >> *(('*' >> factor) | ('/' >> factor));
expression  
= term >> *(('+' >> term) | ('-' >> term));

expression定义了一个四则表达式,注意其中group的定义。
这里必须使用by_ref是因为Xpressive默认是值拷贝,如果这里使用默认的方式,那么会造成一个无限循环。


Xpressive可以在这里下载
http://boost-consulting.com/vault/index.php?PHPSESSID=f1d4af8b742cfa7adae7aab373cfc535&direction=0&order=&directory=Strings%20-%20Text%20Processing&PHPSESSID=f1d4af8b742cfa7adae7aab373cfc535
内有详细的文档

posted @ 2006-07-27 16:27 shifan3 阅读(3090) | 评论 (4)编辑 收藏

看了546@C++@Freecity之后,发觉非常有意思,由此产生一些想法

很多时候写一个类的时候,需要多个模版参数,例如一个遗传算法的算法类,需要一个模版参数来指定交配方式,另一个模版参数来指定子代选择的方式,还要一个参数来指定变异的方式。那么一般来说,这个类会写成:

template<class T                                                //描述问题的一个类
        , class CrossPolicy = AvgCrossPolicy                        //杂交方式
        , class SelectPolicy = DefaultSelectPolicy                //子代选择的方式
        , class VariationPolicy = ReverseVariationPolicy>        //变异方式
class Gene
        : private AvgCrossPolicy
        , private SelectPolicy
        , private VariationPolicy
{
        ....
};

这样用户要使用该类的时候,可以直接指定T,就行了,然而如果要指定变异方式,那么就必须把所有的参数都显式的写出来,很不方便

546提供了一种有效的方法,可以让我们仅仅指定变异参数,而不用写出另两个Policy
甚至允许我们以任意的顺序书写几个Policy参数,都不会有问题

预备知识:
TypeList
一个TypeList是一个类型的容器
template <typename Type_, typename Next_>
struct TypeList
{
        typedef Type_ Type;
        typedef Next_ Next;
};
这就是一个TypeList。
看这个写法,是不是像一个链表?
首先定义一个类型来表示链表尾:class NullType{};
现在一个包含了2个类型的TypeList就可以写为:
TypeList<T1, TypeList<T2, NullType>  >

如何在一个TypeList中查找一个类型的子类?
首先要有一个IsDerivedFrom<Base, T>
这个比较简单
template<class Base, class T>
class IsDerivedFrom
{
        struct large{char a[2];};
        static char pred(Base*);
        static large pred(...);
public:
        enum {Is = sizeof(pred((T*)0)) == sizeof(char)};
};

然后FindChild就容易了
template <class List, class Base>
struct FindChild
{
        template <bool IsChild>
        struct Select
        {
                typedef typename List::Type Type;
        };

        template <>
        struct Select<false>
        {
                typedef typename FindChild<typename List::Next, Base>::Type Type;
        };

        typedef typename Select<IsDerivedFrom<Base, typename List::Type> >::Type Type;
};

当然还要对一些特殊情况进行特化,例如NullType
template <class Base>
struct FindChild<NullType, Base>
{
        typedef NullType Type;
};
这里使用NullType来表明没找到

实际操作:
首先需要给3个Policy3个基类,分别叫
class AvgCrossPolicyBase{};
class SelectPolicyBase{};
class VariationPolicyBase{};
内容为空就行了,这样也没有虚函数调用的开销


然后声明一个类来表示默认情况:
class DefaultPolicy{};

定义一个宏
#define TYPELIST_3_N(a, b, c) TypeList<a, TypeList<b, TypeList<c, NullType> > >

下面要写一些选择器,用于把合适的类型选择出来,如果没找到,则要使用默认的类型
template <class List, class Base, class DefaultType>
struct Selector
{
        template <class RetType>
        struct Judge
        {
                typedef RetType Type;
        };
       
        template<>
        struct Judge<NullType>
        {
                typedef DefaultType Type;
        };
        typedef typename Judge<typename FindChild<List, Base>::Type >::Type Type;
};

好啦,现在整个类的声明可以写为

template<class T
        , class CrossPolicy_ = DefaultPolicy
        , class SelectPolicy_ = DefaultPolicy
        , class VariationPolicy_ = DefaultPolicy     //其后的参数用户不可指定
        , class List = TYPELIST_3_N(CrossPolicy_, SelectPolicy_, VariationPolicy_)
        , class CrossPolicy = typename Selector<List, CrossPolicyBase,  AvgCrossPolicy>::Type
        , class SelectPolicy = typename Selector<List,  SelectPolicyBase,  DefaultSelectPolicy>::Type
        , class VariationPolicy = typename Selector<List,  VariationPolicyBase,  ReverseVariationPolicy>::Type
        >
class Gene
        : private CrossPolicy
        , private SelectPolicy
        , private VariationPolicy
{
       
        ....
};


其中第4-7个参数(List,CrossPolicy,SelectPolicy和VariationPolicy)是不由用户指定的,仅仅是为了起一个别名
第一个参数T必须指定,然后2,3,4这3个参数就可以任意的改变顺序了
例如,可以写Gene<T, DefaultSelectPolicy, AvgCrossPolicy>而不会有任何问题
如果不想要最后面几个参数的话也行,但是代码就要稍微长一点
而且最好在类里面进行3个typedef
typedef typename Selector<List, CrossPolicyBase,  AvgCrossPolicy>::Type CrossPolicy;
等,以便在实现的时候使用

posted @ 2006-07-24 01:06 shifan3 阅读(991) | 评论 (9)编辑 收藏
     摘要: 发信人: shifan (家没有豚豚 T.T), 板面: C++标  题: 如何实现Lambda[第二部分]发信站: 飘渺水云间 (Thu Jun  8 23:30:20 2006), 转信 章节:八:第一部分的小结九:简化,如何减少Lambda代码的冗余和依赖性十:bind的实现十一:实现phoenix 八.    中期总结目前的结果是这样的...  阅读全文
posted @ 2006-07-15 15:32 shifan3 阅读(955) | 评论 (0)编辑 收藏
     摘要: 一. 什么是Lambda所谓Lambda,简单的说就是快速的小函数生成。在C++中,STL的很多算法都要求使用者提供一个函数对象。例如for_each函数,会要求用户提供一个表明“行为”的函数对象。以vector<bool>为例,如果想使用for_each对其中的各元素全部赋值为true,一般需要这么一个函数对象,     c...  阅读全文
posted @ 2006-06-09 13:23 shifan3 阅读(2956) | 评论 (7)编辑 收藏

    最近为了解析SQL语法,怀着试一试的心态去翻了翻boost的spirit库,因为该库的文档的简介里写着LL parser framework  represents parsers directly as EBNF grammars in inlined C++。看着framework这个词自然觉得这个库很牛B,试用了一下果然如此。
    所谓EBNF即扩展巴克斯范式,是一种描述Context-Free Language的文法。在目前常见的非自然语言中,大部分都可以用EBNF表示。例如:
      group  ::='('exp
')'
      factor ::=integer|
group
      term   ::=factor(('*'factor)|('/'factor
))*
      exp    ::=term(('+'term)|('-'term
))*
这是一个整数表达式的EBNF。该段描述用spirit在C++中的实现则是:
   

   rule<> group, factor, term, exp;
   group  
= '(' >> exp >> ')';
   factor 
= int_p | group;
   term   
= factor >> *(('*' >> factor) | ('/' >> factor));
   exp    
= term >> *(('+' >> term) | ('-' >> term));

这里使用=代替::=, 用>>代替空格连接。并且由于C++语法所限,EBNF中后置的*在spirit中改为前置。
等式左边的单词被称为一个rule,等式右边为rule的定义。我们可以看出一个group是一个exp加上一对括号,一个factor是一个整数或者一个group,一个term是一个或多个factor用*/连接,一个exp是一个或多个term用+-连接。处于最顶端的exp可以据此识别出以下表达式
   

   12345
   
-12345
   
+12345
   
1 + 2
   
1 * 2
   
1/2 + 3/4
   
1 + 2 + 3 + 4
   
1 * 2 * 3 * 4
   (
1 + 2* (3 + 4)
   (
-1 + 2* (3 + -4)
   
1 + ((6 * 200- 20/ 6
   (
1 + (2 + (3 + (4 + 5))))

    得到一个rule之后,我们就可以用 parse函数对一个串进行识别了。例如
         

         parse( " (1 + (2 + (3 + (4 + 5)))) " , exp);


该函数返回一个结构parse_info,可以通过访问其中的full成员来判断是否成功识别,也可以访问stop成员来获知失败的位置。这里要特别提一点,关于各个符号之间的空格,spirit的文档的正文说的是给parse再传一个参数space_p,通知parse跳过所有的空格,然而在FAQ中又提到,如果使用以上方法定义rule,第三个参数传space_p会失败。原因是使用rule默认定义的规则被称为character level parsing,即字符级别解析,而parse的第3个参数仅适用于phrase level parsing,即语法级别解析。要使用第3个参数可以有几种方法。
      1。在parse的第二个参数直接传入一个EBNF表达式,不创建rule对象。
         

            parse( " hello world " * anychar_p, space_p);  


      2。以rule<phrase_scanner_t>创建rule。
         

            rule < phrase_scanner_t >  exp; 

注意虽然可以用这两个办法屏蔽空格,但是这样可能完全改变EBNF文法的语义,尤其是在语言本身需要识别空格的时候。对于这种情况,可以不使用第三个参数,并在需要出现空格的地方加上space_p,或者+space_p及*space_p,其中+和*分别表示后面的符号连续出现一次以上和0次以上。例如一个以空格分隔的整数列表可以写成int_p >> *(+space_p >> int_p)
   如上使用parse可以识别一个串,但并不能做更多的操作,例如将语法里的各个成分提取出来。对于这样的需求,可以通过actor实现。下面是使用actor的一个简单例子
   

   bool
   parse_numbers(
char const* str, vector<double>& v)
   
{
      
return parse(str,

   
//  Begin grammar
      (
         real_p[push_back_a(v)] 
>> *(',' >> real_p[push_back_a(v)])
      )
      ,
      
//  End grammar
      space_p).full;
   }

注意到real_p后面的[],中括号里面是一个仿函数(函数指针或者函数对象),该仿函数具有如下调用型别
   

   void operator()(IterT first, IterT last) const;
   
void operator()(NumT val) const;
   
void operator()(CharT ch) const;


一旦spase发现了匹配real_p的子串,就会调用该functor。不同的rule可能会对应不同的调用型别。
第一个型别针对一般规则,first和last为两个指向字符的迭代器(一般为char*),匹配的子串为[first, last)
第二个型别针对数字型规则,如real_p和int_p, 参数val是一个数字类型。
第三个性别针对单字符型规则,如space_p, 参数ch是一个字符类型。
real_p[push_back_a(v)]中的push_back_a是一个spirit已经定义好的functor,它会将匹配好的内容依照匹配到的时间顺序调用v的push_back函数加入到v中。

   到此spirit的常用功能就都介绍完了。要详细深入了解可以参考spirit的文档。

最后在题一个注意要点。spirit的各种EBNF连接都是指针连接,因此才能在expression被赋值前就在group的定义里面使用。所以在使用EBNF的时候一定要小心不要将局部变量的rule提供给全局或者类成员变量使用,例如:
   

   class A
   
{
      rule
<> s;
      A()
      
{
         rule
<> r = int_p | hex_p;

         s 
= r >> *(+space_p >> r); //error, r destructed after return 
      }

   }
;

如果真想使用局部作用域,可以在局部的rule前面加上static.

posted @ 2005-12-18 12:02 shifan3 阅读(7079) | 评论 (5)编辑 收藏
仅列出标题
共3页: 1 2 3