プログラミング言語 作成の実際

プログラミング言語
作成の実際
しらいゆたか
言語プロセッサの処理
次の手順で処理する。
(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();
}
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();
}
単語の識別(3)
単語の識別(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)トレース用ルーチン
// このルーチンを残しておくことでモードがどのように移行しているかをチェックできる。
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=="--"))
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)データ領域アクセス①
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()
{
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)変換用トークンの複写
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)構文解析・コード生成メイン処理①
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
{
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)構文解析・コード生成メイン処理③
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)構文解析・コード生成メイン処理④
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)構文解析・コード生成メイン処理⑤
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)構文解析・コード生成メイン処理⑥
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)構文解析・コード生成メイン処理⑦
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);
i++;
}
}
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);
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();
numStatementNo++;
int oldP=numStatement;
SA設定("StNo",0,numStatementNo.ToString());
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(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
P2:V2
P2:A2
プログラム
カウンタ
変数名テーブル
関数実行
P1:V1
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;
ptrEvalStack++;
}
private void Eval_dimStart(String S) // dim 文の開始
{ EvalStack[ptrEvalStack]=new NameData(S);
EvalStack[ptrEvalStack].Type="*dimStart";
ptrEvalStack++;
}
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文)");
else
{
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()
{ NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack());
if(P1.Type=="Number" && P2.Type=="Number")
pushEvalStack(new NameData("",P1.Val - P2.Val));
else pushEvalStack(new NameData("","計算できません"));
}
private void Eval_mult()
{ NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack());
if(P1.Type=="Number" && P2.Type=="Number")
pushEvalStack(new NameData("",P1.Val * P2.Val));
else pushEvalStack(new NameData("","計算できません"));
}
private void Eval_dev()
{ NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack());
if(P1.Type=="Number" && P2.Type=="Number")
pushEvalStack(new NameData("",P1.Val / P2.Val));
else pushEvalStack(new NameData("","計算できません"));
}
実行用メソッド⑤
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()
{ NameData P2=Eval(popEvalStack()); NameData P1=Eval(popEvalStack());
if(P1.Type=="Number" && P2.Type=="Number")
pushEvalStack(new NameData("",(long)(P1.Val) % (long)(P2.Val)));
else pushEvalStack(new NameData("","計算できません"));
}
private void Eval_minus()
{ NameData P1=Eval(popEvalStack());
if(P1.Type=="Number") pushEvalStack(new NameData("",-P1.Val));
else pushEvalStack(new NameData("","計算できません"));
}
private void Eval_plus()
{ NameData P1=Eval(popEvalStack());
if(P1.Type=="Number") pushEvalStack(new NameData("",P1.Val));
else pushEvalStack(new NameData("","計算できません"));
}
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()
{ 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(true);
}
private void Eval_greater_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_greater_than_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 pushEvalStack(new NameData("","計算できません"));
}
実行用メソッド⑦
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()
{ 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_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_and()
{ 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_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));
else pushEvalStack(new NameData("","計算できません"));
}
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)
MessageBox.Show(NameTable[ID].Name +" Type=" +
NameTable[ID].Type +" Val=" +NameTable[ID].Val);
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));
int i=Eval_set_pointer(P1);
NameTable[i].Val++;
}
private void Eval_MMset() // 後置-{ NameData P1=popEvalStack(); pushEvalStack(Eval(P1));
int i=Eval_set_pointer(P1);
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].Type= "String";
NameTable[i].Text= NameTable[i].Text + P2.Val;
}
else
{ NameTable[i].Type= "String";
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() // *=
{ 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_AsignDivset() // /=
{ 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_BeforPPset() // 前置++
{ NameData P1=popEvalStack(); NameTable[ptrNameTable]=P1;
int i=Eval_set_pointer(P1); NameTable[i].Val++;
pushEvalStack(Eval(P1));
}
実行用メソッド⑪
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());
break;
}
}
}
実行用メソッド⑬
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(S);
}
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;
listBox3.Items.Add(S);
}