一時的な型 長谷川啓 2018.11.01.

Slides:



Advertisements
Similar presentations
独習JAVA Chapter 6 6.6 クラスの修飾子 6.7 変数の修飾子 結城 隆. 6.6 クラスの修飾 abstract インスタンス化できないクラス。1つまたは複数のサブクラスで 実装してはじめてインスタンス化できる。 final 継承されたくないことを明示する。これ以上機能拡張 / 変更でき.
Advertisements

2.5 プログラムの構成要素 (1)文字セット ① ASCII ( American Standard Code for Interchange ) JIS コードと同じ ② EBCDIC ( Extended Binary Coded Decimal for Information Code ) 1.
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
データ構造とアルゴリズム 第10回 mallocとfree
アルゴリズムとプログラミング (Algorithms and Programming)
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
アルゴリズムとデータ構造 2011年6月13日
構造体.
プログラミング言語論 第10回 オブジェクト指向 情報工学科 篠埜 功.
プログラミング演習II 2004年12月 21日(第8回) 理学部数学科・木村巌.
プログラミングII 第 7 回 オブジェクトの配列 New, delete 参照 田向.
補足説明.
プログラミング論 関数ポインタ と 応用(qsort)
情報工学演習I 第12回 C++の演習4(インライン展開).
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
独習JAVA 6.8 コンストラクタの修飾子 6.9 メソッドの修飾子 6.10 ObjectクラスとClassクラス 11月28日(金)
ローカル変数とグローバル変数 ローカル変数  定義された関数内だけで使用できる変数 グローバル変数 プログラム全体で使用できる変数.
アルゴリズムとデータ構造 補足資料5-2 「サンプルプログラムsetop.c」
プログラミング 3 構造体(2).
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
プログラミング言語論 第12回 オブジェクト指向 情報工学科 篠埜 功.
プログラミング言語論 第13回 オブジェクト指向 情報工学科 篠埜 功.
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
アルゴリズムとデータ構造 2010年6月21日
フロントエンドとバックエンドのインターフェース
型の compatibility とポインタ演算
オブジェクト指向プログラミングと開発環境
記号表の検索と登録 長谷川啓
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
データ構造とアルゴリズム 第11回 リスト構造(1)
アルゴリズムとプログラミング (Algorithms and Programming)
C++ 構文解析 構文解析器の状態保存と復元
参照されないリテラル 長谷川啓
プログラミング 3 2 次元配列.
プログラミング言語論 第十一回 理工学部 情報システム工学科 新田直也.
C#プログラミング実習 第3回.
ポインタとポインタを用いた関数定義.
情報基礎演習B 後半第2回 担当 岩村 TA 谷本君.
第13回 ポインタ 1 1.
アルゴリズムとデータ構造 2012年6月11日
アルゴリズムとプログラミング (Algorithms and Programming)
情報処理Ⅱ 第2回 2005年10月14日(金).
情報処理Ⅱ 第2回 2006年10月13日(金).
Chapter 5 5.5 thisキーワード 5.6 インスタンス変数とインスタンスメソッド 結城 隆
アルゴリズムとデータ構造1 2009年6月15日
ネットワーク・プログラミング Cプログラミングの基礎.
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
JAVA入門⑥ クラスとインスタンス.
オブジェクト指向言語論 第十一回 知能情報学部 新田直也.
ドキュメントジェネレータ 詳細仕様 長谷川啓
オブジェクト指向言語論 第九回 知能情報学部 新田直也.
cp-2. 属性,アクセサ (C++ オブジェクト指向プログラミング入門)
X64 函数呼び出し規約 長谷川啓
Inline 展開のアルゴリズム 長谷川啓
アルゴリズムとデータ構造 2010年6月17日
フレンド関数とフレンド演算子.
演算子のオーバーロード.
Tacsim の実装 - 実行部分 長谷川啓
:: の扱い 長谷川啓.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
データ構造と アルゴリズム 第四回 知能情報学部 新田直也.
プログラミング演習II 2003年11月19日(第6回) 木村巌.
プログラミング演習II 2003年12月10日(第7回) 木村巌.
オブジェクト指向言語論 第九回 知能情報学部 新田直也.
C言語講座第5回 2017 構造体.
プログラミング演習II 2003年10月29日(第2,3回) 木村巌.
デフォルト引数 長谷川啓.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
Presentation transcript:

一時的な型 長谷川啓 2018.11.01

一時的なタグ型 void f(struct S { int a; } s) { } ※ struct T { double d; }; struct S* ps; struct T* pt; ... } ※ void g(struct S { int a; } s) struct S s2 = { 1 }; f(s2); /* エラー。f::パラメータスコープ::struct S と g::パラメータスコープ::struct S は compatible ではないから。*/ void f(); // グローバルな f の宣言を隠す f(s2); // ok

一時的なタグ型(続き) 前ページの※のポイントで f::ボディ f::パラメータスコープ は破棄されるが、 型 f::パラメータスコープ::struct S 型 f::ボディ::struct T はどうするべき? ⇒ 型 f::パラメータスコープ::struct S は破棄されてはならない。 f がグローバルスコープにあるから。 前ページのような函数 g における f の呼び出しで型 f::パラメータスコープ::struct S が参照されうるから。 型 f::ボディ::struct T は※以降参照されることがないから、メモリの使用の観点から、破棄されるべき。 但し、必ずしも破棄しなくてもよい。 破棄するのならば、f のボディで作成された struct T* も破棄される必要がある。

