这次展示如何将一个服务器端的C++类让客户端调用。使用早上刚刚开发完的工具,用户可以不用处理任何传输过程中的连接和编码解码等操作。这次实现一个四则运算的语法分析器,客户端发送表达式,服务器端传回语法树(继承树那个模型),客户端将语法树传回去,服务器端传回运算结果。
首先在服务器端定义语法树:
1 class Expression : public VL_Base
2 {
3 public:
4 typedef VL_AutoPtr<Expression> Ptr;
5
6 virtual VDouble Evaluate()
7 {
8 return 0;
9 }
10 };
11
12 class NumberExpression : public Expression
13 {
14 public:
15 VDouble Number;
16
17 NumberExpression()
18 {
19 Number=0;
20 }
21
22 NumberExpression(VDouble aNumber)
23 {
24 Number=aNumber;
25 }
26
27 VDouble Evaluate()
28 {
29 return Number;
30 }
31 };
32
33 enum BinaryType
34 {
35 btAdd,
36 btSub,
37 btMul,
38 btDiv
39 };
40
41 class BinaryExpression : public Expression
42 {
43 public:
44 Expression::Ptr Left;
45 Expression::Ptr Right;
46 BinaryType Type;
47
48 BinaryExpression()
49 {
50 Type=btAdd;
51 }
52
53 BinaryExpression(Expression::Ptr aLeft , Expression::Ptr aRight , BinaryType aType)
54 {
55 Left=aLeft;
56 Right=aRight;
57 Type=aType;
58 }
59
60 VDouble Evaluate()
61 {
62 switch(Type)
63 {
64 case btAdd:
65 return Left->Evaluate()+Right->Evaluate();
66 case btSub:
67 return Left->Evaluate()-Right->Evaluate();
68 case btMul:
69 return Left->Evaluate()*Right->Evaluate();
70 case btDiv:
71 return Left->Evaluate()/Right->Evaluate();
72 default:
73 return 0;
74 }
75 }
76 };
其次使用Combinator写一个语法分析器:
1 enum TokenType
2 {
3 ttNumber,
4 ttAdd,
5 ttSub,
6 ttMul,
7 ttDiv,
8 ttLeft,
9 ttRight
10 };
11
12 Expression::Ptr CreateNumber(const VL_CpToken& Token)
13 {
14 return new NumberExpression(VUnicodeString(Token.Start,Token.Length).ToDouble());
15 }
16
17 Expression::Ptr CreateBinary(const VL_CpPair<Expression::Ptr , VL_CpList<VL_CpPair<VL_CpToken , Expression::Ptr>>>& Input)
18 {
19 Expression::Ptr Result=Input.First;
20 VL_CpList<VL_CpPair<VL_CpToken , Expression::Ptr>>::Node::Ptr Current=Input.Second.Head;
21 while(Current)
22 {
23 switch(Current->Data.First.ID)
24 {
25 case ttAdd:
26 Result=new BinaryExpression(Result,Current->Data.Second,btAdd);
27 break;
28 case ttSub:
29 Result=new BinaryExpression(Result,Current->Data.Second,btSub);
30 break;
31 case ttMul:
32 Result=new BinaryExpression(Result,Current->Data.Second,btMul);
33 break;
34 case ttDiv:
35 Result=new BinaryExpression(Result,Current->Data.Second,btDiv);
36 break;
37 }
38 Current=Current->Next;
39 }
40 return Result;
41 }
42
43 class ExpressionParser
44 {
45 public:
46 Expression::Ptr Parse(VUnicodeString Input)
47 {
48 VL_CpLexer Lexer;
49 Lexer
50 <<Token(false,_UnsignedFloat,ttNumber)
51 <<Token(false,L"+",ttAdd)
52 <<Token(false,L"-",ttSub)
53 <<Token(false,L"*",ttMul)
54 <<Token(false,L"/",ttDiv)
55 <<Token(false,L"(",ttLeft)
56 <<Token(false,L")",ttRight)
57 ;
58
59 typedef VL_CpLexedTypes<Expression::Ptr> Types;
60 Types::Rule Factor,Term,Expr;
61
62 Factor=(CreateNumber<<=Token(ttNumber))||(Token(ttLeft)>Expr<Token(ttRight));
63 Term=CreateBinary<<=(Factor+**((Token(ttMul)||Token(ttDiv))+Factor));
64 Expr=CreateBinary<<=(Term+**((Token(ttAdd)||Token(ttSub))+Term));
65 Types::Parser Parser=Expr;
66
67 VL_CpLexer::_Result LexerResult=Lexer.Parse(Input.Buffer());
68 if(LexerResult.First.Head && !LexerResult.Second.First)
69 {
70 Types::Parser::_FullResult ParserResult=Parser.Parse(LexerResult.First.Head,true);
71 if(ParserResult.Head)
72 {
73 return ParserResult.Head->Data.First;
74 }
75 }
76 return 0;
77 }
78
79 VDouble Evaluate(Expression::Ptr Expr)
80 {
81 return Expr->Evaluate();
82 }
83 };