• 締切済み

コンパイラの作成

 皆さんのお力を貸してください.  現在, Java 言語を用いてコンパイラを作成しているのですが, 関数の引数として 1 次元配列を渡す方法 ( 配列の要素全体のコピーを渡すのではなく配列の先頭の番地を渡す方法 ) と参照渡しのプログラム記述方法が解らず悩んでおります.  何卒ご教授お願いいたします.

  • Java
  • 回答数5
  • ありがとう数5

みんなの回答

回答No.5

これは、情報学科で出された課題ですか? なかなか難しいですね。 簡単に説明しますと、以下の変更を加えます。 caller(関数が呼び出す)側:  配列変数の先頭アドレスをスタックに積む。 callee(関数が呼び出される)側:  引数の配列を使用する場合、callerがスタックに積んだ値を配列の先頭アドレスとして処理する。 targetのアーキテクチャ(CellV内のexecute()を読めば理解出来ます。本にも書いてあるかもしれません。)、CellK内の文法解析の順番を理解出来れば、比較的少ないコーディングですむと思います。 他に方法はあるかもしれませんが、 私の試した方法を書いておきます。 ただし、大雑把な説明なので、以下の変更だけではコンパイルしません。他にも修正、追加する必要があります。 大変でしょうが、頑張って下さい。 -------------------------------------------- caller(呼び出し)側の変更:  配列でない変数を引数にして関数を呼び出す場合は、その変数の値をスタックに積みます。  これは、CellK.javaの中では、  cellV.genCodeT(CellV.lod, tIndex);  という文で実行されています。    これを配列を引数に出来るように拡張するには、配列の先頭アドレスをスタックに積みます。  これは、  cellV.genCodeT(CellV.lda, tIndex);  という文で実行出来ます。 callee(呼び出される)側:  CellK.javaの中で、function()という関数がありますが、ここではfunctionのparseを行なっています。  この中で、while文の中に、if(token.kind == CellG.I)という文がありますが、これは引数が変数(配列でない)の場合の、変数のparameter登録等の処理を行なっています。  配列の引数に対応するには、else if文を追加し、その中で登録等の処理をします。  例:else if (token.kind == CellG.aI) { ... }  また、CellG.javaの中で、識別子の種類を列挙したfinal変数の一覧がありますが、これに配列パラメータの識別子を追加する必要があると思います。  例:static final int parAI = 45;  次に、statement()の中で、配列に代入する場合の処理を行なっている箇所があるのですが(case CellG.arrI)、配列が引数である場合の処理を追加する必要があります。配列が引数である場合は、callee側は配列のアドレスをスタックから読む必要があります(caller側で積んだアドレスがありますよね?)。 case CellG.parAI:   cellV.genCodeT(CellV.lod, tIndex); /* lod 先頭番地 */ case CellG.arrI の中の、  cellV.genCodeT(CellV.lda, tIndex); との違いを理解して下さい。  最後に、引数配列の値を読む場合も同様に、factor()内のcase文に処理を追加します。  case CellG.parAI:   cellV.genCodeT(CellV.lod, tIndex); /* lod 先頭番地 */

No-001
質問者

補足

 twoandhalf さん丁寧な解答ありがとうございます.twoandhalf さんは当参考書を 利用したことがあるのでしょうか?今新たに, "%"( 余りの計算 ) が出来るように拡 張しようと考えているのですが, こちらについてもアドバイスを頂けないでしょう か.よろしくお願いします.

回答No.4

配列の場合、コピーを渡す方が面倒くさかったりする。 こちらを読めばわかるかな。 http://www.atmarkit.co.jp/fjava/rensai3/eclipsejava06/eclipse06_1.html

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.3

