使用面向组合子算法写词法分析器
继 《面向组合子的一些测试》 进一步完善代码,制作出词法分析器.
我们首先需要一个Fail基类,他有一个纯虚函数Parser.
1
class
Fail
2 {
3 public :
4 virtual NWString Parser(NWString & input) = 0 ;
5 };
Parser的输入为要分析的字符串,输出为分析完成后剩余的字符串.
2 {
3 public :
4 virtual NWString Parser(NWString & input) = 0 ;
5 };
然后我们需要一个Ch和一个Str分别用来分析单个字符和一个字符串.
1
class
Ch :
public
Fail
2 {
3 public :
4 Ch(WCHAR _value) : value(_value){}
5
6 NWString Parser(NWString & input);
7
8 WCHAR Value();
9 protected :
10 WCHAR value; // 待匹配串
11 };
12
13 class Str : public Fail
14 {
15 public :
16 Str(NWString _value) : value(_value){}
17
18 NWString Parser(NWString & input);
19 protected :
20 NWString value; // 待匹配串
21 };
2 {
3 public :
4 Ch(WCHAR _value) : value(_value){}
5
6 NWString Parser(NWString & input);
7
8 WCHAR Value();
9 protected :
10 WCHAR value; // 待匹配串
11 };
12
13 class Str : public Fail
14 {
15 public :
16 Str(NWString _value) : value(_value){}
17
18 NWString Parser(NWString & input);
19 protected :
20 NWString value; // 待匹配串
21 };
然后是Seq,Alt和Any,分别表示组合,选择和循环.
1
class
Seq :
public
Fail
2 {
3 public :
4 Seq( const NAutoPtr < Fail >& _left, const NAutoPtr < Fail >& _right) : left(_left),right(_right){}
5
6 NWString Parser(NWString & input);
7 protected :
8 NAutoPtr < Fail > left;
9 NAutoPtr < Fail > right;
10 };
11
12 class Alt : public Fail
13 {
14 public :
15 Alt( const NAutoPtr < Fail >& _left, const NAutoPtr < Fail >& _right) : left(_left),right(_right){}
16
17 NWString Parser(NWString & input);
18 protected :
19 NAutoPtr < Fail > left;
20 NAutoPtr < Fail > right;
21 };
22
23 class Any : public Fail
24 {
25 public :
26 Any( const NAutoPtr < Fail >& _left, const int _count) : left(_left),count(_count){}
27
28 NWString Parser(NWString & input);
29 protected :
30 NAutoPtr < Fail > left;
31 int count;
32 };
2 {
3 public :
4 Seq( const NAutoPtr < Fail >& _left, const NAutoPtr < Fail >& _right) : left(_left),right(_right){}
5
6 NWString Parser(NWString & input);
7 protected :
8 NAutoPtr < Fail > left;
9 NAutoPtr < Fail > right;
10 };
11
12 class Alt : public Fail
13 {
14 public :
15 Alt( const NAutoPtr < Fail >& _left, const NAutoPtr < Fail >& _right) : left(_left),right(_right){}
16
17 NWString Parser(NWString & input);
18 protected :
19 NAutoPtr < Fail > left;
20 NAutoPtr < Fail > right;
21 };
22
23 class Any : public Fail
24 {
25 public :
26 Any( const NAutoPtr < Fail >& _left, const int _count) : left(_left),count(_count){}
27
28 NWString Parser(NWString & input);
29 protected :
30 NAutoPtr < Fail > left;
31 int count;
32 };
最后我们需要一个Node类型来存放以上这几类对象.
1
class
Node
2 {
3 public :
4 Node(){}
5 Node( const NAutoPtr < Fail >& _left) : left(_left){}
6
7 friend NAutoPtr < Node > operator + ( const NAutoPtr < Node >& left, const NAutoPtr < Node >& right);
8 friend NAutoPtr < Node > operator | ( const NAutoPtr < Node >& left, const NAutoPtr < Node >& right);
9 friend NAutoPtr < Node > operator - ( const NAutoPtr < Node >& left, const NAutoPtr < Node >& right);
10
11 static NAutoPtr < Node > OnceMore(NAutoPtr < Node > node);
12 static NAutoPtr < Node > More(NAutoPtr < Node > node);
13 static NAutoPtr < Node > NewCh(WCHAR input);
14 static NAutoPtr < Node > NewStr(NWString input);
15
16 NWString Parser(NWString & input);
17
18 NAutoPtr < Fail >& Value();
19 protected :
20 NAutoPtr < Fail > left;
21 };
下面来分析一下Node里的函数:
2 {
3 public :
4 Node(){}
5 Node( const NAutoPtr < Fail >& _left) : left(_left){}
6
7 friend NAutoPtr < Node > operator + ( const NAutoPtr < Node >& left, const NAutoPtr < Node >& right);
8 friend NAutoPtr < Node > operator | ( const NAutoPtr < Node >& left, const NAutoPtr < Node >& right);
9 friend NAutoPtr < Node > operator - ( const NAutoPtr < Node >& left, const NAutoPtr < Node >& right);
10
11 static NAutoPtr < Node > OnceMore(NAutoPtr < Node > node);
12 static NAutoPtr < Node > More(NAutoPtr < Node > node);
13 static NAutoPtr < Node > NewCh(WCHAR input);
14 static NAutoPtr < Node > NewStr(NWString input);
15
16 NWString Parser(NWString & input);
17
18 NAutoPtr < Fail >& Value();
19 protected :
20 NAutoPtr < Fail > left;
21 };
+:对应于Seq,用于将两个Node连接起来.
|:对应与Alt,用于选择两个Node.
-:只有left和right的Value()都是NAutoPtr<Ch>时才可使用,内部有类型转换,表示从哪个字符到哪个字符.
OnceMore:重复1次及以上.
More:重复0次以上.
NewCh:生成一个NAutoPtr<Ch>的Node对象.
NewStr:生成一个NAutoPtr<Str>的Node对象.
下面我们需要4个宏.
1
#define
ONCEMORE(N) Node::OnceMore(N)
2 #define MORE(N) Node::More(N)
3 #define NEWCH(N) Node::NewCh(N)
4 #define NEWSTR(N) Node::NewStr(N)
这4个宏仅为了输入方便
2 #define MORE(N) Node::More(N)
3 #define NEWCH(N) Node::NewCh(N)
4 #define NEWSTR(N) Node::NewStr(N)
然后我们来测试一下:
1
NAutoPtr
<
Node
>
Symbol
=
ONCEMORE(NEWCH(
'
_
'
)
|
NEWCH(
'
a
'
)
-
NEWCH(
'
z
'
))
|
(NEWCH(
'
A
'
)
-
NEWCH(
'
Z
'
))
2 + MORE(NEWCH( ' _ ' ) | (NEWCH( ' 0 ' ) - NEWCH( ' 9 ' )) | (NEWCH( ' a ' ) - NEWCH( ' z ' )) | (NEWCH( ' A ' ) - NEWCH( ' Z ' )));
3 NAutoPtr < Node > Number = ONCEMORE(NEWCH( ' 0 ' ) - NEWCH( ' 9 ' ));
4 NAutoPtr < Node > Real = Number + NEWCH( ' . ' ) + Number;
相信对正则表达式有一定认识的同学已经知道这3条语句分别对应于什么正则表达式.
2 + MORE(NEWCH( ' _ ' ) | (NEWCH( ' 0 ' ) - NEWCH( ' 9 ' )) | (NEWCH( ' a ' ) - NEWCH( ' z ' )) | (NEWCH( ' A ' ) - NEWCH( ' Z ' )));
3 NAutoPtr < Node > Number = ONCEMORE(NEWCH( ' 0 ' ) - NEWCH( ' 9 ' ));
4 NAutoPtr < Node > Real = Number + NEWCH( ' . ' ) + Number;
Symbol->[_a-zA-Z]+[_0-9a-zA-Z]*
Number->[0-9]+
Real->[0-9]+.[0-9]+
定义一个待分析的字符串.
1
NWString str
=
L
"
abcce_fg123.459agetr
"
;
对其分析.
1
wprintf(L
"
%s\n
"
,str);
2 wprintf(L " %s\n " ,Symbol -> Parser(str));
3 wprintf(L " %s\n " ,Real -> Parser(str));
4 wprintf(L " %s\n " ,Symbol -> Parser(str));
2 wprintf(L " %s\n " ,Symbol -> Parser(str));
3 wprintf(L " %s\n " ,Real -> Parser(str));
4 wprintf(L " %s\n " ,Symbol -> Parser(str));
分析结果.
1
abcce_fg123.459agetr
2 123 .459agetr
3 agetr
4
2 123 .459agetr
3 agetr
4
因为没有考虑分析效率问题,所以使用NWString作为输入和输出,在实际使用中可用LPTSTR来代替NWString,同时修改响应代码.
最后给出 源代码