文法分析与解释器模式(二)
这一章建立一个语法分析器
用Stack分析算数表达式最为简单的是后缀表达式,这里简单举个例子:
(a+b)*c-(d/e)==>ab+c*de/- --------------(1)
对于1式我们分析两个变量:a,b入栈然后见到运算符+,pop()两个变量计算(b,a),其结果并入栈,c入栈,见到运算符*,pop()两个变量(c,a+b的结果),d,e入栈,见到运算符/,pop()两个变量(e,d),计算结果并入栈,见到运算符-,pop()两个变量(d/e的结果,(a+b)*c的结果),计算,这个结果就是最终结果。
下面我准备建立一个分析算数表达式的class,名为InToPost, 其间有方法名为Trans(),返回一个Queue类型的值,匹配后缀表达式,比如有(1)式有:
<<a|b|+|c|*|d|e|/|-<<--------箭头方向为出队列的方向
用Stack分析算数表达式最为简单的是后缀表达式,这里简单举个例子:
(a+b)*c-(d/e)==>ab+c*de/- --------------(1)
对于1式我们分析两个变量:a,b入栈然后见到运算符+,pop()两个变量计算(b,a),其结果并入栈,c入栈,见到运算符*,pop()两个变量(c,a+b的结果),d,e入栈,见到运算符/,pop()两个变量(e,d),计算结果并入栈,见到运算符-,pop()两个变量(d/e的结果,(a+b)*c的结果),计算,这个结果就是最终结果。
下面我准备建立一个分析算数表达式的class,名为InToPost, 其间有方法名为Trans(),返回一个Queue类型的值,匹配后缀表达式,比如有(1)式有:
<<a|b|+|c|*|d|e|/|-<<--------箭头方向为出队列的方向
1
class InToPost
2
{
3
Stack<string> stack;
4
Queue<string> temp;
5
string input;
6
string output;
7
public string OutString
8
{
9
get { return output; }
10
}
11
public InToPost(string str)
12
{
13
this.input = str.Trim(); ;
14
stack = new Stack<string>();
15
temp = new Queue<string>();
16
}
17
public int Trans(out Queue<string> st)
18
{
19
string str;
20
if (!Match())
21
{
22
st = null;
23
return 0;
24
}
25
string[] tokens = GetTokens();
26
for (int i = 0; i < tokens.Length; i++)
27
{
28
str = tokens[i];
29
switch (str)
30
{
31
case"":
32
break;
33
case "+":
34
case "-":
35
GetOperator(str, 1);
36
break;
37
case "*":
38
case "/":
39
GetOperator(str, 2);
40
break;
41
case "^":
42
GetOperator(str, 4);
43
break;
44
case "(":
45
stack.Push(str);
46
break;
47
case ")":
48
GetParen(str);
49
break;
50
default:
51
output += str;
52
temp.Enqueue(str); ;
53
break;
54
}
55
}
56
while (stack.Count != 0)
57
{
58
str = stack.Pop();
59
temp.Enqueue(str);
60
output += str;
61
}
62
st = temp;
63
return 1;
64
}
65
private bool Match()
66
{
67
int left = 0, right = 0;
68
for (int i = 0; i < input.Length; i++)
69
{
70
if (input[i] == '(') left++;
71
else if (input[i] == ')') right++;
72
}
73
return left == right;
74
}
75
private void GetOperator(string opThis, int prec1)
76
{
77
while (stack.Count != 0)
78
{
79
string opTop = stack.Pop();
80
if (opTop == "(")
81
{
82
stack.Push(opTop);
83
break;
84
}
85
else
86
{
87
int prec2 = 0;
88
if (opTop == "+" || opTop == "-")
89
{ prec2 = 1; }
90
else if (opTop == "*" || opTop == "/")
91
{ prec2 = 2; }
92
else if (opTop == "^") { prec2 = 4; }
93
94
if (prec2 < prec1)
95
{
96
stack.Push(opTop);
97
break;
98
}
99
else
100
{
101
output += opTop;
102
temp.Enqueue(opTop);
103
}
104
}
105
}
106
stack.Push(opThis);
107
}
108
private void GetParen(string str)
109
{
110
while (stack.Count != 0)
111
{
112
string s = stack.Pop();
113
if (s == "(") break;
114
else { output += s; temp.Enqueue(s); }
115
}
116
}
117
private string[] GetTokens()
118
{
119
input = input.Replace("+", " + ");
120
input = input.Replace("-", " - ");
121
input = input.Replace("*", " * ");
122
input = input.Replace("/", " / ");
123
input = input.Replace("^", " ^ ");
124
input = input.Replace("(", " ( ");
125
input = input.Replace(")", " ) ");
126
char[] sep ={ ' '};
127
string[] ss = input.Split(sep,StringSplitOptions.None);
128
return ss;
129
}
130
}
鉴于这个类是在仓促下完成的,所以有待优化,经简单测试没有错误,欢迎留言指正。
class InToPost2
{3
Stack<string> stack;4
Queue<string> temp;5
string input;6
string output;7
public string OutString8
{9
get { return output; }10
}11
public InToPost(string str)12
{13
this.input = str.Trim(); ;14
stack = new Stack<string>();15
temp = new Queue<string>();16
}17
public int Trans(out Queue<string> st)18
{19
string str;20
if (!Match())21
{22
st = null;23
return 0;24
}25
string[] tokens = GetTokens();26
for (int i = 0; i < tokens.Length; i++)27
{28
str = tokens[i];29
switch (str)30
{31
case"":32
break;33
case "+":34
case "-":35
GetOperator(str, 1);36
break;37
case "*":38
case "/":39
GetOperator(str, 2);40
break;41
case "^":42
GetOperator(str, 4);43
break;44
case "(":45
stack.Push(str);46
break;47
case ")": 48
GetParen(str);49
break;50
default:51
output += str;52
temp.Enqueue(str); ;53
break;54
}55
}56
while (stack.Count != 0)57
{58
str = stack.Pop();59
temp.Enqueue(str);60
output += str;61
}62
st = temp;63
return 1;64
}65
private bool Match()66
{67
int left = 0, right = 0;68
for (int i = 0; i < input.Length; i++)69
{70
if (input[i] == '(') left++;71
else if (input[i] == ')') right++;72
}73
return left == right;74
}75
private void GetOperator(string opThis, int prec1)76
{77
while (stack.Count != 0)78
{79
string opTop = stack.Pop();80
if (opTop == "(")81
{82
stack.Push(opTop);83
break;84
}85
else86
{87
int prec2 = 0;88
if (opTop == "+" || opTop == "-")89
{ prec2 = 1; }90
else if (opTop == "*" || opTop == "/")91
{ prec2 = 2; }92
else if (opTop == "^") { prec2 = 4; }93

94
if (prec2 < prec1)95
{96
stack.Push(opTop);97
break;98
}99
else100
{101
output += opTop;102
temp.Enqueue(opTop);103
}104
}105
}106
stack.Push(opThis);107
}108
private void GetParen(string str)109
{110
while (stack.Count != 0)111
{112
string s = stack.Pop();113
if (s == "(") break;114
else { output += s; temp.Enqueue(s); }115
}116
}117
private string[] GetTokens()118
{119
input = input.Replace("+", " + ");120
input = input.Replace("-", " - ");121
input = input.Replace("*", " * ");122
input = input.Replace("/", " / ");123
input = input.Replace("^", " ^ ");124
input = input.Replace("(", " ( ");125
input = input.Replace(")", " ) ");126
char[] sep ={ ' '};127
string[] ss = input.Split(sep,StringSplitOptions.None); 128
return ss; 129
}130
}

浙公网安备 33010602011771号