コンパイラ 2012年10月25日 酒居敬一@A468(sakai.keiichi@kochi-tech.ac.jp) http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/COMP/2012/index.html.

Slides:



Advertisements
Similar presentations
2.5 プログラムの構成要素 (1)文字セット ① ASCII ( American Standard Code for Interchange ) JIS コードと同じ ② EBCDIC ( Extended Binary Coded Decimal for Information Code ) 1.
Advertisements

情報処理基礎 A ・ B 第 5 回 プログラミング入門 操作の自動化を実現する仕組み. 2004/11/16 ・ 17 情報処理基礎 A ・ B 2 本日の内容 処理の自動化~プログラムの概念 ハードウェアとソフトウェア プログラミング言語 Excel における処理の自動化 入力支援の機能 分析ツール.
アルゴリズムとデータ構造 第2回 線形リスト(復習).
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第3回 配列(1) 情報・知能工学系 山本一公
基本情報技術概論 I 演習(第5回) 埼玉大学 理工学研究科 堀山 貴史
プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
コンパイラ 2011年10月17日
プログラミング言語としてのR 情報知能学科 白井 英俊.
プログラミング言語論 第6回 型 情報工学科 篠埜 功.
プログラミング言語論 第4回 式の構文、式の評価
アルゴリズムとデータ構造 2011年6月13日
条件式 (Conditional Expressions)
言語処理系(5) 金子敬一.
言語処理系(8) 金子敬一.
アルゴリズムとデータ構造1 2009年6月25日
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
コンパイラ 2012年10月15日
コンパイラ 2012年10月22日
2016年度 プログラミングⅠ ~ 内部構造と動作の仕組み(1) ~.
ML 演習 第 7 回 新井淳也、中村宇佑、前田俊行 2011/05/31.
コンパイラ 2011年10月24日
コンパイラ 2011年10月27日
プログラムの制御構造 選択・繰り返し.
勉強会その3    2016/5/1 10 8分35秒 データの表現 演算.
アルゴリズムとデータ構造1 2006年6月16日
コンピュータ系実験Ⅲ 「ワンチップマイコンの応用」 第1週目 アセンブリ言語講座
プログラミング演習I 2003年5月7日(第4回) 木村巌.
アルゴリズムとデータ構造 2010年6月28日
アルゴリズムとデータ構造1 2005年6月28日
言語プロセッサ 第8回目 平成22年11月22日.
第5章 計算とプログラム 本章で説明すること ・計算の概観と記述法 ・代表的な計算モデル ・プログラムとプログラム言語.
先週の復習: CPU が働く仕組み コンピュータの構造 pp 制御装置+演算装置+レジスタ 制御装置がなければ電卓と同様
コンパイラ 2011年10月20日
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
構造体と共用体.
15.cons と種々のデータ構造.
プログラミング 3 2 次元配列.
地域情報学 C言語プログラミング 第2回 変数・配列、型変換、入力 2017年10月20日
コンピュータアーキテクチャ 第 2 回.
オブジェクト指向言語論 第三回 知能情報学部 新田直也.
2013年度 プログラミングⅠ ~ 内部構造と動作の仕組み(2) ~.
2017年度 プログラミングⅠ ~ 内部構造と動作の仕組み(1) ~.
コンパイラ 2012年11月5日
計算機プログラミングI 木曜日 1時限・5時限 担当: 増原英彦 第1回 2002年10月10日(木)
コンパイラ 2012年10月29日
コンパイラ 2011年11月10日
アルゴリズムとデータ構造 2012年6月11日
コンピュータアーキテクチャ 第 2 回.
コンパイラ 2012年11月1日
アルゴリズムとデータ構造1 2009年6月15日
情報処理Ⅱ 第7回 2004年11月16日(火).
情報処理Ⅱ 2005年10月28日(金).
言語プロセッサ 第12日目 平成20年1月9日.
プログラミング基礎a 第3回 C言語によるプログラミング入門 データ入力
オブジェクト指向言語論 第二回 知能情報学部 新田直也.
コンパイラ 2012年10月11日
プログラミング 4 文字列.
アルゴリズムとデータ構造 2010年6月17日
2014年度 プログラミングⅠ ~ 内部構造と動作の仕組み(1) ~.
PROGRAMMING IN HASKELL
2005年度 データ構造とアルゴリズム 第2回 「C言語の復習:配列」
情報処理Ⅱ 第2回 2004年10月12日(火).
情報処理Ⅱ 2005年11月25日(金).
プログラミング基礎a 第5回 C言語によるプログラミング入門 配列と文字列
情報処理Ⅱ 小テスト 2005年2月1日(火).
プログラミング基礎a 第3回 C言語によるプログラミング入門 データ入力
情報処理Ⅱ 第8回:2003年12月9日(火).
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
6.5 最終コード生成 (1)コードの形式 ①絶対2進コード(AB : absolute binary) 命令後のオペランドが絶対番地指定。
Presentation transcript:

コンパイラ 2012年10月25日 酒居敬一@A468(sakai.keiichi@kochi-tech.ac.jp) http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/COMP/2012/index.html

中間表現 前回までの内容 今回の内容 次回の内容 字句解析 構文解析 構文木や4つ組みとして表されるものをきちんと説明。 意味解析 ソースプログラムという文字の並びから、字句の並びへ変換。 ただし、字句は構造を持ったデータ。つまり少し抽象化したデータの並び。 構文解析 字句の並びから、構造を持ったデータの集まりへ変換。 名前やデータ構造は名前表に出力する。 では、制御構造(文の構造)はどうする??? とりあえずは、構文木や4つ組として出力する、と説明した。とりあえず... 今回の内容 構文木や4つ組みとして表されるものをきちんと説明。 次回の内容 意味解析

二分木 二項演算や代入は二分木で表現可能。 関数呼び出しは特殊ノードとして表現する。 後順走査することで、後置記法のオブジェクトコードを生成可能。 演算・代入は子を2つもつノード。 ノードは、その結果を親ノードへ返す。 変数や定数はリーフ。 参照した値を親ノードへ返す。右辺値を返す? 代入ノードの左の子 親ノードが代入ノードである場合を判断し、左辺値を返す。 右辺値を返し、代入ノードでその右辺値の指す先に値を置く。 関数呼び出しは特殊ノードとして表現する。 引数の数だけ子を持つノード。 戻り値を親ノードへ返す。

式y+find_max(a+b, c, 0)/(x-1)の構文木 〈式〉ノードの種類 (call,+,-,*,/,>,>=,<,<=,<>,=) 子ノードへのポインタ1 子ノードへのポインタ2 型 語長 call find_max arg_vector + y / - x 1 a b c 〈リーフ〉ノードの種類 (名前(変数, 関数), 定数) 名前表へのインデックス 定数値 ※ この例では代入や左辺値を必要とする演算は表されていない。

左辺値と右辺値 左辺値(l-value) 右辺値(r-value) 代入の左辺に置けるもの。代入先に指定できるもの。 言語によるが、たいていは変数。 実行環境が許せば、*((int *)0x1000) でも左辺値になる。 右辺値(r-value) 代入の右辺に置けるもの。 左辺値になれなくても、右辺値になるものはある。 C言語における、関数名・配列名は左辺値にはなれない。 式の返す値。 x++は、右辺値にしかなれない。++(x++)はエラー。 *p = 10; と書けるとき、*p が代入の左辺値である。 pが左辺値かどうかは、pの定義しだい。 pが*演算子で参照された結果が左辺値だ、というだけ。

四つ組 木として保持するより小さく、外部ファイルに出しやすい。 つぎの情報をひとつの四つ組として持つ 保持する情報は木と変わらない。 つぎの情報をひとつの四つ組として持つ 演算子の情報 第一オペランドの情報 第二オペランドの情報 演算結果の保存先 保存先にコンパイラが生成した一時的な変数も存在する。 木の場合には、演算ノードが保持している、ということに対応。