>関数の引数として 1 次元配列を渡す方法 >参照渡しのプログラム記述方法 なんであれ、 (「自作インタプリタ」内部で確保した)「自作メモリ領域」のアドレス を使うだけ。 たとえばその「自作メモリ領域」というのが 「単純な配列」 ならば、 その配列のインデックスこそが「アドレス」。 つまりその内部自作メモリ全体が、int配列 int[] mem = new int[1000] というものであったら、 mem[11], mem[23], mem[45] この11、23、45などが「アドレス」に相当する…よね? --- ●Point 1 「参照渡し」というのは、 この「アドレスを利用する」ことにほかなりません。 例えば まず mem[11] に値 777 が入っていて、これをある関数foo()の引数として渡す際に、 foo(777) とやるのが値渡しで、 foo(11) とやるのが「参照渡し」。 とりあえずこれで「渡す」側の処理はOK。 --- ●Point 2 次にこれを「受け取る」側の処理も、協調して作る必要がある(よね?)。 つまり、つぎのような関数宣言部 foo(Int a, refInt b) を見て、 「ああ、第一引数は「値渡し」だな。 つまり渡ってきた引数には、「値」そのものが入っているのだから、 これを使いたい時は、引数の中味を直接見ればいいのだな。 第二引数は「参照渡し」だな。 ということは、渡ってきた引数には「アドレス」が入っているのだから、 コレを使いたい時は、引数の中味のアドレスを見て、 次にそのアドレスの参照先(ポイント先)を見ればいいのだな。 まあ1ステップ、処理が増えるだけだな」 と考えればよい。 このへんの話は、理屈的にはむずかしくない。 --- が、 http://book.gihyo.co.jp/s-com/ この「スモールコンパイラの制作で学ぶプログラムのしくみ 」という本の 話だよね? 難易度的には (1)Javaの基礎文法を知っている …1 (2)この本のソースコードを「完全に」理解する…10 (3)前述の「参照」の理屈を押さえる…1 (4)これらを踏まえたうえで、  この本のソースコードを正しく書き換える…3か4 とにもかくにも(2)がすべてで、 まずこれをクリアしないことには、どうしようもない。 --- 大半の学生には、自力で作るのキツイんじゃないかなーとは思うけどね。

No-001
質問者

補足

kacchann さんありがとうございます.使っている参考書は「スモールコンパイラの制作で…」です. kacchann さんはこの本を読んだことがあるのでしょうか?それに「大半の学生には、自力で作るのキツイんじゃないかなー」とまさに感じております.それでかなり切羽詰ってまして.  考えている問題としては, まず配列の方では ( 問 ) 関数の引数として 1 次元配列を渡せるように機能拡張する.  渡し方は配列の要素全体のコピーを渡すのではなく, 配列の先頭の番地を渡す.以下のプログラムで動作確認.  {  I sum(aI a[], I n){ vI s = 0, i; for(i = 0; i < n; i = i+1;){ s = s + a[i]; } return s; } aI a[16]; for(i = 0; i < 16; i = i+1;){ a[i] = i * i; } println sum(a, 16); }$  { I copy(aI a[], aI b[], I n){ vI i; for(i = 0; i < n; i = i+1;){ b[i] = a[i]; } return 0; } vI i; aI a[16], b[16]; for(i = 0; i < 16; i = i+1;){ a[i] = i; } dummy = copy(a, b, 16); for(i = 0; i < 16; i = i+1;){ println b[i]; } }$  なんとかコンパイラを拡張して上記のプログラムを動作させたいのですが, 記述方法が解らないのです.  kacchann さんは記述方法は解りますか?解りましたらアドバイスをお願いいたします.

  • edomin
  • ベストアンサー率32% (327/1003)
回答No.2

私もJavaは詳しくありませんが、 「 Java 言語にはポインタのようなものは存在しません.」 という仕様になっているのですから 「 Java 言語は, 配列及びオブジェクトは参照渡しではないでしょうか.」 という内部動作をプログラム上からアクセスすることは無理なんじゃありませんか?Java自体がどういう風に動いているかは関係なく、ユーザが何を使えるのかが問題なのだと思いますが。

No-001
質問者

補足

 ちょっと良く解らないのですが, 変数自体のアドレスを渡すことが出来るような設計にしたいと考えています.

回答No.1

Javaは詳しくないですが。 Javaでポインタ(番地)を扱うことなんてできましたか?

No-001
質問者

補足

 早速の返信ありがとうございます.確かにおっしゃる通りで Java 言語にはポインタのようなものは存在しません.そのかわり Java 言語は, 配列及びオブジェクトは参照渡しではないでしょうか.Java 自体がそのような仕様になっていると何かで読んだ気がするのですが?  それが本当なら, 配列やオブジェクトの場合は値ではなくメモリアドレスが値で渡されていることになり, それを実現したいと思っているのですが….

