プログラミング言語 作成の実際 しらいゆたか
言語プロセッサの処理 次の手順で処理する。 (1)文識別 (2)語彙解析(Lexical Analysis) (3)構文解析(Syntax Analysis) (4)意味解析(Semantic Analysis) およびコード生成(Code Generation) さらに,インタプリタの場合,実行(Execution)
1.文識別 最初に行うのは,1文を取り出す処理。 ■ 1行の中に複数の文 ■ 2行以上で1文 語彙解析の途中で,文の終わりを判別するのは ■ 1行の中に複数の文 ■ 2行以上で1文 語彙解析の途中で,文の終わりを判別するのは 処理を複雑にしてしまう。 文識別は最初に行う。 ただし,文字列の処理が必要。 最小限の文字列処理を行いながら文を取り出す。
プログラム例(1) public int ptrText; public string AllText; private string 文取り出し() // 全ソースの中から1文を取り出す { string S=""; while(ptrText<AllText.Length) { if(AllText[ptrText]=='\n'||AllText[ptrText]=='\r'){ptrText++;return S;} else if(AllText[ptrText]==':') {ptrText++;return S;} else if(AllText[ptrText]=='_') { ptrText++; while(ptrText<AllText.Length){ if(AllText[ptrText]=='\n'||AllText[ptrText]=='\r')break; ptrText++; } } (続きあり)
プログラム例(2) else if(AllText[ptrText]==‘“’){ // 文字列内処理 S += AllText[ptrText].ToString(); ptrText++; while(ptrText<AllText.Length) { if(AllText[ptrText]=='\n'||AllText[ptrText]=='\r') { MessageBox.Show("ダブルクォーテーション(\")が足りません"); return S; } else if(AllText[ptrText]=='"') { if((ptrText>=AllText.Length) || (AllText[ptrText]!='"')) break; S+=AllText[ptrText].ToString(); ptrText++; } } S=S+AllText[ptrText].ToString(); ptrText++; private void 全文取出し() // テキストボックスの内容をソースプログラムとする。 { AllText=textBox1.Text; ptrText=0;
2.語彙解析(Lexical Analysis) 文字列を単語に分ける処理。 準備として,次のような構造体を定義しておこう。 public struct WordData { public string type; public string str; public WordData(string tp,string st) { type = tp; str = st;} }
語彙解析の2段階 複数の文字種別による単語がありうるので, 文字種別の判定だけでは単語を区別するのが困難。 もし可能だとしても処理が複雑になる。 (C#の例)12.5E-12 したがって,2段階に分離するのが常套手段。 単語の識別 呼出し 文字種別による識別
最も低レベルの文字列の判別(1) public string 数字="0123456789"; private int 該当文字(string str, char CH) { for(int i=0;i<str.Length;i++) if(str[i]==CH) return i; return -1; } private WordData LA0() // 文字種別による識別 while(ptr<str.Length) if(str[ptr]==' ' || str[ptr]==' ' || str[ptr]=='\t') ptr++; else if(str[ptr]=='\n') ptr++; else if(str[ptr]=='\r') ptr++; else if(str[ptr]=='\"') return 文字列設定(); else if(str[ptr]=='.' ) return 数字列設定(); else if(該当文字(数字,str[ptr])>=0) return 数字列設定(); else if(該当文字(区切記号,str[ptr])>=0) return 区切記号設定(); else return 名前設定(); return new WordData("End","");
最も低レベルの文字列の判別(2) private WordData 文字列設定() { string S="";ptr++; while(ptr<str.Length) if(str[ptr]=='\n'||str[ptr]=='\r') { MessageBox.Show("\"がありません"); return new WordData("String",S); } else if(str[ptr]=='"') ptr++; if((ptr==str.Length) || (str[ptr]!='"')) return new WordData("String",S); S=S+str[ptr].ToString();
最も低レベルの文字列の判別(3) private WordData 数字列設定() { string S=""; while(ptr<str.Length && 該当文字(数字,str[ptr])>=0) S += str[ptr].ToString(); ptr++; } if(ptr<str.Length && str[ptr]=='.') S +="."; ptr++; while(ptr<str.Length && 該当文字(数字,str[ptr])>=0) { S += str[ptr].ToString(); ptr++; } if(S==".") return new WordData("Delimiter",S); else return new WordData("Number",S);
最も低レベルの文字列の判別(4) private WordData 名前設定() { string S=""; while(ptr<str.Length) if ( str[ptr]=='"' || str[ptr]==' ' || str[ptr]==' ' || str[ptr]=='\n'|| str[ptr]=='\r') break; int N = 該当文字(区切記号,str[ptr]); if (N>=0) break; S += str[ptr].ToString(); ptr++; } return new WordData("Name",S); private WordData 区切記号設定() WordData P= new WordData("Delimiter",str[ptr].ToString()); ptr++; return P;
単語の識別(1) public int numTokenX=0 ; // 語彙解析結果の格納位置 public WordData[] tokenX=new WordData[500]; // 語彙解析結果 private bool E_exp(string str) // Eに続いて数字列になっているか(指数形式の判別) { if(str.Length<2) return false; if(str[0]!='E' && str[0]!='e') return false; for(int i=1;i<str.Length;i++) if(該当文字(数字,str[i])<0) return false; return true; } // 途中経過表示用(途中経過表示なければ必要ない) private void debugLA(WordData token1,WordData token2,WordData token3,WordData token4) string S=" 1:"+ token1.type+ " \t ["+token1.str+"]\n"+ " 2:"+ token2.type+" \t ["+token2.str+"]\n"+ " 3:"+ token3.type+" \t ["+token3.str+"]\n"+ " 4:"+ token4.type+" \t ["+token4.str+"]"; DialogResult result = MessageBox.Show(S,"語彙解析途中",MessageBoxButtons.OKCancel); if(result==DialogResult.Cancel) checkBox1.Checked=false; private void set_TokenX(string type, string str) // 語彙解析結果のセット tokenX[numTokenX].type=type; tokenX[numTokenX].str=str; numTokenX++;
単語の識別(2) private void combineDelimiter(string str1, string str2) // 複数区切り記号による演算子 { set_TokenX("Delimiter",str1+str2);} private void LA1() { numTokenX=0; WordData token1,token2,token3,token4; token1=LA0();token2=LA0();token3=LA0();token4=LA0(); while(token1.type!="End") if(checkBox1.Checked)debugLA(token1,token2,token3,token4); if( token1.type=="Number" && token2.type=="Name" && token2.str=="E" && token3.type=="Delimiter" && (token3.str=="+" || token3.str=="-")&& token4.type=="Number") set_TokenX("Number",token1.str+token2.str+token3.str+token4.str); } else if( token1.type=="Number" && token2.type=="Name" && E_exp(token2.str)){ set_TokenX("Number",token1.str+token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); else if(token1.type=="Delimiter" && token1.str==">" && token2.type=="Delimiter" && token2.str=="=" ) { combineDelimiter(token1.str,token2.str);
単語の識別(3) else if(token1.type=="Delimiter" && token1.str==">" && combineDelimiter(token1.str,token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); } else if(token1.type=="Delimiter" && token1.str=="=" && token2.type=="Delimiter" && token2.str=="<" ){ else if(token1.type=="Delimiter" && token1.str=="<" && else if(token1.type=="Delimiter" && token1.str=="|" && token2.type=="Delimiter" && token2.str=="|" ){ else if(token1.type=="Delimiter" && token1.str=="&" && token2.type=="Delimiter" && token2.str=="&" ){ else if(token1.type=="Delimiter" && token1.str=="%" && token2.type=="Delimiter" && token2.str=="%" ){
単語の識別(4) else if(token1.type=="Delimiter" && token1.str=="!" && combineDelimiter(token1.str,token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); } else if(token1.type=="Delimiter" && token1.str=="=" && else if(token1.type=="Delimiter" && token1.str=="+" && token2.type=="Delimiter" && token2.str=="+"){ else if(token1.type=="Delimiter" && token1.str=="-" && token2.type=="Delimiter" && token2.str=="-"){
単語の識別(5) else if(token1.type=="Delimiter" && token1.str=="-" && combineDelimiter(token1.str,token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); } else if(token1.type=="Delimiter" && token1.str=="*" && token2.type=="Delimiter" && token2.str=="="){ else if(token1.type=="Delimiter" && token1.str=="/" && else if(token1.type=="Name" && token1.str=="end" && token2.type=="Name" && token2.str=="if"){ set_TokenX(token1.type,token1.str+token2.str); else{ set_TokenX(token1.type,token1.str); token1=token2;token2=token3;token3=token4;token4=LA0();
3.構文解析 語彙解析の結果から文を判別して, 一文の解析結果を作成する。 ただし,式の場合は,優先順位を判別する必要がある。 基本的には,逆ポーランド記法に展開する。 文全体の処理と逆ポーランド記法への変換を分ける。
逆ポーランド記法変換 ①変数や定数はそのまま出力トークンへ移動する。 ②演算子はスタック上の演算子と比較し,スタック上の演算子の優先度が取り出した演算子と等しいか大きい場合,スタック上の演算子をポップして出力トークンに移動する。 ④取り出した演算子をプッシュする。 ⑤前括弧の場合,プッシュする。 ⑥後括弧の場合,前括弧までをポップする。このとき,スタックトップが関数表現ならば,関数呼出しを出力トークンに移動する。 ⑦関数表現の場合,関数表現と前括弧をプッシュする。 ⑧コンマの場合,前括弧の直前までポップする。 ⑨1文終わりのときは後括弧と同じ処理を行う。
演算子等の解釈 ①演算子モードと値モードを用意し,初期値は値モードとする。 ②値モードのとき,演算子がきたら前置単項演算子とみなす。 ③演算子モードのとき,前括弧がきたら,先行する名前は関数表現とみなし,値モードに移行する。 ④演算子モードのとき,後置演算子か通常の演算子かを判定する。 後置演算子でない場合,値モードに移行する。 ⑤コンマのとき,値モードに移行する。 ⑥前括弧の場合,値モードに移行する。 ⑦後括弧の場合,演算子モードに移行する。
逆ポーランド記法への変換 (1)トレース用ルーチン // このルーチンを残しておくことでモードがどのように移行しているかをチェックできる。 private void debugSA0(int i,bool Mode) { string S="*Lexical\n";int k; for(k=i; k<numToken; k++) S +=" " + token[k].str; S+="\n*Mode = "+(Mode ? "Value" :"Operation")+"\n*Polish\n"; for(k=0; k<numPolish; k++) if(Polish[k].operation=="-$" || Polish[k].operation=="+$") S +=" " + Polish[k].operation; else S +=" " + Polish[k].str; } S += "\n*Stack\n"; for(k=ptrStack-1; k>=0; k--) if(Stack[k].operation=="-$" || Stack[k].operation=="+$") S +=" " + Stack[k].operation; else S +=" " + Stack[k].str; S+="\n"; DialogResult result = MessageBox.Show(S,"構文解析途中経過1",MessageBoxButtons.OKCancel); if(result==DialogResult.Cancel) checkBox1.Checked=false;
逆ポーランド記法への変換 (2)データ領域宣言 public struct TokenData { public string operation; public int priority; public string str; public TokenData(string ope,int pr, string st) operation = ope; priority = pr ; str = st ; } public int numPolish=0 ;// 出力トークンの数 public int numToken=0 ; // 入力トークンの数 public int ptrStack=0 ; // スタックの高さ public TokenData[] Polish=new TokenData[200];// 出力トークン public TokenData[] Stack=new TokenData[200]; // スタック public WordData[] token=new WordData[500]; // 入力トークン
逆ポーランド記法への変換 (3)変換処理① // 以下の処理を行う前に, // 文中の式表現に対応する部分を取り出して // token[numToken]に移しておく private void SA0() { numPolish=0; ptrStack=0 ; int i=0;bool Mode=true; while(i<numToken) if(checkBox1.Checked) debugSA0(i,Mode); if(Mode) { // 値モード if(token[i].type=="Delimiter" && (token[i].str=="+" || token[i].str=="-")) pushProc(new TokenData(token[i].str+“$”,300,token[i].str)); // 前置 else if(token[i].type=="Delimiter" && (token[i].str=="++" || token[i].str=="--")) else if(token[i].type=="Delimiter" && token[i].str=="!" ) pushProc(new TokenData(token[i].str,40,token[i].str)); // 前置 else if(token[i].type=="Delimiter" && token[i].str=="(") pushProc(new TokenData(token[i].str,0,token[i].str)); // 前置 else if(token[i].type=="Name" && token[i].str=="if") { // if関数 postFix(new TokenData("if",0,token[i].str)); push(new TokenData("Block",0,token[i].str)); }
逆ポーランド記法への変換 (3)変換処理② else if(token[i].type==“Name” && // 関数表現 i<(numToken-1) && (token[i+1].type=="Delimiter" && token[i+1].str=="(")) { postFix(new TokenData("ArgEnd",0,token[i].str)); push(new TokenData("Func",0,token[i].str)); i++; } else if(token[i].type!=“Delimiter”) // 値または変数など postFix(new TokenData(token[i].type,0,token[i].str)); Mode=false; // 演算子モードに移行 else MessageBox.Show("001 区切記号の位置の誤り"); break;
逆ポーランド記法への変換 (3)変換処理③ else { // 演算子モード Mode=true; // 標準的には値モードに移行 { // 演算子モード Mode=true; // 標準的には値モードに移行 if (token[i].type=="Delimiter" && (token[i].str=="+" || token[i].str=="-")) pushProc(new TokenData(token[i].str,100,token[i].str)); else if(token[i].type=="Delimiter" && (token[i].str=="++" || token[i].str=="--")) pushProc(new TokenData(token[i].str,10,token[i].str)); else if(token[i].type=="Delimiter" && (token[i].str=="+=" || token[i].str=="-=")) else if(token[i].type=="Delimiter" && (token[i].str=="*=" || token[i].str=="/=")) else if(token[i].type=="Delimiter" && token[i].str=="=") else if(token[i].type=="Delimiter" && (token[i].str=="||" || token[i].str=="&&" || token[i].str== "%%")) pushProc(new TokenData(token[i].str,30,token[i].str)); (token[i].str=="==" || token[i].str=="!=" || token[i].str== ">" || token[i].str==">=" || token[i].str=="=>" || token[i].str== "<" || token[i].str=="<=" || token[i].str=="=<")) { if (token[i].str=="=>") token[i].str=">="; else if(token[i].str=="=<") token[i].str="<="; pushProc(new TokenData(token[i].str,50,token[i].str)); } (token[i].str=="*" || token[i].str=="/"|| token[i].str=="%")) pushProc(new TokenData(token[i].str,200,token[i].str));
逆ポーランド記法への変換 (3)変換処理④ else if(token[i].type=="Name" && token[i].str=="mod") pushProc(new TokenData(token[i].str,200,token[i].str)); else if(token[i].type=="Delimiter" && token[i].str=="^") pushProc(new TokenData(token[i].str,400,token[i].str)); else if(token[i].type=="Delimiter" && token[i].str==")") { popProcS();Mode=false;} else if(token[i].type=="Delimiter" && token[i].str==",") popProcF(); else if(token[i].type=="Name" && (token[i].str=="then" || token[i].str=="else")){ popProcBlock(); postFix(new TokenData(token[i].str,0,token[i].str)); push(new TokenData("Block",0,token[i].str)); Mode=true; } else if(token[i].type=="Name" && token[i].str=="endif"){ else { MessageBox.Show("002 名前の位置または演算子の誤り"); break; i++; } if(checkBox1.Checked) debugSA0(i,Mode); popProcE();
逆ポーランド記法への変換 (4)データ領域アクセス① public void push(TokenData TK) { Stack[ptrStack++]=TK; } public TokenData pop() { if(ptrStack==0) return new TokenData("Empty",0,""); ptrStack--; return Stack[ptrStack]; } public void postFix(TokenData TK) { Polish[numPolish]=TK;numPolish++;} public void pushProc(TokenData TK) { if(ptrStack>0) while(ptrStack>0 &&TK.priority<=Stack[ptrStack-1].priority && TK.operation!="(") postFix(pop()); push(TK); public void popProcS() { TokenData XX=pop(); while(ptrStack>=0) if(XX.operation=="(") break; if(XX.operation=="Func"){postFix(XX);break; } postFix(XX); XX=pop();
逆ポーランド記法への変換 (4)データ領域アクセス② public void popProcF() { TokenData XX = pop(); while(ptrStack>=0) if(XX.operation=="Func"){push(XX); break;} postFix(XX); XX=pop(); } public void popProcBlock() if(XX.operation=="Block")break; public void popProcE() TokenData XX; XX=pop(); while(ptrStack>0) { postFix(XX);XX=pop();} if(XX.operation!="Empty")postFix(XX);
逆ポーランド記法への変換 (5)変換用トークンの複写 private void token複写(ref int i) // 語彙解析結果すべてを複写 { numToken=0; while(i<numTokenX) token[numToken]=tokenX[i];numToken++; i++; } private void token複写Comma(ref int i) // コンマまでを複写(括弧のレベルを考慮する) numToken=0;int lebel=0; if (tokenX[i].type=="Delimiter" && tokenX[i].str=="(")lebel++; else if(tokenX[i].type=="Delimiter" && tokenX[i].str==")")lebel--; else if(lebel==0 && tokenX[i].type=="Delimiter" && tokenX[i].str==",") return;
1文ごとの構文解析 文種別ごとに, 式部分を分離し,逆ポーランド変換を行い, 文ごとの解釈を行う。 IfブロックやWhileブロックの処理を行うために スタックを用意する。
If ブロックやWhileブロック用のスタック public struct BlockData // ブロックコントロールデータ { public string Type; public int BP; public int IfP; public int ThenP; } public BlockData [] IfStack=new BlockData[200]; public int IfStackP=0; public BlockData [] DoStack=new BlockData[200]; public int DoStackP=0; public int[] numBreak=new int[200]; // Break処理用テーブル public int[,] BreakP=new int[200,200];
構文解析 (1)トレース用ルーチン private void debugSA(int i) { listBox2.Items.Clear();string S=""; for(int k=0;k<numPolish;k++) string X=Polish[k].operation+ "\t" + Polish[k].str; S="\n"+X; listBox2.Items.Add(X); } DialogResult result = MessageBox.Show(S,"構文解析途中経過2",MessageBoxButtons.OKCancel); if(result==DialogResult.Cancel) checkBox1.Checked=false;
構文解析 (2)構文解析・コード生成メイン処理① private void SA() { int i=0; while(i<numTokenX) if(tokenX[i].type==“Name” && tokenX[i].str==“if”) // if文 if論理式(ref i); // if文から論理式を取り出し numPolish=0; SA0(); numStatementNo++; int oldP=numStatement; SA設定("StNo",0,numStatementNo.ToString()); if(checkBox1.Checked) debugSA(0); 現Polishのオブジェクト設定(); IfPush(oldP,numStatement,0); SA設定("Number",0,""); SA設定("then",0,"then"); if(i+1 < numTokenX) MessageBox.Show("thenの後に文は書けません"); }
構文解析 (2)構文解析・コード生成メイン処理② else if(tokenX[i].type==“Name” && tokenX[i].str==“else”) // else処理 { IfStack[IfStackP].ThenP=numStatement; SA設定("Number",0,""); SA設定("goto",0,"goto"); numStatementNo++; AllStatement[IfStack[IfStackP].IfP].str=numStatement.ToString(); SA設定("StNo",0,numStatementNo.ToString()); if(i+1 < numTokenX) MessageBox.Show("elseの後に文は書けません"); } else if(tokenX[i].type=="Name" && tokenX[i].str=="endif") // end if int IP=IfStack[IfStackP].IfP; if(AllStatement[IP].str=="") AllStatement[IP].str=numStatement.ToString(); else AllStatement[IfStack[IfStackP].ThenP].str=numStatement.ToString(); if(i+1 < numTokenX) MessageBox.Show("endifの後に文は書けません"); IfStackP--;
構文解析 (2)構文解析・コード生成メイン処理③ else if(tokenX[i].type==“Name” && tokenX[i].str==“while”) // while文 { i++; token複写(ref i); numPolish=0; SA0(); numStatementNo++; int oldP=numStatement; SA設定("StNo",0,numStatementNo.ToString()); if(checkBox1.Checked) debugSA(0); 現Polishのオブジェクト設定(); DoPush(oldP,numStatement,0,"while"); SA設定("Number",0,""); SA設定("then",0,"then"); } else if(tokenX[i].type=="Name" && tokenX[i].str=="wend") numStatementNo++; SA設定("Number",0,DoStack[DoStackP].BP.ToString()); SA設定("goto",0,"goto"); string S=numStatement.ToString(); if (DoStack[DoStackP].Type=="while") AllStatement[DoStack[DoStackP].IfP].str=S; else MessageBox.Show("while_wendの対応がとれません.文="+numStatementNo.ToString()); for(int k=0;k<numBreak[DoStackP];k++) AllStatement[BreakP[DoStackP,k]].str=S; if(i+1 < numTokenX) MessageBox.Show ("wendの後に文は書けません.文="+numStatementNo.ToString()); DoStackP--;
構文解析 (2)構文解析・コード生成メイン処理④ else if(tokenX[i].type=="Name" && tokenX[i].str=="repeat") { numStatementNo++; int oldP=numStatement; SA設定("StNo",0,numStatementNo.ToString()); DoPush(oldP,numStatement,0,"repeat"); } else if(tokenX[i].type=="Name" && tokenX[i].str=="until") i++; token複写(ref i); numPolish=0; SA0(); if(checkBox1.Checked) debugSA(0); 現Polishのオブジェクト設定(); string BS=DoStack[DoStackP].BP.ToString(); SA設定("Number",0,BS); SA設定("then",0,"then"); string S=numStatement.ToString(); if (DoStack[DoStackP].Type !="repeat") MessageBox.Show("repeat_untilの対応がとれません.文="+numStatementNo.ToString()); for(int k=0;k<numBreak[DoStackP];k++) AllStatement[BreakP[DoStackP,k]].str=S; if (DoStackP>0) DoStackP--;
構文解析 (2)構文解析・コード生成メイン処理⑤ else if(tokenX[i].type=="Name" && tokenX[i].str=="for") { i++; for初期化(ref i); numPolish=0;SA0(); numStatementNo++; // 初期化式 SA設定("StNo",0,numStatementNo.ToString()); if(checkBox1.Checked) debugSA(0); 現Polishのオブジェクト設定(); numPolish=0; for判定(ref i); SA0(); // 判定式 for(int k=0;k<numPolish;k++)TempStatement[k]=Polish[k]; int numTemp=numPolish; int IGoto=numStatement; SA設定("Number",0,""); SA設定("goto",0,"goto"); int oldP=numStatement; for増分(ref i); numPolish=0; SA0(); // 増分式 AllStatement[IGoto].str=numStatement.ToString(); for(int k=0;k<numTemp;k++) AllStatement[numStatement++]=TempStatement[k]; DoPush(oldP,numStatement,0,"for"); SA設定("Number",0,""); SA設定("then",0,"then"); }
構文解析 (2)構文解析・コード生成メイン処理⑥ else if(tokenX[i].type=="Name" && tokenX[i].str=="next") { numStatementNo++; SA設定("StNo",0,numStatementNo.ToString()); SA設定("Number",0,DoStack[DoStackP].BP.ToString()); SA設定("goto",0,"goto"); string S=numStatement.ToString(); if (DoStack[DoStackP].Type=="for") AllStatement[DoStack[DoStackP].IfP].str=S; else MessageBox.Show("for_nextの対応がとれません.文="+numStatementNo.ToString()); S=numStatement.ToString(); for(int k=0;k<numBreak[DoStackP];k++) AllStatement[BreakP[DoStackP,k]].str=S; if(i+1 < numTokenX) MessageBox.Show ("nextの後に文は書けません.文="+numStatementNo.ToString()); DoStackP--; break; } else if(tokenX[i].type=="Name" && tokenX[i].str=="break") BreakP[DoStackP,numBreak[DoStackP]++]=numStatement; SA設定("Number",0,""); if(i+1 < numTokenX) MessageBox.Show("breakの後に文は書けません");
構文解析 (2)構文解析・コード生成メイン処理⑦ else if(tokenX[i].type=="Name" && tokenX[i].str=="function") { i++; if (tokenX[i].type != "Name") MessageBox.Show("関数名がありません。"+tokenX[i].str); } else FunctionNameTable[numberOfFunction].name=tokenX[i].str; int ID=0; while(FunctionNameTable[ID].name != tokenX[i].str) ID++; if(ID>=numberOfFunction) numberOfFunction++; FunctionNameTable[ID].ptr=numStatement; numStatementNo++; SA設定("StNo",0,numStatementNo.ToString()); if(checkBox1.Checked) string S=“関数名 : ” +FunctionNameTable[ID].name + " address : " +FunctionNameTable[ID].ptr; DialogResult result = MessageBox.Show (S, "構文解析途中経過2",MessageBoxButtons.OKCancel); if(result==DialogResult.Cancel) checkBox1.Checked=false; i++;
構文解析 (2)構文解析・コード生成メイン処理⑧ if(tokenX[i].type !="Delimiter" || tokenX[i].str!="(") MessageBox.Show("左括弧がありません。"+tokenX[i].str); i++; SA設定("*PStart*",0,"*PStart*"); if(i<numTokenX){ while(i<numTokenX){ if(tokenX[i].type=="Name"){ AllStatement[numStatement].operation="*Parm*"; AllStatement[numStatement].priority=0; AllStatement[numStatement].str=tokenX[i].str; numStatement++; if(checkBox1.Checked){ DialogResult result = MessageBox.Show ("仮引数 : "+tokenX[i].str,"構文解析途中経過2",MessageBoxButtons.OKCancel); if(result==DialogResult.Cancel) checkBox1.Checked=false; } else MessageBox.Show("引数名がありません。"+tokenX[i].str); i++; if(!(tokenX[i].type =="Delimiter" &&( tokenX[i].str!=","|| tokenX[i].str!=")"))) MessageBox.Show("コンマ,または右括弧がありません。"+tokenX[i].str); } SA設定("*PEnd*",0,"*PEnd*"); }
構文解析 (2)構文解析・コード生成メイン処理⑨ else if(tokenX[i].type=="Name" && tokenX[i].str=="dim") { i++; string ArrayName; numStatementNo++; SA設定("StNo",0,numStatementNo.ToString()); while(i<numTokenX) ArrayName=tokenX[i].str; token複写Comma(ref i); numPolish=0; SA0(); SA設定("*dimStart",0,ArrayName); if(checkBox1.Checked) listBox2.Items.Clear(); for(int k=0;k<numPolish;k++) listBox2.Items.Add(Polish[k].operation+ "\t" + Polish[k].priority.ToString()+ "\t" + Polish[k].str); } Polish[numPolish-1].operation ="dim"; 現Polishのオブジェクト設定(); if(checkBox1.Checked) debugSA(i);
構文解析 (2)構文解析・コード生成メイン処理⑩ else if(tokenX[i].type=="Name" && tokenX[i].str=="end") { numStatementNo++; SA設定("StNo",0,numStatementNo.ToString()); SA設定("end",0,"end"); if(i+1 < numTokenX) MessageBox.Show ("endの後に文は書けません.文="+numStatementNo.ToString()); break; } else if(tokenX[i].type=="Name" && tokenX[i].str=="return") i++; token複写(ref i); numPolish=0; SA0(); int oldP=numStatement; if(checkBox1.Checked) debugSA(0); 現Polishのオブジェクト設定(); SA設定("return",0,"return"); string S=numStatement.ToString();
構文解析 (2)構文解析・コード生成メイン処理⑪ else { // 代入文 token複写(ref i); numPolish=0; SA0(); numStatementNo++; SA設定("StNo",0,numStatementNo.ToString()); if(checkBox1.Checked) { listBox2.Items.Clear(); for(int k=0;k<numPolish;k++) listBox2.Items.Add(Polish[k].operation+ "\t" + Polish[k].priority.ToString()+ "\t" + Polish[k].str); } 現Polishのオブジェクト設定(); if(checkBox1.Checked) debugSA(i); i++;
構文解析 (3)設定用関数① private void if論理式(ref int i) // ifの論理式 { numToken=0;i++; if(i<numTokenX) { while(i<numTokenX){ if(tokenX[i].type=="Name" && tokenX[i].str=="then"){i++;break;} token[numToken++]=tokenX[i++]; } } } private void for初期化(ref int i) // forの初期化式 { numToken=0; if(tokenX[i].type=="Delimiter" && tokenX[i].str==";"){i++;break;} private void for判定(ref int i) // forの判定式 private void for増分(ref int i) // forの増分式
構文解析 (3)設定用関数② private void SA設定(string op, int pr, string str) { AllStatement[numStatement].operation=op; AllStatement[numStatement].priority=pr; AllStatement[numStatement].str=str; numStatement++; } private void IfPush(int BP, int IfP,int ThenP) { IfStackP++; IfStack[IfStackP].BP=BP; IfStack[IfStackP].IfP=IfP; IfStack[IfStackP].ThenP=ThenP; IfStack[IfStackP].Type="if"; private void DoPush(int BP, int IfP,int ThenP, string Type) { DoStackP++; DoStack[DoStackP].BP=BP; DoStack[DoStackP].IfP=IfP; DoStack[DoStackP].ThenP=ThenP; DoStack[DoStackP].Type=Type; numBreak[DoStackP]=0; private void 現Polishのオブジェクト設定() { for(int k=0;k<numPolish;k++) AllStatement[numStatement++]=Polish[k]; }
逆ポーランド記法のまま実行するには, スタックマシンとして実行する これによってインタプリタを実現できる。 評価用のスタックが必要。 ただし,代入等の処理が必要なので, 演算等により値が必要になった時点で評価する。 配列は,本来,該当サイズの領域を確保する必要があるが, ここでは,配列添え字と組み合わせた文字列の変数 たとえば「A(1,2,3)」として処理する。
バインディングの方法 (呼出時) ①リターンアドレスをプログラムスタックにpush ②仮引数名と値をプログラムスタックにpush ③演算スタックをPopし,仮引数名に実引数の値を割り当てる。 (リターン時) ①仮引数の値をプログラムスタックからPopして元に戻す。 ②リターンアドレスをプログラムスタックからPopして元に戻す。 ③リターン値を演算スタックにPushする。
バインディングの方法 手続き ①仮引数Push ②値割り当て ③関数実行 ④リターン 演算スタック A2 A1 返却値 プログラム カウンタ 関数アドレス 変数名テーブル 変数名テーブル 変数名テーブル P1:V1 P1:A1 P1:V1 関数実行 プログラム カウンタ P2:V2 P2:A2 P2:V2 Return プログラムスタック P2:V2 P2:V2 P2:V2 P1:V1 P1:V1 P1:V1 リターンアドレス リターンアドレス リターンアドレス リターンアドレス
インタプリタのデータ宣言① public struct NameData // 変数名の構造体 { public string Name; public string Text; public double Val; public string Type; public NameData(string name, double val) Name=name; Val=val; Text=val.ToString(); Type="Number"; } public NameData(string name, string val) Name=name; Val=0.0; Text=val; Type="String"; public NameData(string name) Name=name; Val=0.0; Text=""; Type="Name";
インタプリタのデータ宣言② public struct BlockData // 実行用ブロックコントロールデータ { public string Type; public int BP; public int IfP; public int ThenP; } public struct FunctionName // 関数名データ public string name; public int ptr; public FunctionName [] FunctionNameTable =new FunctionName[200]; public int numberOfFunction=0; public NameData[] argData =new NameData[200]; public int numArg=0; public int ptrArg=0; public int nextIP; public NameData [] NameTable = new NameData[200]; public int ptrNameTable=0; public NameData [] EvalStack = new NameData[200]; public int ptrEvalStack=0; public NameData[] ProgStack=new NameData[2000]; public int ptrProgStack=0 ;
private void button3_Click(object sender, System.EventArgs e) { ptrProgStack=0;Eval();Eval_Display_Result(numStatement+1);} private void Eval() { NameData P1,P2; int i=0; pushEvalStack(new NameData("*Function*")); while(i<numStatement) { if(checkBox1.Checked)debugEval(i); nextIP =i+1; if (AllStatement[i].operation=="end") { MessageBox.Show("プログラムの終了です。カウンタ=" + i.ToString()); break;} switch (AllStatement[i].operation) { case "+" :Eval_add();break; case "-" :Eval_sub();break; case "%" :Eval_mod();break; case "*" :Eval_mult();break; case "mod" :Eval_mod();break; case "/" :Eval_dev();break; case "^" :Eval_exp();break; case "=" :Eval_set();break; case "++" :Eval_PPset();break; case "--" :Eval_MMset();break; case "++$" :Eval_BeforPPset();break; case "--$" :Eval_BeforMMset();break; case "-$" :Eval_minus();break; case "+$" :Eval_plus();break; case "+=" :Eval_AsignPset();break; case "-=" :Eval_AsignMset();break; case "*=" :Eval_AsignMultset();break; case "/=" :Eval_AsignDivset();break; case "==" :Eval_equal();break; case "!=" :Eval_not_equal();break; case ">" :Eval_greater_than();break; インタプリタメイン①
インタプリタメイン② case ">=" :Eval_greater_than_equal();break; case "<" :Eval_less_than();break; case "<=" :Eval_less_than_equal();break; case "||" :Eval_or();break; case "&&" :Eval_and();break; case "%%" :Eval_exclusive_or();break; case "!" :Eval_not();break; case "ArgEnd" :Eval_Arg();break; case "Func" :Eval_func(AllStatement[i].str);break; case "*dimStart" :Eval_dimStart(AllStatement[i].str);break; case "dim" :Eval_dim();break; case "*PStart*" :Eval_PStart();break; case "*Parm*" :Eval_Param(AllStatement[i].str);break; case "return" :Eval_return();break; case "StNo" : StatementNo=int.Parse(AllStatement[i].str); if(checkBox1.Checked) MessageBox.Show("Statement No = "+AllStatement[i].str); ptrEvalStack=0;break; case "goto" : P1=Eval(popEvalStack()); nextIP=(int)P1.Val; break; case "then" : P2=Eval(popEvalStack()); P1=Eval(popEvalStack()); if(P1.Type=="Number" && P2.Type=="Number" ) { if(P1.Val ==0) nextIP=(int)P2.Val; } else MessageBox.Show("評価エラーです"); break; default :pushEvalStack(AllStatement[i]);break; } i=nextIP; Eval_Display_Result(i); } } インタプリタメイン②
トレース用ルーチン private void debugEval(int i) { string S1=AllStatement[i].operation; string S2=AllStatement[i].str; if(S1!=S2) { if(S1=="String") S1 += ("\"" + S2+"\""); else S1 += ("(" + S2+")"); } string S="*Operation " +S1 + "\n\n*PC=" + i + " StNo=" + StatementNo.ToString(); int k; S += "\n\n*Name Table\n"; for(k=0; k<ptrNameTable; k++) { S +=NameTable[k].Name+"\t"; if(NameTable[k].Type=="Number") S +="Number[" + NameTable[k].Val+"]\n"; else S +=NameTable[k].Type+"[" + NameTable[k].Text+"]\n"; S += "\n*Eval Stack\n"; for(k=ptrEvalStack-1; k>=0; k--) { S +=EvalStack[k].Name+"\t"; if (EvalStack[k].Type=="Name") S += "Name\n"; else if(EvalStack[k].Type=="Number") S +="Number[" + EvalStack[k].Val+"]\n"; else S +=EvalStack[k].Type+"\"" + EvalStack[k].Text+"\"\n"; DialogResult result = MessageBox.Show(S,"評価",MessageBoxButtons.OKCancel); if(result==DialogResult.Cancel) checkBox1.Checked=false;
実行用メソッド① private void pushEvalStack(TokenData TK) // TokenのPush { switch (TK.operation) { case "String" : EvalStack[ptrEvalStack]=new NameData("",TK.str);break; case "Number" : EvalStack[ptrEvalStack]=new NameData("",double.Parse(TK.str));break; case "Name" : EvalStack[ptrEvalStack]=new NameData(TK.str);break; default : EvalStack[ptrEvalStack]=new NameData("",0.0); //MessageBox.Show("未だサポートしていません"+TK.operation); break; } ptrEvalStack++; private void pushEvalStack(NameData NM) // 変数名のPush { EvalStack[ptrEvalStack]=NM; private void Eval_dimStart(String S) // dim 文の開始 { EvalStack[ptrEvalStack]=new NameData(S); EvalStack[ptrEvalStack].Type="*dimStart"; private void Eval_Array_gen(string nameDT,NameData[] P,int N,string S) // 配列生成 { if(N<0) NameTable[ptrNameTable++]=new NameData(nameDT+"("+S+")"); else for(int i=1;i<=P[N].Val;i++)Eval_Array_gen(nameDT,P,N-1,S +","+i.ToString());
実行用メソッド② private void Eval_dim() // dim文の実行 { NameData[] P =new NameData[200]; NameData P1=popEvalStack(); if(P1.Type=="=*dimStart") NameTable[ptrNameTable++]=new NameData(P1.Name); else { int numArg=0; while(ptrEvalStack>=0 && P1.Type!="ARGEND"){ P[numArg++]=P1; P1 =popEvalStack();} P1=popEvalStack(); if(P1.Type!="*dimStart") MessageBox.Show("**System Error(Dim文)"); { int N=numArg-1; if( N>=0) for(int i=0;i<=P[N].Val-1;i++)Eval_Array_gen(P1.Name,P,N-1,i.ToString()); } } } private void Eval_Arg() // 引数終了 { EvalStack[ptrEvalStack]=new NameData("ARGEND"); EvalStack[ptrEvalStack].Type="ARGEND"; ptrEvalStack++; } private NameData popEvalStack() // ポップ:ただし,初期値はUndefinedとする。 { NameData P=new NameData("$$Undefined$$"); if(ptrEvalStack>0) { ptrEvalStack--; P=EvalStack[ptrEvalStack]; return P;
実行用メソッド③ private NameData Eval(NameData NM) // 変数値を求める { switch (NM.Type) { case "String": return NM; case "Number": return NM; case "Refer" : return Eval(NameTable[(int)NM.Val]); default : if(NM.Name=="$$Undefined$$") return new NameData("",0.0); NameTable[ptrNameTable]=NM; // 変数名テーブルの探索 int ID=-1; for(int i=ptrNameTable-1;i>=0;i--) if(NameTable[i].Name==NM.Name){ ID=i;break;} if(ID<0) // 変数名テーブルになければ変数を登録する { NameTable[ptrNameTable]=NM; ptrNameTable++; return new NameData(NM.Name,0.0); } else // 変数名スコープでReferなら上位を参照 { while (NameTable[ID].Type=="Refer") ID=(int)NameTable[ID].Val; return NameTable[ID];
実行用メソッド④ private void Eval_add() { NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack()); if(P1.Type=="Number" && P2.Type=="Number") pushEvalStack(new NameData("",P1.Val + P2.Val)); else if(P1.Type=="String" && P2.Type=="String") pushEvalStack(new NameData("",P1.Text + P2.Text)); else if(P1.Type=="String" && P2.Type=="Number") pushEvalStack(new NameData("",P1.Text + P2.Val.ToString())); else if(P1.Type=="Number" && P2.Type=="String") pushEvalStack(new NameData("",P1.Val.ToString() + P2.Text)); else pushEvalStack(new NameData("",0)); } private void Eval_sub() pushEvalStack(new NameData("",P1.Val - P2.Val)); else pushEvalStack(new NameData("","計算できません")); private void Eval_mult() pushEvalStack(new NameData("",P1.Val * P2.Val)); private void Eval_dev() pushEvalStack(new NameData("",P1.Val / P2.Val));
実行用メソッド⑤ private void Eval_exp() { NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack()); if(P1.Type=="Number" && P2.Type=="Number") pushEvalStack(new NameData("",Math.Pow(P1.Val,P2.Val))); else pushEvalStack(new NameData("","計算できません")); } private void Eval_mod() pushEvalStack(new NameData("",(long)(P1.Val) % (long)(P2.Val))); private void Eval_minus() { NameData P1=Eval(popEvalStack()); if(P1.Type=="Number") pushEvalStack(new NameData("",-P1.Val)); private void Eval_plus() if(P1.Type=="Number") pushEvalStack(new NameData("",P1.Val)); private void Eval_Boolean(bool R) // 論理値のプッシュ { if(R) pushEvalStack(new NameData("",-1)); else pushEvalStack(new NameData("",0));
実行用メソッド⑥ private void Eval_equal() { NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack()); if (P1.Type=="Number" && P2.Type=="Number" ) Eval_Boolean(P1.Val == P2.Val); else if(P1.Type=="String" && P2.Type=="String" ) Eval_Boolean(string.Compare(P1.Text, P2.Text)==0); else Eval_Boolean(false); } private void Eval_not_equal() if (P1.Type=="Number" && P2.Type=="Number" ) Eval_Boolean(P1.Val != P2.Val); Eval_Boolean(string.Compare(P1.Text, P2.Text)!=0); else Eval_Boolean(true); private void Eval_greater_than() if (P1.Type=="Number" && P2.Type=="Number" ) Eval_Boolean(P1.Val > P2.Val); Eval_Boolean(string.Compare(P1.Text, P2.Text)>0); else pushEvalStack(new NameData("","計算できません")); private void Eval_greater_than_equal() if (P1.Type=="Number" && P2.Type=="Number" ) Eval_Boolean(P1.Val >= P2.Val); Eval_Boolean(string.Compare(P1.Text, P2.Text)>=0);
実行用メソッド⑦ private void Eval_less_than() { NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack()); if (P1.Type=="Number" && P2.Type=="Number" ) Eval_Boolean(P1.Val < P2.Val); else if(P1.Type=="String" && P2.Type=="String" ) Eval_Boolean(string.Compare(P1.Text, P2.Text)<0); else pushEvalStack(new NameData("","計算できません")); } private void Eval_less_than_equal() if (P1.Type=="Number" && P2.Type=="Number" ) Eval_Boolean(P1.Val <= P2.Val); Eval_Boolean(string.Compare(P1.Text, P2.Text)<=0); private void Eval_or() if (P1.Type=="Number" && P2.Type=="Number" ) Eval_Boolean((P1.Val !=0) || (P2.Val !=0)); private void Eval_and() Eval_Boolean((P1.Val !=0) && (P2.Val !=0));
実行用メソッド⑧ private void Eval_exclusive_or() { NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack()); if (P1.Type=="Number" && P2.Type=="Number" ) Eval_Boolean((P1.Val !=0) ^ (P2.Val !=0)); else pushEvalStack(new NameData("","計算できません")); } private void Eval_not() { NameData P1=Eval(popEvalStack()); if (P1.Type=="Number" ) Eval_Boolean(!(P1.Val !=0)); private int Eval_set_search(NameData P) // 代入用変数名テーブルの探索 { for(int i=ptrNameTable-1;i>=0;i--) if(NameTable[i].Name==P.Name) return i; return -1; private int Eval_set_pointer(NameData P) // 代入すべき変数名の探索(Referを考慮) { int ID=Eval_set_search(P); if(ID>=0) { while(NameTable[ID].Type=="Refer") { if(checkBox1.Checked) MessageBox.Show(NameTable[ID].Name +" Type=" + NameTable[ID].Type +" Val=" +NameTable[ID].Val); ID=(int)(NameTable[ID].Val); if(checkBox1.Checked) else{ NameTable[ptrNameTable]=P;ID=ptrNameTable++;} return ID;
実行用メソッド⑧ private void Eval_set() // 代入処理 { NameData P2=Eval(popEvalStack()); NameData P1=popEvalStack(); int i=Eval_set_pointer(P1); if(checkBox1.Checked) MessageBox.Show("Set ("+i+") Name=" + NameTable[i].Name + " Type=" + NameTable[i].Type + " Val=" + NameTable[i].Val+ "\n Assign Type” + P2.Type+ " Val=” + P2.Val+ " Text=\"” +P2.Text + "\""); NameTable[i].Text=P2.Text; NameTable[i].Type=P2.Type; NameTable[i].Val =P2.Val; pushEvalStack(P2); } private void Eval_PPset() // 後置++ { NameData P1=popEvalStack(); pushEvalStack(Eval(P1)); NameTable[i].Val++; private void Eval_MMset() // 後置-- NameTable[i].Val--;
実行用メソッド⑨ private void Eval_AsignPset() // += { NameData P2=Eval(popEvalStack()); NameData P1=popEvalStack(); int i=Eval_set_pointer(P1); if(NameTable[i].Type=="Number" && P2.Type=="Number") NameTable[i].Val += P2.Val; else if(NameTable[i].Type=="Number" && P2.Type=="String") { NameTable[i].Type= "String"; NameTable[i].Text= NameTable[i].Val.ToString() + P2.Text; } else if(NameTable[i].Type=="String" && P2.Type=="Number") NameTable[i].Text= NameTable[i].Text + P2.Val; else NameTable[i].Text= NameTable[i].Text + P2.Text; pushEvalStack(Eval(P1));
実行用メソッド⑩ private void Eval_AsignMset() // -= { NameData P2=Eval(popEvalStack()); NameData P1=popEvalStack(); int i=Eval_set_pointer(P1); if(NameTable[i].Type=="Number" && P2.Type=="Number") NameTable[i].Val -= P2.Val; else MessageBox.Show("演算の型が異なります"); pushEvalStack(Eval(P1)); } private void Eval_AsignMultset() // *= if(NameTable[i].Type=="Number" && P2.Type=="Number") NameTable[i].Val *= P2.Val; private void Eval_AsignDivset() // /= if(NameTable[i].Type=="Number" && P2.Type=="Number") NameTable[i].Val /= P2.Val; private void Eval_BeforPPset() // 前置++ { NameData P1=popEvalStack(); NameTable[ptrNameTable]=P1; int i=Eval_set_pointer(P1); NameTable[i].Val++;
実行用メソッド⑪ private void Eval_BeforMMset() // 前置-- { NameData P1=popEvalStack(); NameTable[ptrNameTable]=P1; int i=Eval_set_pointer(P1); NameTable[i].Val--; pushEvalStack(Eval(P1)); } private NameData Eval_func(string S, double V, string T) // 関数定義 { NameData P1=new NameData(""); P1.Type=T; P1.Val=V; P1.Text=S; return P1; private void Eval_funCall(FunctionName FName) // 関数呼出し:シャドウバインディング { int prt=FName.ptr; string S=FName.name; int i; ProgStack[ptrProgStack++]=new NameData("*progStart",(double)nextIP); while(ptrEvalStack>0) // 実引数をPop,プログラムスタックにPush { NameData P1=popEvalStack(); if (P1.Type !="Number" && P1.Type !="String") i = Eval_set_pointer(P1); ProgStack[ptrProgStack++]=P1; nextIP=prt; // Return Addressの設定 if(checkBox1.Checked) MessageBox.Show( "Call Address="+nextIP.ToString()); int P=ptrNameTable; NameTable[ptrNameTable++]=new NameData("*function*",S); NameTable[P].Val=StatementNo;
実行用メソッド⑫ private void Eval_return() // 復帰処理 { NameData P1=Eval(popEvalStack()); ptrEvalStack=0; while(ptrProgStack>0) { NameData P2=ProgStack[--ptrProgStack]; if(P2.Name=="*progStart") { nextIP=(int)P2.Val; if(checkBox1.Checked) MessageBox.Show("Return Address="+nextIP); break; } pushEvalStack(P2); if(checkBox1.Checked) MessageBox.Show("ProgStack Value="+P2.Name); pushEvalStack(P1); if(checkBox1.Checked) MessageBox.Show("return Value="+P1.Val); while(ptrNameTable>0) // 変数名テーブルの復帰 { NameData P2=NameTable[--ptrNameTable]; if(P2.Name=="*function*") { StatementNo=(int)P2.Val; if(checkBox1.Checked) MessageBox.Show("Return Statement="+StatementNo.ToString());
実行用メソッド⑬ private void Eval_PStart() { ptrArg=numArg; if(checkBox1.Checked) MessageBox.Show(" Arg番号 " + ptrArg.ToString()); } private void Eval_Param(string Pname) // パラメータの設定 { int i,j; if( ptrArg<=0){ MessageBox.Show("引数の数が合いません.");return;} NameData P2=argData[--ptrArg]; i=ptrNameTable; NameTable[ptrNameTable++]=new NameData(Pname); switch (P2.Type) { case "Number": case "String":NameTable[i].Type=P2.Type; NameTable[i].Text=P2.Text; NameTable[i].Val=P2.Val; break; default: j=ptrNameTable-1; while (j>=0 && NameTable[j].Name !="*function*") j--; while (j>=0 && NameTable[j].Name !=P2.Name)j--; if (NameTable[j].Name !=P2.Name) { MessageBox.Show("変数"+P2.Name + "が見つかりません."); NameTable[i].Type="Number"; NameTable[i].Val=0; else { NameTable[i].Type="Refer"; NameTable[i].Val=j;} break; if(checkBox1.Checked) { string S="*Parameter ptrArg=" + ptrArg.ToString()+" 変数番号 " + i.ToString() + " 仮引数名 " +NameTable[i].Name + "\n型 " +NameTable[i].Type+ " Val=" +NameTable[i].Val +" Text=\"" +NameTable[i].Text+"\""; MessageBox.Show(S);
実行用メソッド⑭ private void Eval_func(string Fname) { NameData P1 =popEvalStack(); numArg=0; while(ptrEvalStack>0 && P1.Type!="ARGEND") {argData[numArg]=P1; numArg++; P1 =popEvalStack();} string S=""; double V=0.0; string T="Number"; FunctionNameTable[numberOfFunction].name=Fname; int i=0; while(FunctionNameTable[i].name!=Fname)i++; if(i!=numberOfFunction) Eval_funCall(FunctionNameTable[i]); else { switch (Fname) { case "sin" : P1=Eval_func(S,Math.Sin(Eval(argData[0]).Val),T);break; case "cos" : P1=Eval_func(S,Math.Cos(Eval(argData[0]).Val),T);break; case "tan" : P1=Eval_func(S,Math.Tan(Eval(argData[0]).Val),T);break; case "abs" : P1=Eval_func(S,Math.Abs(Eval(argData[0]).Val),T);break; case "ToString" : P1=Eval_func(Eval(argData[0]).Val.ToString(),V,"String");break; case "MsgBox" : P1=Eval(argData[0]); if(P1.Type=="Number") S=P1.Val.ToString(); else S=P1.Text; MessageBox.Show(S); P1=Eval_func(S,0,"String");break; default : NameData PX=Eval(argData[numArg-1]); S=Fname +"("+PX.Val.ToString(); for(i=numArg-2;i>=0;i--) {PX=Eval(argData[i]); S += ","+PX.Val.ToString();} S += ")"; i=Eval_set_pointer(new NameData(S)); P1=Eval(NameTable[i]); break; } pushEvalStack(P1); } }
実行用メソッド⑮ private void Eval_Display_Result(int ProgramCounter) { listBox3.Items.Clear(); string S="**PC = " + ProgramCounter.ToString()+ " StNo = " + StatementNo.ToString(); listBox3.Items.Add(S); listBox3.Items.Add(""); for(int i=0;i<ptrNameTable;i++) { S=NameTable[i].Name+ "\t" + NameTable[i].Type + " :\t" ; if(NameTable[i].Type=="String") S += "\"" + NameTable[i].Text +"\""; else S += NameTable[i].Val.ToString(); listBox3.Items.Add(S); } listBox3.Items.Add(""); listBox3.Items.Add("関数名"); for(int i=0;i<numberOfFunction;i++) { S=FunctionNameTable[i].name+ "\t" + FunctionNameTable[i].ptr; listBox3.Items.Add(""); listBox3.Items.Add("プログラムスタック ("+ptrProgStack+")"); for(int i=ptrProgStack-1;i>=0;i--) { S="Name ="+ProgStack[i].Name+ " Type=" +ProgStack[i].Type+ " Text=" +ProgStack[i].Text+ " Val=" + ProgStack[i].Val;