scope, tag, record_type, incomplete_tagged_type tagn incomplete_tagged_typen record_typen

~scope() でタグを破棄しないようにすると・・・ struct scope { map<string, vector<usr*> > m_usrs; // 変数、函数等 map<string, tag*> m_tags; // タグ ... ~scope() { for (auto u : m_usrs) for (auto p : u.second) delete p; /* 分かりにくいが、 for (auto p : m_tags) delete p.second; のようにしない。 */ } }; struct tag { enum kind_t { STRUCT, UNION, ENUM } m_kind; scope* m_scope; /* タグが所属する scope を保持しておく。しかし、scope が破棄されても tag が破棄されないとすると、破棄されない tag は破棄された scope を参照しうることになる。これは、分かりにくいし、マズい。 */ class record_type : public type { tag* m_tag; ... }; class incomplete_tagged_type : public type { tag* m_tag; ...; ~incomplete_tagged_type(){ delete m_tag; }; // ここでタグを破棄する

~scope() でタグを破棄しないようにする改訂版 struct scope { map<string, vector<usr*> > m_usrs; // 変数、函数等 map<string, tag*> m_tags; // タグ ... ~scope() { for (auto u : m_usrs) for (auto p : u.second) delete p; for (auto p : m_tags) p.second->m_scope = 0; // こうする } };

variable length array (VLA) void f(int n, int (*p)[n-3]) { int a[n+5], b[n*2]; int (*pa)[] = &a, (*pb)[n+10] = &b; ... } ※ ※のポイントで p の指す VLA の次元 n-3 a の次元 n+5 b の次元 n*2 pb の指す VLA の次元 n+10 の演算結果は破棄される。 class varray_type : public type { const type* m_T; var* m_dim; varray_type(const type* T, var* dim) : m_T(T), m_dim(dim) {} }; のような実装だとすると、varray_type はいつ破棄されるべきか? varray_type::m_dim は型式の dag の設計からすると必要なメンバなのだが・・・

VLA(続き) ブロックスコープの VLA パラメータスコープの VLA varray_type::dim はそのスコープが破棄されるときに同時に破棄されるので、同時に varray_type オブジェクトも破棄する。 パラメータスコープの VLA ブロックスコープの varray_type::dim と同じ扱いだが、パラメータスコープの破棄のタイミングで不完全型配列に変更する。 例えば、前ページの f の第2引数の型は pointer(array(int, 0)) に変更する。

dag による型式の例 function pointer function int void void (*signal(int, void (*)(int)))(int) の型式 function 等価な型には同じ型オブジェクト を割り当てる ⇒ 型の等価性は型オブジェクトの アドレス比較で判定できる pointer function int void

dag による型式の実装 例 class pointer_type : public type { public: }; const type* m_T; pointer_type(const type* T) : m_T(T) {} // private コンストラクタ ... public: static const pointer_type* create(const type* T) { table_t& table = T->tmp() ? tmp_table : pmt_table; table_t::const_iterator p = table.find(T); if (p != table.end()) return p->second; return table[T] = new pointer_type(T); } }; tmp_table は函数のコンパイルが終わったら、一旦クリアする。

inline 函数内の一時的な型 inline 函数の情報 3番地コード パラメータスコープ およびその子供のブロックスコープ inline 函数内で生成された一時的な型 ★これ! inline 展開する前に一時的な型を破棄すると当然だがまずい。

ブロックスコープ内の函数宣言が例えば, VLA へのポインタを引数にとる void f() { ...; int g(int n, float (*p)[n * (n + 1)]); ...; } g の宣言に対する 3 番地コードは生成されてはならない g の第 2 引数の型は float の不完全型配列へのポインタにする g の引数の型の一部に VLA を入れてはならない 備考 函数の外側の函数宣言が VLA へのポインタを引数にとる場合 VLA へのポインタは不完全型配列へのポインタに変更する 生成された 3 番地コードは破棄する 函数定義が VLA へのポインタを引数にとる場合 VLA へのポインタはコード生成が終わった後、不完全型配列へのポインタに変更される 生成された 3 番地コードのオペランド ( x := y op z の x, y, z) は函数のブロックスコープに引っ越しされて、函数の最初のコードで通常通り評価される

もう少し複雑な例 void f(int n) { void (*array[n*3])(int m, int (*pa)[m+2]); ... } array の型は函数ポインタの VLA. この函数の第2引数は VLA へのポインタ array のバイト数を計算する3番地コードは生成されなくてはならない pa の指す VLA のバイト数を計算する3番地コードは削除されなくてはならない

ブロックスコープ内の函数宣言が例えば, VLA へのポインタを引数にとる(2) 函数定義の場合と同様に、3番地コードを出してオペランドを移動するのはだめ 例 void f(int n){ ...; void g(int n, int (*)[n+2]); ...; } t0 := n + 2 t1 := t0 << 2 が生成される. t0 や t1 を移動することはできるが, n は移動できない。 n は g のパラメータスコープが破棄されるときに、同時に破棄される.

ブロックスコープ内の函数宣言が例えば, VLA へのポインタを引数にとる(3) 実装の例 ブロックスコープ内のパラメータスコープで VLA が宣言されたら不完全型配列にすぐに変更する ブロックスコープ以外のパラメータスコープで VLA が宣言されたら通常通り