関連するQ&A

  • スモールコンパイラの制作という参考書について

     現在大学で, 「スモールコンパイラの制作で学ぶプログラムのしくみ」という参考書を勉強しているのですが, 出題された課題の中でどうしても解らない問題があるのです.上記の参考書を学習した方だけではなく, 幅広い方からご教授を頂きたいと思っておりますので何卒宜しくお願いいたします.  課題の内容は, (1) 関数の引数として 1 次元配列を渡せるように機能拡張せよ.   渡し方は C言語の方法に習え.すなわち, 配列の要素全体のコピーを渡すのではなく, 配列の先頭の番地を渡せ.以下のプログラム ( 配列の要素の和と配列のコピー ) で動作を確認せよ.    I sum(aI a[], I n){ vI s = 0, i; for(i = 0; i < n; i = i+1;){ s = s + a[i]; } return s; } aI a[16]; for(i = 0; i < 16; i = i+1;){ a[i] = i * i; } println sum(a, 16); }$  { I copy(aI a[], aI b[], I n){ vI i; for(i = 0; i < n; i = i+1;){ b[i] = a[i]; } return 0; } vI i; aI a[16], b[16]; for(i = 0; i < 16; i = i+1;){ a[i] = i; } dummy = copy(a, b, 16); for(i = 0; i < 16; i = i+1;){ println b[i]; } }$  用いるコンパイラは Java 言語で記述されており, ソースファイルは, http://book.gihyo.co.jp/s-com/ から取得できるようになっております.宜しくお願いいたします.

  • 関数のパラメータに配列を渡すときは、非参照型が普通なんですか?

     LippmanのC++プライマー(第4版)を勉強中です。 p.274以降に、配列に作用する関数の定義法と使用法に関する解説があり、p.275に以下の記述があります。 ■配列アーギュメント  配列パラメータも参照型と非参照型がある。  普通、配列は非参照型にする  非参照型パラメータは対応するアーギュメントのコピーで初期化される。配列アーギュメントはその配列の先頭要素へのポインタであり、そのポインタがパラメータにコピーされる。関数はアーギュメントのポインタを変更することはないが、パラメータのポインタを使って配列要素を変更することはできる。 ■配列を参照で渡すこと  配列パラメータを配列への参照にすることもできる。パラメータが配列への参照である場合、コンパイラは配列アーギュメントをポインタに変換しない。配列への参照そのものを渡す。この場合、配列の大きさはパラメータの型の一部である。コンパイラは配列アーギュメントの大きさがパラメータの大きさに一致するかどうかチェックする。 しかしp.268の「ヒント」には以下のように記されています。 ヒント:  Cの素養があるC++プログラマはアーギュメントにアクセスするためにポインタを渡すことに慣れている。 C++では、参照パラメータを使うのが安全かつ自然である。  配列パラメータも参照で渡したほうが、ポインタをコピーしないですむし、配列の大きさを越えてアクセスすることによる実行時エラーも抑止できるので、いいように思いますが、なんで「普通、配列は非参照型にする」んでしょうか?

  • 行列の列の絶対値の総和の最大値を得る関数を教えてください

    4*4行列の列ごとの各要素の絶対値の総和の最大値 課題の途中で上記の関数が作れないので止まりました・・・ 行列は2次元の配列で定義しているので 配列を引数にできるような関数を教えてくださいお願いします。

  • android-JNIでクラス配列参照方法について

    androidのJNIで関数引数をクラス配列にした場合、C側ではこのポインタをどのようにすれば取得出来るのでしょうか? 一応GetByteArrayElements()を使用してクラス配列の要素数までは取得できましたが、このクラスのポインタの取得方法が出来ません。 ※クラス配列にある変数をC言語側で参照したいと考えております。 (このクラスはC言語の構造体として扱うようにしています)

  • ポインタの勉強中なのですが

    C言語の勉強中なのですが、ポインタのところで苦労しています。 次のような関数を作成し、main関数で実行したところ、sizeof(array)は4になりました。 main関数内で同じようにsizeof(array)を表させると配列全体のサイズが表示されますよね。 関数の仮引数として配列を書いても、実際には配列の先頭要素を指すポインタとして扱われるので 関数には&array[0]が渡され、関数は配列ひとつあたりのサイズを基に他の配列の要素のアドレスを 受け取るで合ってますよね? でもmain関数内ではsizeof(array)は配列全体のサイズを返すのに、関数内では配列ひとつあたりのサイズしか返さないのはどうしてなのでしょうか? int sum_array( int array[], int num ){ int i; int sum = 0; for( i = 0; i < num; i++ ){ sum += *(array+i); } printf("sum = %d\nsizeof(array)=%d\n",sum,sizeof(array)); return sum; }

  • 多次元配列のポインタ渡し

    C++を使用しています。 多次元配列を関数の引数として渡したいとき、関数側では void A::Func(int a[10][20][30])~ 呼びだし側では Finc(a); とやればいいのはわかります。 お聞きしたいのは、仮引数として呼び出された配列(上でいうa)をクラスのメンバ変数として保持したい場合の方法です。 aは先頭アドレスなのでそこを差すポインタを受ければいい、っていうことはわかりますが、 この方法ですと、受けたメンバ変数が配列みたいに[]を使ってアクセスできません。 (メンバ変数のポインタは配列じゃないから当然ですよね) これを通常の配列みたいに扱えるようにするにはどうしたらいいでしょうか。

  • GCCで関数の引数が渡らない

    gcc Ver2.9 でSH-2の開発をしています。 通常に関数を作成し、引数を渡しているのですが、引数が渡らないという現象が起きています。 現象は、 1.引数はポインタではなく値渡しである 2.引数の値が0の時だけ正しく渡らない。値が0以外の時は正常にわたる 3.引数の型は一致している 4.引数は複数あるが、後半のいくつかがだめ(何個とまでは詳しく調べていません) 5.ある特定の関数の特定の呼び出しのみがだめで全てだめというわけではない 6.コンパイルオプションに -m2 をつけるとだめだが、-m1 オプションだと問題ない 7.最適化オプションをなくしても同じだった といった状況です。 上記5からある特定の記述方法とか順序になるとだめになるのではないかといろいろ試してみたのですが見つけられません。6から記述方法に誤りがあるとも考えにくい状況です。コンパイラのバグといって片付けていいものなのかどうかです。どなたか同じような経験をされた方はいらっしゃいませんか。また関数呼び出しの場合、コンパイラがどうやって引数を渡すかご教授願えませんか。

  • 関数へのポインタ渡しでの配列の初期化について

    はじめまして、C言語の基本的な質問をさせてください。 C言語で、外部関数へポインタで引数を渡す場合に、 関数に渡されるのはアドレスですよね? で、渡された関数側でそのポインタの配列の初期化を するときにはアドレスだけの情報だと、要素数がいくつ あるか分からず、領域の破壊をしてしまいそうな気が するのですが?いかがでしょうか? また、関数かなんかで、配列の要素数が分かる関数が あったような気がするのですが、それもアドレスだけ でわかるのでしょうか?

  • PHP 多次元配列の次要素を返す便利関数

    PHP5を独学中の者です。 1次元や多次元配列を扱ってきて、次元数が決定されていない配列を自作関数に渡す事で、 現在のポイントの次要素を返す便利関数を考案中です。 【関数に求める利点】  ・引き渡した配列の次元数(1~n)に関わりなく、現在のポイントの次要素を返す。 【関数を使用した想定コード】   $e[0][0] = "a1";   $e[0][1] = "a2";   $e[0][2] = "a3"; // $e配列の次要素を取得 $r = 自作関数($e);  ※ 上記コードでは、現在のポイント($e[0][1])の次要素($e[0][2])を、$rに "a3" を返す   $e[0][0][0] = "a1";   $e[0][0][1] = "a2";   $e[0][0][2] = "a3"; // $e配列の次要素を取得 $r = 自作関数($e);  ※ 上記コードでは、現在のポイント($e[0][0][0])の次要素($e[0][0][1])を、$rに "a2" を返す 関数に対して引数を与えたり、色々と試行錯誤中ですが、アドバイス頂ければ嬉しいです。

    • 締切済み
    • PHP
  • 二次元配列の初期化の方法。

    java初心者です。 二次元配列(9×9)の要素すべてに同じ値で初期化したいのですが、どういった方法があるのでしょう? {{0,0,0,0,0,0,0,0,0,},{0,0,・・・ という方法しか分からないのですが、やたらと大変だなぁと思ったのですが・・・ よろしくお願いします。

    • ベストアンサー
    • Java

専門家に質問してみよう