四つ組と木構造 + = * a b c d 四つ組 (①*,②c,③d,④tmp#1) (①+,②b,③tmp#1,④tmp#2) 四つ組の代入形式表現 tmp#1 := c*d tmp#2 := b+tmp#1 a := tmp#2 代入のときの保存先は左辺値である。 四つ組で@をつけているところで、アドレスで参照している。 一方の木構造の例では、名前で参照している。

四つ組と木構造の関係 木を後順走査した結果と四つ組表現がよく合う。 変数や定数 木は必ずしも2分木である必要はない。 子を先に走査することがオペランドを用意することに対応し、 演算子はそれらオペランドに作用することから後で出力する。 演算途中の値は、一時変数に置く。 変数や定数 木でも四つ組でも名前表に置き、インデックスなどで参照する。 木は必ずしも2分木である必要はない。 三項演算子・引数が2個より多い関数は多分木のほうがよい。 if-then-elseやforのような制御構造を表す場合も多分木 のほうがよく合う。 四つ組は書き方が機械命令に近い。 除算のように、戻り値が2つ以上ある演算も書けたりする。

z=y+1/(x-1)の木構造と四つ組 対応する四つ組 ①(-,x,1,tmp#1) ②(/,1,tmp#1,tmp#2) ③(+,y,tmp#2,tmp#3) ④(=,tmp#3,,@z) 対応する三つ組 ①(-,x,1) ②(/,1,①) ③(+,y,②) ④(=,③,@z) 代入形式 ①tmp#1 := x-1 ②tmp#2 := 1/tmp#1 ③tmp#3 := y+tmp#2 ④z := tmp#3 = z + y / 1 - x 1

中間言語の必要性 四つ組は3オペランド形式の機械語に近いとはいうものの… 命令セットアーキテクチャは、マイクロアーキテクチャの影響 を受けて設計されるため、そのままでは使いにくい。 オペランドの組み合わせに関する直交性が限定的。 メモリ対メモリの演算ができない命令セットアーキテクチャが多い。 一時変数としてのレジスタ数に限りがある。 SPARC v9で32個、IA-32で8個、だけど使途に制約あり。 即値・絶対アドレスといった値の大きさに制約がある。 たいていは倍精度浮動小数点数を即値で表せない。 レジスタの使途に制約がある場合がある。 整数演算用・浮動小数点演算用・アドレス保持用・暗黙的使用など。

例: IA-32とH8(単純なもの) IA-32(Intel表記) H8(gas表記) add eax,ebx add r0,r1 add [eax],ecx lea eax,[ebx+edx] lea eax,[esi+edi*4+8] mul eax,edx mov ecx,eax mov eax,[ebx+16] mov eax,[ebx+ecx*4] mov [edx],ecx H8(gas表記) add r0,r1 mulxu r0l,r1 mov r2,r5 mov @(12,r2),r0 mov r0,@r1 DSPの場合は3より多いオペランドを取る場合がある。古のSoundBlaster搭載のe-mu 8000や10k、組み込み用DSC dsPIC33Fなどを参照。

例:dsPIC33Fのmac命令(複雑なもの) Multiply and Accumulate命令 mac W4*W5,A, [W8],W6, [W10],W7, [W13] W4とW5の乗算結果をAアキュムレータへ加算(積和) W8で指し示されるXメモリからW6へロード(次命令のためのプリロード) W10で指し示されるYメモリからW7へロード(次命令のためのプリロード) W13で指し示すメモリへBアキュムレータの値を飽和・丸めの後でストア 先行命令の結果のストア、現在命令の演算、後続命令の オペランドのロード、を同時に1クロック時間で片付ける。 構文解析後に、いきなり生成することはできません!

ポインタや参照といったもの C言語は、高級アセンブリ言語Cと言い換えても 構わないくらい、機械語とつながりが深い。 C言語は、高級アセンブリ言語Cと言い換えても 構わないくらい、機械語とつながりが深い。 int *f(); /* fはintへのポインタを返す関数 */ int (*f)(); /* fはintを返す関数へのポインタ */ char **argv; /* charへのポインタのポインタ */ int (*daytab)[13]; /* daytabはintを要素とする要素数13の配列へのポインタ */ int *daytab[13]; /* daytabはintへのポインタを要素とする要素数13の配列 */ char (*(*x())[])(); /* xはcharを返す関数へのポインタの配列へのポインタを返す関数 */ char (*(*x[3])())[5];/* xはcharを要素とする要素数5の配列へのポインタを返す関数 へのポインタを要素とする要素数3の配列 */ 出典: "プログラミング言語C 第2版", 共立出版, 149ページ, 2001年. もちろん、typedefを使って複雑な記述を避けることが鉄則です。勉強のために極端な例を使ってます。 別のキーワードとしては、名前による参照、アドレスによる参照、からも勉強するといいでしょう。

例:char (*(*x[3])())[5];という定義 例の定義ではポインタ3個分の大きさのメモリがxとして定義されます(xは名前による参照)。 ポインタの大きさは処理系依存ですが、大きさはintと同じことが多い。 xの要素を参照する、つまりプログラムの中で y = x[0](); としたときのyは? x: .word a, b, c ! a, b, cは関数のエントリーポイントであるとする。 y: .word 0 ! 戻り値を入れる場所とする。yの型はchar (*)[5] mov @x,r0 jsr @r0 ! x[0]()に対応し、呼ばれた関数がr0に値を返す。 yには関数から戻ったときのr0の値が入る。その変数の指す先に要素数5のcharの配列がある。 y

関数呼び出しの()と、キャストの() 下線をつけたところが関数呼び出しの()。 関数呼び出しのときの()の左側のオブジェクトは何? 文脈で区別され、内側から読むと、「xは大きさ3の配列で、 その要素を参照することで関数が呼び出され、呼び出された 関数の返す値を参照すると大きさ5のchar配列にたどり着く。」 関数呼び出しのときの()の左側のオブジェクトは何? エントリーポイントを保持する変数。関数へのポインタ。 ポインタを参照して得た値が関数へのエントリーポイント ポインタ変数は関数ではないが、感覚的に同じように使える。 アセンブリ言語レベルでは、ラベルでしかないもの。 ラベルは最終的にはldによりアドレスに変換されます。 感覚的には名前=関数。 左辺値 char (*(*x[3])())[5]; 原理から考える習慣を身に着けてほしい。