680 likes | 691 Views
プログラミング言語 作成の実際. しらいゆたか. 言語プロセッサの処理. 次の手順で処理する。 (1)文識別 (2)語彙解析( Lexical Analysis ) (3)構文解析( Syntax Analysis ) (4)意味解析( Semantic Analysis ) およびコード生成( Code Generation ) さらに,インタプリタの場合,実行( Execution ). 1.文識別. 最初に行うのは, 1 文を取り出す処理。 ■ 1 行の中に複数の文 ■ 2 行以上で 1 文 語彙解析の途中で,文の終わりを判別するのは
E N D
プログラミング言語作成の実際 しらいゆたか
言語プロセッサの処理 次の手順で処理する。 (1)文識別 (2)語彙解析(Lexical Analysis) (3)構文解析(Syntax Analysis) (4)意味解析(Semantic Analysis) およびコード生成(Code Generation) さらに,インタプリタの場合,実行(Execution)
1.文識別 最初に行うのは,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++; } 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]=='"'){ S += AllText[ptrText].ToString(); ptrText++; if((ptrText>=AllText.Length) || (AllText[ptrText]!='"')) break; } S+=AllText[ptrText].ToString();ptrText++; } } S=S+AllText[ptrText].ToString(); ptrText++; } return S; } 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"; public string 区切記号=";,.+-/*^=:<>[]()|&%!{}"; 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(); ptr++; } MessageBox.Show("\"がありません"); return new WordData("String",S); }
最も低レベルの文字列の判別(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); token1=LA0();token2=LA0();token3=LA0();token4=LA0(); } 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); token1=token3;token2=token4;token3=LA0();token4=LA0(); }
単語の識別(3) else if(token1.type=="Delimiter" && token1.str==">" && token2.type=="Delimiter" && token2.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=="<" ){ 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=="=" ){ 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=="|" ){ 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=="&" ){ 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=="%" ){ combineDelimiter(token1.str,token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); }
単語の識別(4) else if(token1.type=="Delimiter" && token1.str=="!" && token2.type=="Delimiter" && token2.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=="="){ 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=="+"){ 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=="-"){ 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=="="){ combineDelimiter(token1.str,token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); }
単語の識別(5) else if(token1.type=="Delimiter" && token1.str=="-" && token2.type=="Delimiter" && token2.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=="="){ 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=="="){ combineDelimiter(token1.str,token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); } else if(token1.type=="Name" && token1.str=="end" && token2.type=="Name" && token2.str=="if"){ set_TokenX(token1.type,token1.str+token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); } else{ set_TokenX(token1.type,token1.str); token1=token2;token2=token3;token3=token4;token4=LA0(); } } }
3.構文解析 語彙解析の結果から文を判別して, 一文の解析結果を作成する。 ただし,式の場合は,優先順位を判別する必要がある。 基本的には,逆ポーランド記法に展開する。 文全体の処理と逆ポーランド記法への変換を分ける。
逆ポーランド記法変換 ①変数や定数はそのまま出力トークンへ移動する。 ②演算子はスタック上の演算子と比較し,スタック上の演算子の優先度が取り出した演算子と等しいか大きい場合,スタック上の演算子をポップして出力トークンに移動する。 ④取り出した演算子をプッシュする。 ⑤前括弧の場合,プッシュする。 ⑥後括弧の場合,前括弧までをポップする。このとき,スタックトップが関数表現ならば,関数呼出しを出力トークンに移動する。 ⑦関数表現の場合,関数表現と前括弧をプッシュする。 ⑧コンマの場合,前括弧の直前までポップする。 ⑨1文終わりのときは後括弧と同じ処理を行う。
演算子等の解釈 ①演算子モードと値モードを用意し,初期値は値モードとする。 ②値モードのとき,演算子がきたら前置単項演算子とみなす。 ③演算子モードのとき,前括弧がきたら,先行する名前は関数表現とみなし,値モードに移行する。 ④演算子モードのとき,後置演算子か通常の演算子かを判定する。 後置演算子でない場合,値モードに移行する。 ⑤コンマのとき,値モードに移行する。 ⑥前括弧の場合,値モードに移行する。 ⑦後括弧の場合,演算子モードに移行する。
逆ポーランド記法への変換(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)データ領域宣言逆ポーランド記法への変換(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=="--")) pushProc(new TokenData(token[i].str+“$”,300,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;// 標準的には値モードに移行 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=="-=")) pushProc(new TokenData(token[i].str,10,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=="=") pushProc(new TokenData(token[i].str,10,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)); else if(token[i].type=="Delimiter" && (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)); } else if(token[i].type=="Delimiter" && (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"){ popProcBlock(); postFix(new TokenData(token[i].str,0,token[i].str)); Mode=true; } else { MessageBox.Show("002 名前の位置または演算子の誤り"); break; } } i++; } if(checkBox1.Checked) debugSA0(i,Mode); popProcE(); }
逆ポーランド記法への変換(4)データ領域アクセス①逆ポーランド記法への変換(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)データ領域アクセス②逆ポーランド記法への変換(4)データ領域アクセス② public void popProcF() { TokenData XX = pop(); while(ptrStack>=0) { if(XX.operation=="Func"){push(XX); break;} postFix(XX); XX=pop(); } } public void popProcBlock() { TokenData XX = pop(); while(ptrStack>=0) { if(XX.operation=="Block")break; postFix(XX); XX=pop(); } } public void popProcE() { TokenData XX; XX=pop(); while(ptrStack>0) { postFix(XX);XX=pop();} if(XX.operation!="Empty")postFix(XX); }
逆ポーランド記法への変換(5)変換用トークンの複写逆ポーランド記法への変換(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; while(i<numTokenX) { 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; token[numToken]=tokenX[i];numToken++; i++; } }
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)構文解析・コード生成メイン処理①構文解析(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)構文解析・コード生成メイン処理②構文解析(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 { numStatementNo++; SA設定("StNo",0,numStatementNo.ToString()); 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)構文解析・コード生成メイン処理③構文解析(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設定("StNo",0,numStatementNo.ToString()); 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)構文解析・コード生成メイン処理④構文解析(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(); numStatementNo++; int oldP=numStatement; SA設定("StNo",0,numStatementNo.ToString()); 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)構文解析・コード生成メイン処理⑤構文解析(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();// 判定式 if(checkBox1.Checked) debugSA(0); 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; SA設定("StNo",0,numStatementNo.ToString()); for増分(ref i); numPolish=0; SA0(); // 増分式 if(checkBox1.Checked) debugSA(0); 現Polishのオブジェクト設定(); 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)構文解析・コード生成メイン処理⑥構文解析(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") { numStatementNo++; SA設定("StNo",0,numStatementNo.ToString()); BreakP[DoStackP,numBreak[DoStackP]++]=numStatement; SA設定("Number",0,""); SA設定("goto",0,"goto"); if(i+1 < numTokenX) MessageBox.Show("breakの後に文は書けません"); break; }
構文解析(2)構文解析・コード生成メイン処理⑦構文解析(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)構文解析・コード生成メイン処理⑧構文解析(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); i++; } } SA設定("*PEnd*",0,"*PEnd*"); } }
構文解析(2)構文解析・コード生成メイン処理⑨構文解析(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); i++; } }
構文解析(2)構文解析・コード生成メイン処理⑩構文解析(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(); numStatementNo++; int oldP=numStatement; SA設定("StNo",0,numStatementNo.ToString()); if(checkBox1.Checked) debugSA(0); 現Polishのオブジェクト設定(); SA設定("return",0,"return"); string S=numStatement.ToString(); }
構文解析(2)構文解析・コード生成メイン処理⑪構文解析(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(i<numTokenX) { while(i<numTokenX){ if(tokenX[i].type=="Delimiter" && tokenX[i].str==";"){i++;break;} token[numToken++]=tokenX[i++]; } } } private void for判定(ref int i)// forの判定式 { numToken=0; if(i<numTokenX) { while(i<numTokenX){ if(tokenX[i].type=="Delimiter" && tokenX[i].str==";"){i++;break;} token[numToken++]=tokenX[i++]; } } } private void for増分(ref int i) // forの増分式 { numToken=0; if(i<numTokenX) { while(i<numTokenX){ if(tokenX[i].type=="Delimiter" && tokenX[i].str==";"){i++;break;} token[numToken++]=tokenX[i++]; } } }
構文解析(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;