源碼下載: http://www.gzqzyz.cn/UploadFiles/2008-8/expressionanalyzer.rar
# Token.cs
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace OOHacker.ExpressionAnalyzer
- {
- //===========================================================================
- // 抽象標記
- //===========================================================================
- public abstract class Token
- {
- public abstract object Value { get;}
- public override string ToString()
- {
- return Value.ToString();
- }
- }
- //===========================================================================
- // 左括號
- //===========================================================================
- public class LP : Token
- {
- public override object Value
- {
- get
- {
- return '(';
- }
- }
- }
- //===========================================================================
- // 右括號
- //===========================================================================
- public class RP : Token
- {
- public override object Value
- {
- get
- {
- return ')';
- }
- }
- }
- //===========================================================================
- // 數值
- //===========================================================================
- public class Number : Token
- {
- private double val;
- public Number(double value)
- {
- val = value;
- }
- public override object Value
- {
- get
- {
- return val;
- }
- }
- }
- //===========================================================================
- // 操作符
- //===========================================================================
- public class Oper : Token
- {
- private char op;
- public Oper(char oper)
- {
- op = oper;
- }
- public override object Value
- {
- get
- {
- return op;
- }
- }
- }
- }
# GrammarAnalyzer.CS
- using System;
- using System.Text;
- using System.Collections;
- using System.Collections.Generic;
- namespace OOHacker.ExpressionAnalyzer
- {
- public class GrammerAnalyzer
- {
- //=========================================================================
- // 構造函數:
- // exp: 要分析的表達式
- //=========================================================================
- public GrammerAnalyzer(string exp)
- {
- expression = exp;
- index = 0;
- tokens = new List<Token>();
- }
- //=========================================================================
- // 表達式詞法分析
- //=========================================================================
- public void Analyze()
- {
- tokens.Clear();
- index = 0;
- Token tok = null;
- while ((tok = GetToken()) != null)
- {
- tokens.Add(tok);
- }
- }
- //=========================================================================
- // 獲取標記列表
- //=========================================================================
- public Token[] TokenList
- {
- get { return tokens.ToArray(); }
- }
- //=========================================================================
- // 分析後讀取一個標記
- //=========================================================================
- private Token GetToken()
- {
- Token token = null;
- // 忽略空白字符
- while (HasChar && char.IsWhiteSpace(CurrentChar)) MoveNext();
- if (!HasChar) return null;
- if (CurrentChar == '(') // 左括號
- {
- token = new LP();
- }
- else if (CurrentChar == ')') // 右括號
- {
- token = new RP();
- }
- else if (IsOper(CurrentChar)) // 操作符
- {
- token = new Oper(CurrentChar);
- }
- else if (char.IsDigit(CurrentChar)) // 數字
- {
- bool dotFound = false;
- StringBuilder buf = new StringBuilder();
- do
- {
- char c = CurrentChar;
- if (dotFound && c == '.')
- {
- throw new Exception("無效的數字!");
- }
- buf.Append(c);
- MoveNext();
- } while (HasChar && (char.IsDigit(CurrentChar) || CurrentChar == '.'));
- MovePrev(); // 回溯一次
- token = new Number(Convert.ToDouble(buf.ToString()));
- }
- else
- {
- throw new Exception("表達式中含有無效字符:'" + CurrentChar + "'!");
- }
- MoveNext();
- return token;
- }
- //=========================================================================
- // 是否操作符
- //=========================================================================
- private bool IsOper(char c)
- {
- string opers = "+-*/";
- return opers.IndexOf(c) != -1;
- }
- //=========================================================================
- // 是否還有可讀字符
- //=========================================================================
- private bool HasChar
- {
- get { return index < expression.Length; }
- }
- //=========================================================================
- // 當前字符
- //=========================================================================
- private char CurrentChar
- {
- get { return expression[index]; }
- }
- //=========================================================================
- // 轉到下一字符
- //=========================================================================
- private void MoveNext()
- {
- ++index;
- }
- //=========================================================================
- // 轉到上一字符
- //=========================================================================
- private void MovePrev()
- {
- --index;
- }
- private int index;
- private string expression;
- private List<Token> tokens;
- }
- }
# SyntaxAnalyzer.CS
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace OOHacker.ExpressionAnalyzer
- {
- //===========================================================================
- // 語法樹結點
- //===========================================================================
- public class SyntaxTreeNode
- {
- public SyntaxTreeNode(Token tok,
- SyntaxTreeNode lc,
- SyntaxTreeNode rc,
- int nest)
- {
- token = tok;
- lchild = lc;
- rchild = rc;
- this.nest = nest;
- }
- //=========================================================================
- // 標記
- //=========================================================================
- public Token Token
- {
- set { token = value; }
- get { return token; }
- }
- //=========================================================================
- // 左孩子
- //=========================================================================
- public SyntaxTreeNode LChild
- {
- set { lchild = value; }
- get { return lchild; }
- }
- //=========================================================================
- // 右孩子
- //=========================================================================
- public SyntaxTreeNode RChild
- {
- set { rchild = value; }
- get { return rchild; }
- }
- //=========================================================================
- // 嵌套層數
- //=========================================================================
- public int Nest
- {
- set { nest = value; }
- get { return nest; }
- }
- private Token token;
- private SyntaxTreeNode lchild;
- private SyntaxTreeNode rchild;
- private int nest;
- }
- //===========================================================================
- // 語法分析器
- //===========================================================================
- public class SyntaxAnalyzer
- {
- public SyntaxAnalyzer(Token[] toks)
- {
- tokens = toks;
- stack = new Stack<SyntaxTreeNode>();
- tree = null;
- index = 0;
- }
- //=========================================================================
- // 獲取語法樹
- //=========================================================================
- public SyntaxTreeNode SyntaxTree
- {
- get { return tree; }
- }
- //=========================================================================
- // 分析表達式
- //=========================================================================
- public void Analyze()
- {
- // 還原初始狀態
- stack.Clear();
- index = 0;
- tree = null;
- nest = 0;
- if (!HasToken) return;
- // 表達式必須以數值或左括號開頭
- if (CurrentToken is Number)
- {
- N(ref tree);
- }
- else if (CurrentToken is LP)
- {
- Lp(ref tree);
- }
- else
- {
- throw new Exception("無效表達式! 表達式只能數值或左括號開頭!");
- }
- if (stack.Count != 0)
- {
- throw new Exception("無效表達式! 左右括號不配對");
- }
- }
- //=========================================================================
- // 數值標記分析
- //=========================================================================
- private void N(ref SyntaxTreeNode curr)
- {
- SyntaxTreeNode node = new SyntaxTreeNode(CurrentToken,
- null,
- null,
- nest);
- if (curr == null)
- {
- curr = node;
- }
- else
- {
- if (curr.RChild != null)
- {
- curr.RChild.RChild = node;
- }
- else
- {
- curr.RChild = node;
- }
- }
- MoveNext();
- // 數值後的標記必須是操作符或右括號
- if (!HasToken) return;
- if (CurrentToken is Oper)
- {
- Op(ref curr);
- }
- else if (CurrentToken is RP)
- {
- Rp(ref curr);
- }
- else
- {
- throw new Exception("無效表達式! 數值之後發現標記:'"
- + CurrentToken.Value + "'!");
- }
- }
- //=========================================================================
- // 左括號分析
- //=========================================================================
- private void Lp(ref SyntaxTreeNode curr)
- {
- stack.Push(curr); // 壓入括號外分析樹
- curr = null; // 清空分析樹
- ++nest; // 嵌套層增加
- MoveNext();
- if (!HasToken) return;
- // 左括號後必須是數值或左括號
- if (CurrentToken is Number)
- {
- N(ref curr);
- }
- else if (CurrentToken is LP)
- {
- Lp(ref curr);
- }
- else
- {
- throw new Exception("無效表達式! 左括號之後發現標記:'"
- + CurrentToken.Value + "'!");
- }
- }
- //=========================================================================
- // 右括號分析
- //=========================================================================
- private void Rp(ref SyntaxTreeNode curr)
- {
- if (stack.Count == 0)
- {
- throw new Exception("無效表達式! 左右括號不配對!");
- }
- --nest; // 嵌套層遞減
- SyntaxTreeNode node = stack.Pop();
- if (node != null)
- {
- // 將括號內表達式樹作爲子樹掛到括號外表達式樹上
- if (node.RChild != null)
- {
- node.RChild.RChild = curr;
- curr = node;
- }
- else
- {
- node.RChild = curr;
- curr = node;
- }
- }
- MoveNext();
- if (!HasToken) return;
- // 右括號後面必須是操作符或右括號
- if (CurrentToken is Oper)
- {
- Op(ref curr);
- }
- else if (CurrentToken is RP)
- {
- Rp(ref curr);
- }
- else
- {
- throw new Exception("無效表達式! 右括號之後發現標記:'"
- + CurrentToken.Value + "'!");
- }
- }
- //=========================================================================
- // 操作符分析
- //=========================================================================
- private void Op(ref SyntaxTreeNode curr)
- {
- SyntaxTreeNode node = new SyntaxTreeNode(CurrentToken, null, null, nest);
- // 只有位於同一嵌套層中的操作符有優先級可比性
- if ((curr.Token is Oper)
- && (node.Nest == curr.Nest)
- && IsPrior((char)CurrentToken.Value, (char)curr.Token.Value) > 0)
- {
- node.LChild = curr.RChild;
- curr.RChild = node;
- }
- else
- {
- node.LChild = curr;
- curr = node;
- }
- MoveNext();
- // 操作符之後必須是數或左括號
- if (CurrentToken is Number)
- {
- N(ref curr);
- }
- else if (CurrentToken is LP)
- {
- Lp(ref curr);
- }
- else
- {
- throw new Exception("無效表達式! 操作符之後發現標記:'"
- + CurrentToken.Value + "'!");
- }
- }
- //=========================================================================
- // 比較操作符優先級
- //=========================================================================
- private int IsPrior(char op1, char op2)
- {
- int rslt = 0;
- if (op1 == '+' || op1 == '-')
- {
- if (op2 == '*' || op2 == '/')
- rslt = -1;
- }
- else if (op1 == '*' || op1 == '/')
- {
- if (op2 == '+' || op2 == '-')
- rslt = 1;
- }
- return rslt;
- }
- //=========================================================================
- // 是否還有標記可讀
- //=========================================================================
- private bool HasToken
- {
- get { return index < tokens.Length; }
- }
- //=========================================================================
- // 轉到下一標記
- //=========================================================================
- private void MoveNext()
- {
- ++index;
- }
- //=========================================================================
- // 當前標記
- //=========================================================================
- private Token CurrentToken
- {
- get { return (Token)tokens[index]; }
- }
- private int index;
- private int nest;
- private SyntaxTreeNode tree;
- private Token[] tokens;
- private Stack<SyntaxTreeNode> stack;
- }
- }
# Calculator.CS
- using System;
- using System.Text;
- using System.IO;
- namespace OOHacker.ExpressionAnalyzer
- {
- //===========================================================================
- // 表達式計算器
- //===========================================================================
- public class Calculator
- {
- //=========================================================================
- // 構造函數
- // tree: 表達式語法樹, 由SyntaxAnalyzer創建;
- //=========================================================================
- public Calculator(SyntaxTreeNode tree)
- {
- this.tree = tree;
- log = new StringBuilder();
- }
- //=========================================================================
- // 計算表達式值
- public double Calc()
- {
- if (tree == null)
- {
- throw new Exception("計算樹爲空!");
- }
- log.Remove(0, log.Length);
- return Travel(tree);
- }
- //=========================================================================
- // 求解過程日誌
- //=========================================================================
- public string Log
- {
- get { return log.ToString(); }
- }
- //=========================================================================
- // 遍歷表達式分析樹,求取結果
- //=========================================================================
- private double Travel(SyntaxTreeNode tree)
- {
- if (tree.Token is Number)
- {
- return (double)tree.Token.Value;
- }
- double lsh = Travel(tree.LChild);
- double rsh = Travel(tree.RChild);
- return Op((char)tree.Token.Value, lsh, rsh);
- }
- //=========================================================================
- // 實際計算操作
- //=========================================================================
- private double Op(char op, double lsh, double rsh)
- {
- double rslt = 0;
- switch (op)
- {
- case '+':
- rslt = lsh + rsh;
- break;
- case '-':
- rslt = lsh - rsh;
- break;
- case '*':
- rslt = lsh * rsh;
- break;
- case '/':
- if (rsh == 0)
- {
- throw new Exception("除0溢出!");
- }
- rslt = lsh / rsh;
- break;
- default:
- throw new Exception("未能識別的操作類型!");
- }
- log.AppendFormat("{0,5}{1,5}{2,5}={3,5}/n", lsh, op, rsh, rslt);
- return rslt;
- }
- private SyntaxTreeNode tree;
- private StringBuilder log;
- }
- }
# 主程序
- using System;
- using System.Text;
- using System.Collections;
- using OOHacker.ExpressionAnalyzer;
- class Program
- {
- static void Main(string[] args)
- {
- string expression;
- Console.Write("請輸入表達式:");
- expression = Console.ReadLine();
- try
- {
- GrammerAnalyzer ga = new GrammerAnalyzer(expression);
- ga.Analyze();
- Token[] toks = ga.TokenList;
- for (int i = 0; i < toks.Length; ++i)
- {
- Console.Write(toks[i]);
- }
- SyntaxAnalyzer sa = new SyntaxAnalyzer(toks);
- sa.Analyze();
- Calculator calc = new Calculator(sa.SyntaxTree);
- double value = calc.Calc();
- Console.Write("={0}", value);
- Console.WriteLine("/n解析過程:/n{0}", calc.Log);
- }
- catch (Exception e)
- {
- Console.WriteLine("錯誤:" + e.Message);
- }
- Console.Read();
- }
- }
# 測試:
請輸入表達式:(1*2+(3-5)*7)/22+(1-2*3)*5
(1*2+(3-5)*7)/22+(1-2*3)*5=-25.5454545454545
解析過程:
1 * 2= 2
3 - 5= -2
-2 * 7= -14
2 + -14= -12
-12 / 22=-0.545454545454545
2 * 3= 6
1 - 6= -5
-5 * 5= -25
-0.545454545454545 + -25=-25.5454545454545
請輸入表達式:(1+2+3*(1+2+3)/6)*5*(1+2+3)*(1+1)
(1+2+3*(1+2+3)/6)*5*(1+2+3)*(1+1)=360
解析過程:
1 + 2= 3
1 + 2= 3
3 + 3= 6
3 * 6= 18
18 / 6= 3
3 + 3= 6
6 * 5= 30
1 + 2= 3
3 + 3= 6
30 * 6= 180
1 + 1= 2
180 * 2= 360
請輸入表達式:(3+2*(9/3))*10-5/8-3*3*(1+2+3+(1+2+3))
(3+2*(9/3))*10-5/8-3*3*(1+2+3+(1+2+3))=-18.625
解析過程:
9 / 3= 3
2 * 3= 6
3 + 6= 9
9 * 10= 90
5 / 8=0.625
90 -0.625=89.375
3 * 3= 9
1 + 2= 3
3 + 3= 6
1 + 2= 3
3 + 3= 6
6 + 6= 12
9 * 12= 108
89.375 - 108=-18.625
請輸入表達式:1+(2*3)/6*(3+5)
1+(2*3)/6*(3+5)=9
解析過程:
2 * 3= 6
6 / 6= 1
3 + 5= 8
1 * 8= 8
1 + 8= 9
請輸入表達式:3+2*(3+1)*5-1
3+2*(3+1)*5-1=42
解析過程:
3 + 1= 4
2 * 4= 8
8 * 5= 40
3 + 40= 43
43 - 1= 42
,