summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/chapter12/12-grammar.ja.md136
-rw-r--r--docs/chapter12/12-grammar.md132
-rw-r--r--docs/chapter12/Makefile12
-rw-r--r--docs/chapter12/README.ja.md101
-rw-r--r--docs/chapter12/README.md150
5 files changed, 531 insertions, 0 deletions
diff --git a/docs/chapter12/12-grammar.ja.md b/docs/chapter12/12-grammar.ja.md
new file mode 100644
index 00000000..827e7478
--- /dev/null
+++ b/docs/chapter12/12-grammar.ja.md
@@ -0,0 +1,136 @@
+# 第12章の文法
+
+[English](12-grammar.md) | 日本語
+
+この文書は [原文](12-grammar.md) の日本語訳です。
+
+[第12章に戻る](README.ja.md)
+
+```antlrv4
+grammar SimpleLanguage;
+
+program
+ : statement+ EOF
+ ;
+
+statement
+ : returnStatement
+ | structDeclaration
+ | declStatement
+ | blockStatement
+ | expressionStatement
+ | ifStatement
+ | whileStatement
+ | breakStatement
+ | continueStatement
+ ;
+
+PRIMTYPE
+ : 'int'
+ ;
+
+field
+ : PRIMTYPE IDENTIFIER ';'
+ | structName ('?')? IDENTIFIER ';'
+ ;
+
+fields
+ : field+
+ ;
+
+structDeclaration
+ : 'struct' IDENTIFIER '{' fields '}'
+ ;
+
+whileStatement
+ : 'while' '(' expression ')' statement
+ ;
+
+breakStatement
+ : 'break' ';'
+ ;
+
+continueStatement
+ : 'continue' ';'
+ ;
+
+ifStatement
+ : 'if' '(' expression ')' statement ('else' statement)?
+ ;
+
+
+expressionStatement
+ : IDENTIFIER '=' expression ';'
+ | fieldExpression '=' expression ';'
+ ;
+
+blockStatement
+ : '{' statement+ '}'
+ ;
+
+structName
+ : IDENTIFIER
+ ;
+
+declStatement
+ : PRIMTYPE IDENTIFIER '=' expression ';'
+ | structName ('?')? IDENTIFIER '=' expression ';'
+ ;
+
+returnStatement
+ : 'return' expression ';'
+ ;
+
+expression
+ : comparisonExpression
+ ;
+
+comparisonExpression
+ : additiveExpression (('==' | '!='| '>'| '<'| '>='| '<=') additiveExpression)*
+ ;
+
+additiveExpression
+ : multiplicativeExpression (('+' | '-') multiplicativeExpression)*
+ ;
+
+multiplicativeExpression
+ : unaryExpression (('*' | '/') unaryExpression)*
+ ;
+
+unaryExpression
+ : ('-') unaryExpression
+ | '!' unaryExpression
+ | primaryExpression
+ ;
+
+newExpression
+ : 'new' IDENTIFIER
+ ;
+
+fieldExpression
+ : primaryExpression '.' IDENTIFIER
+ ;
+
+primaryExpression
+ : IDENTIFIER
+ | INTEGER_LITERAL
+ | 'true'
+ | 'false'
+ | 'null'
+ | newExpression
+ | '(' expression ')'
+ | fieldExpression
+ ;
+
+INTEGER_LITERAL
+ : [1-9][0-9]*
+ | [0]
+ ;
+
+IDENTIFIER
+ : NON_DIGIT (NON_DIGIT | DEC_DIGIT)*
+ ;
+
+NON_DIGIT: [a-zA-Z_];
+DEC_DIGIT: [0-9];
+```
diff --git a/docs/chapter12/12-grammar.md b/docs/chapter12/12-grammar.md
new file mode 100644
index 00000000..41a7e24e
--- /dev/null
+++ b/docs/chapter12/12-grammar.md
@@ -0,0 +1,132 @@
+# Grammar for Chapter 12
+
+English | [日本語](12-grammar.ja.md)
+
+```antlrv4
+grammar SimpleLanguage;
+
+program
+ : statement+ EOF
+ ;
+
+statement
+ : returnStatement
+ | structDeclaration
+ | declStatement
+ | blockStatement
+ | expressionStatement
+ | ifStatement
+ | whileStatement
+ | breakStatement
+ | continueStatement
+ ;
+
+PRIMTYPE
+ : 'int'
+ ;
+
+field
+ : PRIMTYPE IDENTIFIER ';'
+ | structName ('?')? IDENTIFIER ';'
+ ;
+
+fields
+ : field+
+ ;
+
+structDeclaration
+ : 'struct' IDENTIFIER '{' fields '}'
+ ;
+
+whileStatement
+ : 'while' '(' expression ')' statement
+ ;
+
+breakStatement
+ : 'break' ';'
+ ;
+
+continueStatement
+ : 'continue' ';'
+ ;
+
+ifStatement
+ : 'if' '(' expression ')' statement ('else' statement)?
+ ;
+
+
+expressionStatement
+ : IDENTIFIER '=' expression ';'
+ | fieldExpression '=' expression ';'
+ ;
+
+blockStatement
+ : '{' statement+ '}'
+ ;
+
+structName
+ : IDENTIFIER
+ ;
+
+declStatement
+ : PRIMTYPE IDENTIFIER '=' expression ';'
+ | structName ('?')? IDENTIFIER '=' expression ';'
+ ;
+
+returnStatement
+ : 'return' expression ';'
+ ;
+
+expression
+ : comparisonExpression
+ ;
+
+comparisonExpression
+ : additiveExpression (('==' | '!='| '>'| '<'| '>='| '<=') additiveExpression)*
+ ;
+
+additiveExpression
+ : multiplicativeExpression (('+' | '-') multiplicativeExpression)*
+ ;
+
+multiplicativeExpression
+ : unaryExpression (('*' | '/') unaryExpression)*
+ ;
+
+unaryExpression
+ : ('-') unaryExpression
+ | '!' unaryExpression
+ | primaryExpression
+ ;
+
+newExpression
+ : 'new' IDENTIFIER
+ ;
+
+fieldExpression
+ : primaryExpression '.' IDENTIFIER
+ ;
+
+primaryExpression
+ : IDENTIFIER
+ | INTEGER_LITERAL
+ | 'true'
+ | 'false'
+ | 'null'
+ | newExpression
+ | '(' expression ')'
+ | fieldExpression
+ ;
+
+INTEGER_LITERAL
+ : [1-9][0-9]*
+ | [0]
+ ;
+
+IDENTIFIER
+ : NON_DIGIT (NON_DIGIT | DEC_DIGIT)*
+ ;
+
+NON_DIGIT: [a-zA-Z_];
+DEC_DIGIT: [0-9];
+```
diff --git a/docs/chapter12/Makefile b/docs/chapter12/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/docs/chapter12/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/docs/chapter12/README.ja.md b/docs/chapter12/README.ja.md
new file mode 100644
index 00000000..2b0f19dc
--- /dev/null
+++ b/docs/chapter12/README.ja.md
@@ -0,0 +1,101 @@
+# 第12章: 参照
+
+[English](README.md) | 日本語
+
+[前: 第11章](../chapter11/README.ja.md) |
+[次: 第13章](../chapter13/README.ja.md)
+
+この文書は [原文](README.md) の日本語訳です。
+
+第10章と第11章では、構造体に整数フィールドを追加し、そのメモリへの作用を SSA で表しました。この章では、まだ定義が現れていない構造体も含め、フィールドにほかの構造体への参照を格納できるようにします。メモリグラフを変更せずに、連結リストや互いを参照するオブジェクトを扱えます。
+
+線形の Git 履歴で[この章](https://github.com/SeaOfNodes/Simple/tree/linear-chapter12)を読むことや、[第11章との差分](https://github.com/SeaOfNodes/Simple/compare/linear-chapter11...linear-chapter12)を見ることもできます。
+
+## 型付きフィールドと前方参照
+
+```java
+struct Person {
+ int age;
+ FamilyTree? tree;
+}
+struct FamilyTree {
+ Person? father;
+ Person? mother;
+}
+```
+
+パーサーの `TYPES` テーブルは名前を型に対応付けます。初期状態では `int`(およびほかのプリミティブ型。後の章でさらに登場します)が入っています。`type()` が未知の名前を使う宣言を認識すると、`_fields == null` の、名前だけの `TypeStruct` を登録します。これは構造体名だけがわかっていて、ほかの情報はない構造体です。その構造体へのポインタがあれば、参照フィールドを記述するには十分で、`?` によってポインタが null であることを許容します。
+
+`parseStruct()` は、すべてのフィールドを収集してから完全な構造体を `TYPES` に登録します。テーブルのエントリを置き換えるのであって、古い型を変更したり、フィールドリストの途中までを順次公開したりはしません。フィールドのエイリアスは、これまでと同じく宣言が完成した時点で割り当てます。
+
+[パーサー](../../src/main/java/com/seaofnodes/simple/Parser.java)、特に `type()`、`parseField()`、`parseStruct()` と、[文法](12-grammar.ja.md)を参照してください。
+
+## 再帰構造体: `L0` と `L1`
+
+```java
+struct LLI { LLI? next; int i; }
+```
+
+コンパイラが実際に何を構築するかを覚えておくには、次の2つの記述が役立ちます。
+
+```text
+L0 = TypeStruct("LLI", fields = null)
+L1 = TypeStruct("LLI", fields = { next: pointer-to-L0?, i: int })
+TYPES["LLI"] = L1
+```
+
+`L0` は `LLI? next` フィールドをパースするときに作られます。閉じ波括弧の後で、名前テーブル内の `L0` を `L1` が置き換えます。`L1` 内の `next` フィールドは引き続き `L0` を指します。`L1` に戻るように書き換えません。
+
+この設計は、**不変で浅い参照を、必要に応じて名前で解決する**ものです。実行時のオブジェクトはサイクルを形成しても、コンパイラの型記述は有限で非循環のままです。これは、**再帰的な型の展開を止める**意図的な決定です。すべての参照に完成した定義を再帰的に代入すると、無限に展開するか、循環する型のインターン化、等価性、ハッシュ、束の操作が必要になります(実際に、束を扱う章で登場します)。
+
+[`TypeStruct`](../../src/main/java/com/seaofnodes/simple/type/TypeStruct.java) は、代わりに名前だけの記述で止めます。`dual()` と `glb()` はその記述をそのままにします。同じ構造体の完全な記述と名前だけの記述の meet は、名前だけの記述になります。これによってフィールドの詳細は失われますが、構造体の識別情報は失われません。`L0` をますます深い `L1`、`L2` などの列へと展開しようとするパスはありません。
+
+## 浅い参照の解決
+
+`head.next` のパース時、`parsePostfix()` はポインタの構造体名を取り出し、`TYPES` で現在の宣言を検索します。ポインタ自身の型にまだ `L0` が含まれていても、その宣言からフィールドの配置とエイリアスを得ます。`head.next.next.i` のような連鎖には、次のフィールドアクセスでも検索を繰り返せば十分です。
+
+局所宣言や代入では、`parseExpressionStatement()` も、代入の互換性を確認する前に名前だけのポインタを解決します。この「深める」処理はチェックに使う一時的な型を変更するだけで、式ノードの型を書き換えたり、グラフ内の古い参照をすべて置き換えたりはしません。
+
+```java
+struct LLI { LLI? next; int i; }
+LLI? head = null;
+while (arg) {
+ LLI x = new LLI;
+ x.next = head;
+ x.i = arg;
+ head = x;
+ arg = arg - 1;
+}
+if (!head) return 0;
+LLI? next = head.next;
+if (next == null) return 1;
+return next.i;
+```
+
+null チェックは、生き残る制御経路でポインタの型を絞り込みます。特に、明示的な `else` がなくても、`if` の false 経路はその絞り込みを記録しなければなりません。名前の解決はフィールドの定義を与えますが、ポインタが null でないことを証明するわけではありません。
+
+## 初期化と不完全な定義
+
+`newStruct()` は、各フィールドをその型の `makeInit()` で初期化します。整数はゼロ、参照は null です。Load と Store は第11章と同じエイリアスとメモリ最適化を使います。したがって、初期化 Store からの Load は null に畳み込めます。
+
+使われない前方参照は、最後まで定義する必要がありません。
+
+```java
+struct Holder { Missing? ref; }
+Holder h = new Holder;
+return h.ref; // null; no definition of Missing is needed
+```
+
+ここでは、完全な定義なしに null でない `Missing` を構築する方法はありません。`new Missing` は拒否されます。そのフィールドにアクセスするにも、null でないポインタに加えて定義が必要です。null を許容する参照型に言及するだけでは、プログラムの終わりまでに定義する義務は生じません。
+
+この章には、初期化に関する一時的な許容事項が1つあります。
+
+```java
+struct N { N next; int i; }
+N n = new N;
+return n.next; // null, despite the non-null field declaration
+```
+
+初期化 Store は、null を許容しない参照フィールドにも null を書き込めます。通常の `n.next = null` は拒否されます。第16章ではコンストラクタを追加して初期化をチェックします。この章では、この区別を [`StoreNode`](../../src/main/java/com/seaofnodes/simple/node/StoreNode.java) に明示的に保持します。
+
+[参照のテスト](../../src/test/java/com/seaofnodes/simple/Chapter12Test.java)は、連結リスト、相互参照、null チェック、不完全な型を検証します。`make tests` で実行でき、`make view` は同じ未スケジュールのグラフを表示します。これで第13章には、ロード/ストアの反依存も含めた大域的コード移動の導入に必要な、メモリと参照の意味論がそろいました。
diff --git a/docs/chapter12/README.md b/docs/chapter12/README.md
new file mode 100644
index 00000000..5087ee21
--- /dev/null
+++ b/docs/chapter12/README.md
@@ -0,0 +1,150 @@
+# Chapter 12: References
+
+English | [日本語](README.ja.md)
+
+[Previous: Chapter 11](../chapter11/README.md) |
+[Next: Chapter 13](../chapter13/README.md)
+
+Chapters 10 and 11 gave structs integer fields and represented their memory
+effects in SSA. This chapter lets fields contain references to other structs,
+including structs whose definitions have not yet appeared. Linked lists and
+mutually referring objects become possible without changing the memory graph.
+
+You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter12)
+in the linear Git history and [compare it with Chapter 11](https://github.com/SeaOfNodes/Simple/compare/linear-chapter11...linear-chapter12).
+
+## Typed fields and forward references
+
+```java
+struct Person {
+ int age;
+ FamilyTree? tree;
+}
+struct FamilyTree {
+ Person? father;
+ Person? mother;
+}
+```
+
+The parser's `TYPES` table maps names to types. It initially contains `int`
+(and any other primitive types, more are showing up in later chapters). When
+`type()` recognizes a declaration using an unknown name, it installs a
+name-only `TypeStruct`, with `_fields == null` - this a struct where we only
+know the struct name, and no other information. A pointer to that struct is
+enough to describe a reference field,`?` allows the pointer to be null.
+
+`parseStruct()` collects all fields before installing the complete struct in
+`TYPES`. It replaces the table entry; it does not mutate the old type or
+publish successive prefixes of the field list. Field aliases are allocated
+with the completed declaration, as before.
+
+See [the parser](../../src/main/java/com/seaofnodes/simple/Parser.java), particularly
+`type()`, `parseField()`, and `parseStruct()`, and the
+[grammar](12-grammar.md).
+
+## Recursive structs: `L0` and `L1`
+
+```java
+struct LLI { LLI? next; int i; }
+```
+
+Two descriptions are useful for remembering what the compiler actually builds:
+
+```text
+L0 = TypeStruct("LLI", fields = null)
+L1 = TypeStruct("LLI", fields = { next: pointer-to-L0?, i: int })
+TYPES["LLI"] = L1
+```
+
+`L0` is created when parsing the `LLI? next` field. After the closing brace,
+`L1` replaces it in the name table. The `next` field inside `L1` still points
+to `L0`; it is not patched to point back to `L1`.
+
+The design is **immutable shallow references, resolved by name when needed**.
+The runtime objects may form a cycle; their compiler type descriptions remain
+finite and acyclic. This is an intentional decision to **stop recursive type
+expansion**. Recursively substituting the completed definition into every
+reference would either expand forever or require cyclic type interning,
+equality, hashing, and lattice operations (which indeed show up in a lattice
+chapter).
+
+[`TypeStruct`](../../src/main/java/com/seaofnodes/simple/type/TypeStruct.java)
+instead stops at the name-only description. Its `dual()` and `glb()` leave that
+description alone. Meeting a complete description with a name-only description
+of the same struct yields the name-only description. That loses field detail
+without losing the struct's identity. There is no pass trying to expand `L0`
+into an ever deeper sequence of `L1`, `L2`, and so on.
+
+## Resolving a shallow reference
+
+When parsing `head.next`, `parsePostfix()` takes the pointer's struct name and
+looks up the current declaration in `TYPES`. It gets the field layout and alias
+from that declaration, even if the pointer's own type still contains `L0`.
+Doing the lookup again for the next field access is sufficient for a chain
+such as `head.next.next.i`.
+
+For a local declaration or assignment, `parseExpressionStatement()` also
+resolves a name-only pointer before checking assignment compatibility. This
+"deepening" changes the temporary type used for the check; it does not rewrite
+the expression node's type or replace all old references in the graph.
+
+```java
+struct LLI { LLI? next; int i; }
+LLI? head = null;
+while (arg) {
+ LLI x = new LLI;
+ x.next = head;
+ x.i = arg;
+ head = x;
+ arg = arg - 1;
+}
+if (!head) return 0;
+LLI? next = head.next;
+if (next == null) return 1;
+return next.i;
+```
+
+The null checks refine the pointer on the surviving control path. In
+particular, the false path of an `if` must record its refinement even when
+there is no explicit `else`. Resolving a name supplies the field definition;
+it does not prove that the pointer is non-null.
+
+## Initialization and incomplete definitions
+
+`newStruct()` initializes each field using its type's `makeInit()`: zero for
+integers and null for references. Loads and Stores use the same aliases and
+memory optimizations as Chapter 11. A Load from an initializing Store can
+therefore fold to null.
+
+An unused forward reference need not ever be defined:
+
+```java
+struct Holder { Missing? ref; }
+Holder h = new Holder;
+return h.ref; // null; no definition of Missing is needed
+```
+
+There is no way here to construct a non-null `Missing` without its complete
+definition: `new Missing` is rejected. Accessing one of its fields also needs
+a definition, as well as a non-null pointer. Simply mentioning a nullable
+reference type does not impose a requirement to define it before the end of
+the program.
+
+There is one temporary initialization allowance in this chapter:
+
+```java
+struct N { N next; int i; }
+N n = new N;
+return n.next; // null, despite the non-null field declaration
+```
+
+The initializing Store may write null even into a non-null reference field.
+An ordinary `n.next = null` is rejected. Chapter 16 adds constructors and
+checks initialization; this chapter keeps the distinction explicit in
+[`StoreNode`](../../src/main/java/com/seaofnodes/simple/node/StoreNode.java).
+
+The [reference tests](../../src/test/java/com/seaofnodes/simple/Chapter12Test.java)
+exercise linked lists, mutual references, null checks, and incomplete types.
+Run them with `make tests`; `make view` displays the same unscheduled graph.
+Chapter 13 now has the memory and reference semantics it needs to introduce
+global code motion, including load/store anti-dependencies.