using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public struct nameSet // 実行用スタックの要素 { public string name;  // 変数名,評価済みのとき"*VALUE*" public double value; // 評価済み値 public nameSet(string n, double v) { name = n; value = v;} } public struct opeSet // 逆ポーランド変換用スタックの要素 { public string name; // 演算子 public int value; // 優先順位 public opeSet(string n, int v) { name = n; value = v;} } public struct token // 単一トークンの形式 { public string atr; // トークンの種類"NUM","OPE","VAR" public string str; // トークンの文字列 public token(string a, string s) { atr = a.ToUpper(); str=s;} } public nameSet[] STab=new nameSet[500]; // 記号表 public int numStab; // 記号表のサイズ public token[] Polish = new token[500]; // 逆ポーランド記法の出力先 public int numPolish; // 逆ポーランド記法のサイズ public nameSet[] Stack = new nameSet[500]; // 実行用スタック public int stackP; // スタックポインタ public opeSet[] StackOpe = new opeSet[500];// 逆ポーランド変換用スタック public string Alltext; // 入力文字列 public string Delmiter = "()+-*/="; // 区切り記号(演算子) public string Number = "0123456789"; // 数字 public token[] LAData = new token[500]; // 語彙解析結果 public int numLA; // 語彙解析結果のサイズ public Form1() {  InitializeComponent(); } private void push(nameSet X)  // 実行用スタック Push { if (stackP >= 500) MessageBox.Show("Stack Over"); else { Stack[stackP] = X; if(checkBox1.Checked)MessageBox.Show("push(" + stackP.ToString() + ")" + X.name + " Value=" + X.value.ToString()); stackP++; } } private nameSet pop() // 実行用スタック Pop { if (stackP <= 0) { MessageBox.Show("Stack Empty"); return new nameSet("*Error*", 0);} else { stackP--;nameSet X = Stack[stackP]; if (checkBox1.Checked) MessageBox.Show("pop(" + stackP.ToString() + ")" + X.name +" Value=" + X.value.ToString()); return X; } } private void pushOpe(opeSet X) // 変換用 Push { if (stackP >= 500) MessageBox.Show("Stack Over"); else { StackOpe[stackP] = X; if (checkBox1.Checked) MessageBox.Show("push(" + stackP.ToString() + ")" + X.name +" Priority=" + X.value.ToString()); stackP++; } } private opeSet popOpe() // 変換用 Pop { if (stackP <= 0) { MessageBox.Show("Stack Empty"); return new opeSet("*Error*", 0);} else { stackP--; opeSet X=StackOpe[stackP]; if (checkBox1.Checked) MessageBox.Show("pop(" + stackP.ToString() + ")" + X.name +" Priority=" + X.value.ToString()); return X; } } private nameSet sepValue(string X)// TextBoxの変数名/値分離 { string[] S = new string[2]; S=X.Split('='); return new nameSet(S[0].Trim(' '),double.Parse(S[1])); } private token setPolish(string X) // TextBoxのトークン設定 { string[] S = new string[2]; S = X.Split(':'); return new token(S[0].Trim(' '), S[1].Trim(' ')); } private void setValue(string Name, double V)//変数値の設定 { STab[numStab].name=Name; int i=0; while (STab[i].name!=Name) i++; STab[i].value = V; if (i >= numStab) numStab++; dspName(); } private double getValue(string Name) // 与えられた変数の値 { for (int i = 0; i < STab.Length; i++) if (STab[i].name == Name) return STab[i].value; return 0; } private void outStab(string s) // "変数名=値"のデータを記号表に登録 { STab[numStab] = sepValue(s); numStab++; } private void outSPolish(string s) // "種類:記号"のデータをトークンとして設定 { Polish[numPolish] = setPolish(s); numPolish++; } private void initialize() // 実行用初期設定 { numStab = 0; // 名前表 for (int i = 0; i < textBoxSymbol.Lines.Length; i++) if (textBoxSymbol.Lines[i].Length >= 2) outStab(textBoxSymbol.Lines[i]); numPolish = 0; // 逆ポーランド記法 for (int i = 0; i < textBoxPolish.Lines.Length; i++) if (textBoxPolish.Lines[i].Length >= 2) outSPolish(textBoxPolish.Lines[i]); stackP = 0; // スタックポインタ } private void outLAData(string s) // "種類:記号"のデータを語彙解析結果として設定 { LAData[numLA] = setPolish(s); numLA++; } private void initializeSA() // 変換の初期設定 { numLA = 0; // 語彙解析結果 for (int i = 0; i < textBoxLA.Lines.Length; i++) if (textBoxLA.Lines[i].Length >= 2) outLAData(textBoxLA.Lines[i]); stackP = 0; } private double evalDT(nameSet X) // 値を求める { if (X.name == "*VALUE*") return X.value; return getValue(X.name); } private void exePolish() // 逆ポーランド記法の実行 { initialize(); //初期設定 for (int i = 0; i < numPolish; i++)  //【注】変数Pushの場合、値が必要になった時点で評価。 { if(Polish[i].atr=="VAR") push(new nameSet(Polish[i].str, 0));//変数Push(ここでは値はダミー) else if (Polish[i].atr == "OPE") { nameSet A1, A2; if (checkBox1.Checked) MessageBox.Show("演算実行 " + Polish[i].str); //演算実行 A2 = pop(); double V2 = evalDT(A2); // 演算対象Popと評価 if (Polish[i].str == "$+") { }      // 単項演算子実行 $+ else if (Polish[i].str == "$-") V2 = -V2; // $- else { A1 = pop(); // 演算対象Pop if (Polish[i].str == "=") // 代入処理 { if (A1.name == "*VALUE*") MessageBox.Show("代入に矛盾があります"); else setValue(A1.name, V2); } else // 以下2項演算 { double V1 = evalDT(A1); if (Polish[i].str == "+") V2 = V1 + V2; else if (Polish[i].str == "-") V2 = V1 - V2; else if (Polish[i].str == "*") V2 = V1 * V2; else if (Polish[i].str == "/") V2 = V1 / V2; else MessageBox.Show("演算子の例外"); } } push(new nameSet("*VALUE*", V2)); // 演算結果のPush } else push(new nameSet("*VALUE*", double.Parse(Polish[i].str)));// 数値のPush } } private void dspName() // 記号表をテキストボックスに表示 { string S = ""; for(int i=0;i -1) // 数字のあいだ以下を繰り返す { if (ch == ".") { if (dot) MessageBox.Show(".の位置の誤り"); dot = true; } s += ch; Alltext = Alltext.Substring(1, Alltext.Length - 1); if (Alltext == "") break; ch = Alltext.Substring(0, 1); } } return (new token("Num", s)); } private token nameProc(string ch)// 変数名の設定 { string s = ch; if (Alltext != "") { ch = Alltext.Substring(0, 1); while (ch != " " && Delmiter.IndexOf(ch) <= -1)// 空白、区切り記号のいずれ { s += ch; // でもないあいだ繰り返す Alltext = Alltext.Substring(1, Alltext.Length - 1); if (Alltext == "") break; ch = Alltext.Substring(0, 1); } } return (new token("Var", s)); } private token getLAToken() // 語彙解析 { Alltext=Alltext.TrimStart(); if (Alltext == "") return (new token("$EOF$", "$EOF$")); string ch = Alltext.Substring(0, 1); Alltext = Alltext.Substring(1, Alltext.Length - 1); if (Delmiter.IndexOf(ch) > -1) return (new token("Ope", ch)); else if (ch=="." || Number.IndexOf(ch) > -1) return numberProc(ch); else return nameProc(ch); } private void dspPolish()//逆ポーランド記法をテキストボックスに表示 { string S = ""; for (int i = 0; i < numPolish; i++) S += Polish[i].atr + ":" + Polish[i].str + "\r\n"; textBoxPolish.Text = S; } private void button2_Click(object sender, EventArgs e)// 連続語彙解析 { startLA(); string S = ""; token TK = getLAToken(); while (TK.atr != "$EOF$") { string X = TK.atr + ":" + TK.str; S = S + X + "\r\n"; if (checkBox1.Checked) MessageBox.Show(X); TK = getLAToken(); } textBoxLA.Text = S; } private int priority(string s) // 演算子による優先順位の設定 { if (s == "=") return 10; else if (s == "+" || s == "-") return 20; else if (s == "*" || s == "/") return 30; else if (s == ")") return -1; else return 0; } private void singleOpe(string s) // 単項演算子と左カッコの処理 { if (s == "+" || s == "-") // 2項演算子の+,-と区別するために pushOpe(new opeSet("$" + s, 200));// それぞれ$を先頭に付ける。 else if (s == "(") // 左括弧の場合Push pushOpe(new opeSet("(", 0)); else MessageBox.Show("演算子エラー"); } private int operandProc(token S) // 演算対象の場合、そのまま変換結果に移動 { Polish[numPolish] = S; numPolish++; return 1; // 次のモードを演算子モードにする。 } private void rightParPop()// 右カッコの処理 { if (stackP > 0) // 左カッコになるまでPopして変換結果に移動 { opeSet X = popOpe(); while (X.name != "(" && stackP >= 0) { Polish[numPolish] = new token("OPE", X.name); numPolish++; X = popOpe(); } } else MessageBox.Show("左カッコが足りません"); } private int operationProc(string s, int Opt)// 演算子処理 { if (stackP > 0) // スタック上に優先順位が高いか、 { while (stackP>0) // 同じ演算子があればPopして変換結果に移動 { if (StackOpe[stackP-1].value < Opt) break; opeSet X = popOpe(); Polish[numPolish] = new token("OPE", X.name); numPolish++; } } pushOpe(new opeSet(s, Opt));// 演算子をPush return 0; // 次のモードを演算対象モードとする。 } private void endPop()// スタック上に残った演算子を変換結果に移動。 { while (stackP > 0) { opeSet X = popOpe(); Polish[numPolish] = new token("OPE", X.name); numPolish++; } } private void SA() // 逆ポーランドへの変換 { initializeSA(); int SMode = 0; numPolish = 0; for (int i = 0; i < numLA; i++) { string ATR = LAData[i].atr.ToUpper(); if (SMode == 0) // 演算対象モード(演算子は、+,-(単項演算子)か左括弧) { if (ATR == "OPE") singleOpe(LAData[i].str);// 単項演算子と左括弧の処理 else SMode = operandProc(LAData[i]); //演算対象処理 } else // 演算子モード(2項演算子か右括弧だけのモード) { if (ATR == "OPE") { int Opt = priority(LAData[i].str); // 演算子の優先順位設定 if (Opt == 0) MessageBox.Show("演算子エラー"); // (0:エラー,-1:右括弧) else if (Opt < 0) rightParPop(); // 右括弧の処理 else SMode = operationProc(LAData[i].str, Opt);// 2項演算子処理 } else MessageBox.Show("演算子がありません"); } } endPop(); dspPolish(); // スタックに残った演算子を変換結果に移して結果表示 } private void button3_Click(object sender, EventArgs e) { SA(); } } }