文法分析与解释器模式(一)
考虑算术表达式:(5+10)*20 他具有BNF(此处已考虑结合律问题): exp -> exp addop term|term addop -> +|- term -> term mulop factor|factor mulop -> *|/ factor -> (exp)|number 提取标记(token): exp:"exp" "addop" "term"| addop: "+" "-"| term: "term" "mulop" "factor"|=>"exp" "+" "-" "*" "/" "number" mulop: "*" "/"| factor: "number"| 然后建立他们的类型:其中“exp”是根,所以应改建立抽象类
1
abstract class Expression
2
{
3
public abstract double Interpret();
4
public abstract override bool Equals(object obj);
5
public abstract override int GetHashCode();
6
public abstract override string ToString();
7
}
8
class Number : Expression
9
{
10
private double value; public Number()
11
{ this.value = value; }
12
public override double Interpret()
13
{ return value; }
14
public override bool Equals(object o)
15
{
16
if (o != null && o is Number)
17
{ return this.value == ((Number)o).value; }
18
return false;
19
}
20
public override int GetHashCode()
21
{ return (this.ToString()).GetHashCode(); }
22
public override string ToString()
23
{ return value.ToString(); }
24
}
25
class Add : Expression
26
{
27
private Expression left, right; public Add(Expression left, Expression right)
28
{ this.left = left; this.right = right; }
29
public override double Interpret()
30
{ return left.Interpret() + right.Interpret(); }
31
public override bool Equals(object obj)
32
{
33
if (obj != null && obj is Add)
34
{ return this.left.Equals(((Add)obj).left) && this.right.Equals(((Add)obj).right); }
35
return false;
36
}
37
public override int GetHashCode()
38
{ return (this.ToString()).GetHashCode(); }
39
public override string ToString()
40
{ return "(" + left.ToString() + "+" + right.ToString() + ")"; }
41
}
于此建立类似的二元运算符类:dec,mul,div 有
Expression exp= new Mul(new Add(new Number(5),new Number(10)),new number(20))这里有一个刚刚接触解释器模式的朋友(就是我^_^)最迷惑的问题:到底怎么才能动态的生成 exp 的表达式?(就是如何决定什么时候new哪种类型)呵呵,其实这并不是解释器模式所做的事!至少不是它的初衷,这是分析器所做的事,因为分析器没有固定的写法,多不同类型的需求其性能差别很大,下一章针对这种表达式建立一种简单的分析器,其中用到“后缀表达式”,再下一章讨论有“变量”存在的表达式的分析和有“一元运算符”存在的表达式。 对于一些不存在次序的问题,比如转换中文数字到阿拉伯数字,可以在其“解释函数-Interpret()"中分析(递归)这样就省略了单独的分析器”其实对于算术表达式之类的较为复杂的问题的分析,在编译原理里有建立自动机的方法,然后建立状态表,这种方法速度很快,而且对于熟练者来说更为快捷,但是对于状态表化简头痛的人(比如我当年就是),还是直接的方法好一些,还有一种方式是语法分析树,这和解释器模式有异曲同工之处,树的节点就像上面建立的类,这是编译原理的初衷。就个人使用的经验而言,状态表的最大好处就是可以很容易把错误分析集中在一起,而其他两种方式则分散的多。有时间写一下关于状态表,和语法分析树的文章来做一下横向对比。


浙公网安备 33010602011771号