リポジトリ / emssr / independent_common_compiler
r2
| r2 emssr | 1 | # -*- coding: utf-8 -*- |
| r2 emssr | 2 | """commonc の作業領域を画面の形へ写す。 |
| r2 emssr | 3 | |
| r2 emssr | 4 | doc: commonc.alloc commonc.stages plain.tensor casm.lane64.block |
| r2 emssr | 5 | |
| r2 emssr | 6 | compile が終わった lane には、commonc が自分で組んだ表がそのまま残っている |
| r2 emssr | 7 | (19 §3.2)。この module はその表を読むだけで、計算を足さない。 |
| r2 emssr | 8 | |
| r2 emssr | 9 | 語 4 B 配列の刻み |
| r2 emssr | 10 | 語 5 n_syl 音節の数 |
| r2 emssr | 11 | 語 6 n_box 箱の数 |
| r2 emssr | 12 | 語 132 BODY 本文の最初の音節番号。手前は採用語彙の表 |
| r2 emssr | 13 | SYL 1B 音節番号 |
| r2 emssr | 14 | OPK 4B 種類 1 Cst 2 Add 3 Mul 4 Neg 5 Store 6 Ok 7 Load 8 EqBr 9 LtBr |
| r2 emssr | 15 | OPA 6B 第一引数の箱番号(Cst では分子) |
| r2 emssr | 16 | OPB 8B 第二引数の箱番号 |
| r2 emssr | 17 | OPD 10B 深度 δ |
| r2 emssr | 18 | OPL 12B 分岐先の箱番号 |
| r2 emssr | 19 | |
| r2 emssr | 20 | 覆いは λ(w) = 語 64 + w(19 式 6.1)なので、実行した後の語 64+w が箱 w の分子になる。 |
| r2 emssr | 21 | 分子と深度の対で二進有理数が決まる。 |
| r2 emssr | 22 | |
| r2 emssr | 23 | 値(w) = OPA・OPB から組んだ分子 / 2^OPD[w] 01 §1 |
| r2 emssr | 24 | """ |
| r2 emssr | 25 | |
| r2 emssr | 26 | import generators |
| r2 emssr | 27 | |
| r2 emssr | 28 | KIND = {1: "Cst", 2: "Add", 3: "Mul", 4: "Neg", 5: "Store", |
| r2 emssr | 29 | 6: "Ok", 7: "Load", 8: "EqBr", 9: "LtBr"} |
| r2 emssr | 30 | |
| r2 emssr | 31 | # 引数の欄を辺として読む種類。Cst の OPA は分子であって箱番号ではない |
| r2 emssr | 32 | EDGES = {2: (True, True), 3: (True, True), 4: (True, False), |
| r2 emssr | 33 | 5: (True, True), 7: (True, False), 8: (True, True), 9: (True, True)} |
| r2 emssr | 34 | |
| r2 emssr | 35 | WIRE_BASE = 64 # 19 式 6.1 |
| r2 emssr | 36 | |
| r2 emssr | 37 | |
| r2 emssr | 38 | def arrays(M): |
| r2 emssr | 39 | """commonc の表を切り出す。返りは辞書一つ""" |
| r2 emssr | 40 | B = M[4] |
| r2 emssr | 41 | n_syl, n_box = M[5], M[6] |
| r2 emssr | 42 | return { |
| r2 emssr | 43 | "B": B, |
| r2 emssr | 44 | "nSyl": n_syl, |
| r2 emssr | 45 | "nBox": n_box, |
| r2 emssr | 46 | "nNeed": M[3], |
| r2 emssr | 47 | "body": M[132], |
| r2 emssr | 48 | "syl": M[B:B + n_syl], |
| r2 emssr | 49 | "opk": M[4 * B:4 * B + n_box], |
| r2 emssr | 50 | "opa": M[6 * B:6 * B + n_box], |
| r2 emssr | 51 | "opb": M[8 * B:8 * B + n_box], |
| r2 emssr | 52 | "opd": M[10 * B:10 * B + n_box], |
| r2 emssr | 53 | "opl": M[12 * B:12 * B + n_box], |
| r2 emssr | 54 | } |
| r2 emssr | 55 | |
| r2 emssr | 56 | |
| r2 emssr | 57 | # ===== 第一段:音節列を語と層へ切る(16 §2)===== |
| r2 emssr | 58 | # |
| r2 emssr | 59 | # 疎テンソル S(k,q,r) は音節列の中に既に入っている。 |
| r2 emssr | 60 | # |
| r2 emssr | 61 | # r 層境界音 ka の出現回数 |
| r2 emssr | 62 | # q 層の中の位置。無声ワイヤ ki が一本ぶん進める |
| r2 emssr | 63 | # |
| r2 emssr | 64 | # 層の切れ目だけを数えるので、ここに文法解析は現れない。 |
| r2 emssr | 65 | |
| r2 emssr | 66 | def words(a, lexicon=None): |
| r2 emssr | 67 | """本文の音節を語へ切り、層番号と位置を付ける。表の区間は落とす""" |
| r2 emssr | 68 | body = generators.read(a["syl"][a["body"]:], lexicon) |
| r2 emssr | 69 | out, r, q = [], 0, 0 |
| r2 emssr | 70 | for spelling, symbol, pin, pout, boxes, layer, _n in body: |
| r2 emssr | 71 | if spelling == "ka": |
| r2 emssr | 72 | r += 1 |
| r2 emssr | 73 | q = 0 |
| r2 emssr | 74 | continue |
| r2 emssr | 75 | out.append({"syl": spelling, "sym": symbol, "pin": pin, "pout": pout, |
| r2 emssr | 76 | "boxes": boxes, "cls": layer, "r": r, "q": q}) |
| r2 emssr | 77 | q += 1 |
| r2 emssr | 78 | return out |
| r2 emssr | 79 | |
| r2 emssr | 80 | |
| r2 emssr | 81 | # ===== 採用語彙の見出し(16 §1.3〜1.5)===== |
| r2 emssr | 82 | # |
| r2 emssr | 83 | # 見出しは文を引く。Lex ⊆ Σ* × C(16 式 1.5)なので、余域はチェンバーであって |
| r2 emssr | 84 | # 原子箱ではない。差し込み(式 1.6)は書かれた位置 q から文の層を置くので、 |
| r2 emssr | 85 | # 見出しの境界の幅は文を畳めば出る。 |
| r2 emssr | 86 | # |
| r2 emssr | 87 | # 文を畳むときは、机が足りなくなった分を「外から借りた」と数える。 |
| r2 emssr | 88 | # 借りた本数が Γ⁻ の幅、畳み終えた机の高さが Γ⁺ の幅になる。 |
| r2 emssr | 89 | |
| r2 emssr | 90 | def fold(text, table): |
| r2 emssr | 91 | """文ひとつの (pin, pout, 箱の本数)。table は先に畳んだ見出しの表""" |
| r2 emssr | 92 | front, borrowed, boxes = [], 0, 0 |
| r2 emssr | 93 | layer = [] |
| r2 emssr | 94 | for spelling, _sym, pin, pout, bx, _cls, _n in generators.read( |
| r2 emssr | 95 | generators.stream(text), table): |
| r2 emssr | 96 | if spelling == "ka": |
| r2 emssr | 97 | front, borrowed, boxes = _fold_layer(front, layer, borrowed, boxes) |
| r2 emssr | 98 | layer = [] |
| r2 emssr | 99 | continue |
| r2 emssr | 100 | layer.append((spelling, pin, pout, bx)) |
| r2 emssr | 101 | front, borrowed, boxes = _fold_layer(front, layer, borrowed, boxes) |
| r2 emssr | 102 | return borrowed, len(front), boxes |
| r2 emssr | 103 | |
| r2 emssr | 104 | |
| r2 emssr | 105 | def _fold_layer(front, layer, borrowed, boxes): |
| r2 emssr | 106 | cur, out = 0, [] |
| r2 emssr | 107 | for spelling, pin, pout, bx in layer: |
| r2 emssr | 108 | if bx is None: |
| r2 emssr | 109 | boxes = None |
| r2 emssr | 110 | elif boxes is not None: |
| r2 emssr | 111 | boxes += bx |
| r2 emssr | 112 | take = 1 if spelling == "ki" else pin |
| r2 emssr | 113 | for _ in range(take): |
| r2 emssr | 114 | if cur >= len(front): |
| r2 emssr | 115 | front = front + ["Γ⁻"] |
| r2 emssr | 116 | borrowed += 1 |
| r2 emssr | 117 | if spelling == "ki": |
| r2 emssr | 118 | out.append(front[cur]) |
| r2 emssr | 119 | cur += 1 |
| r2 emssr | 120 | if spelling != "ki": |
| r2 emssr | 121 | out += [spelling] * pout |
| r2 emssr | 122 | return out + front[cur:], borrowed, boxes |
| r2 emssr | 123 | |
| r2 emssr | 124 | |
| r2 emssr | 125 | def lexicon(entries): |
| r2 emssr | 126 | """`.dic` の行を順に畳む。後の行は前の見出しを引ける""" |
| r2 emssr | 127 | table = {} |
| r2 emssr | 128 | for _n, name, body in entries: |
| r2 emssr | 129 | try: |
| r2 emssr | 130 | table[name] = fold(body, table) |
| r2 emssr | 131 | except ValueError: |
| r2 emssr | 132 | table[name] = (0, 0, None) |
| r2 emssr | 133 | return table |
| r2 emssr | 134 | |
| r2 emssr | 135 | |
| r2 emssr | 136 | # ===== 第二段:層ごとの frontier(19 §4.2)===== |
| r2 emssr | 137 | # |
| r2 emssr | 138 | # 箱は現在位置 q から消費する。無声ワイヤ ki が一本を素通しして位置を一つ進める。 |
| r2 emssr | 139 | # |
| r2 emssr | 140 | # fr(Λ_{r+1}) = fr(Λ_r) の未消費部 ‖ 層 r の出力 |
| r2 emssr | 141 | # |
| r2 emssr | 142 | # 位置 0 が机の上になる。hu は机の上へ置き、ki hu は一つ奥へ差し込む。 |
| r2 emssr | 143 | |
| r2 emssr | 144 | def frontier(ws): |
| r2 emssr | 145 | """層ごとの机と、箱が机のどこを取ってどこへ置いたか。 |
| r2 emssr | 146 | |
| r2 emssr | 147 | 返りの一行は |
| r2 emssr | 148 | |
| r2 emssr | 149 | r 層番号 |
| r2 emssr | 150 | in 入口の机。欄は語の綴り |
| r2 emssr | 151 | out 出口の机 |
| r2 emssr | 152 | put [{syl, take, give, at}] take は入口の区間、give は出口の区間 |
| r2 emssr | 153 | """ |
| r2 emssr | 154 | rows, front = [], [] |
| r2 emssr | 155 | for r in range(max((w["r"] for w in ws), default=-1) + 1): |
| r2 emssr | 156 | layer = [w for w in ws if w["r"] == r] |
| r2 emssr | 157 | if not layer: |
| r2 emssr | 158 | continue |
| r2 emssr | 159 | cur, out, put = 0, [], [] |
| r2 emssr | 160 | for w in layer: |
| r2 emssr | 161 | if w["syl"] == "ki": |
| r2 emssr | 162 | if cur < len(front): |
| r2 emssr | 163 | out.append(front[cur]) |
| r2 emssr | 164 | put.append({"syl": "ki", "take": [cur, cur + 1], |
| r2 emssr | 165 | "give": [len(out) - 1, len(out)], "wire": True}) |
| r2 emssr | 166 | cur += 1 |
| r2 emssr | 167 | continue |
| r2 emssr | 168 | at = len(out) |
| r2 emssr | 169 | out += [w["syl"]] * w["pout"] |
| r2 emssr | 170 | put.append({"syl": w["syl"], "cls": w["cls"], |
| r2 emssr | 171 | "take": [cur, cur + w["pin"]], |
| r2 emssr | 172 | "give": [at, at + w["pout"]], "wire": False}) |
| r2 emssr | 173 | cur += w["pin"] |
| r2 emssr | 174 | rest = front[cur:] |
| r2 emssr | 175 | for k in range(len(rest)): |
| r2 emssr | 176 | put.append({"syl": rest[k], "take": [cur + k, cur + k + 1], |
| r2 emssr | 177 | "give": [len(out) + k, len(out) + k + 1], "wire": True}) |
| r2 emssr | 178 | rows.append({"r": r, "in": list(front), "out": out + rest, "put": put}) |
| r2 emssr | 179 | front = out + rest |
| r2 emssr | 180 | return rows |
| r2 emssr | 181 | |
| r2 emssr | 182 | |
| r2 emssr | 183 | # ===== 第三段:箱の DAG(19 §4.2、§4.3)===== |
| r2 emssr | 184 | |
| r2 emssr | 185 | def boxes(a, wire=None): |
| r2 emssr | 186 | """箱を節点、OPA と OPB を辺として並べる。 |
| r2 emssr | 187 | |
| r2 emssr | 188 | wire は実行した後の作業領域。渡すと語 64+w を分子として添える。 |
| r2 emssr | 189 | """ |
| r2 emssr | 190 | opk, opa, opb, opd, opl = a["opk"], a["opa"], a["opb"], a["opd"], a["opl"] |
| r2 emssr | 191 | out = [] |
| r2 emssr | 192 | for i in range(a["nBox"]): |
| r2 emssr | 193 | k = opk[i] |
| r2 emssr | 194 | ua, ub = EDGES.get(k, (False, False)) |
| r2 emssr | 195 | node = {"i": i, "kind": KIND.get(k, str(k)), "d": opd[i], |
| r2 emssr | 196 | "in": [x for x, use in ((opa[i], ua), (opb[i], ub)) if use]} |
| r2 emssr | 197 | if k == 1: |
| r2 emssr | 198 | node["num"] = opa[i] |
| r2 emssr | 199 | if k in (8, 9): |
| r2 emssr | 200 | node["to"] = opl[i] |
| r2 emssr | 201 | if wire is not None and WIRE_BASE + i < len(wire): |
| r2 emssr | 202 | node["v"] = wire[WIRE_BASE + i] |
| r2 emssr | 203 | out.append(node) |
| r2 emssr | 204 | return out |
| r2 emssr | 205 | |
| r2 emssr | 206 | |
| r2 emssr | 207 | def gamma(a): |
| r2 emssr | 208 | """出口境界 Γ⁺。末尾の Cst と Store の連なりが語 0.. を埋める(19 §2.1)""" |
| r2 emssr | 209 | opk, opa = a["opk"], a["opa"] |
| r2 emssr | 210 | i = a["nBox"] - 1 |
| r2 emssr | 211 | out = [] |
| r2 emssr | 212 | while i >= 0 and opk[i] in (1, 5, 6): |
| r2 emssr | 213 | if opk[i] == 5 and opk[opa[i]] == 1 and opa[opa[i]] < WIRE_BASE: |
| r2 emssr | 214 | out.append({"word": opa[opa[i]], "box": a["opb"][i]}) |
| r2 emssr | 215 | i -= 1 |
| r2 emssr | 216 | return sorted(out, key=lambda x: x["word"]) |
| r2 emssr | 217 | |
| r2 emssr | 218 | |
| r2 emssr | 219 | def align(ws, a): |
| r2 emssr | 220 | """語と箱を並べて突き合わせる。 |
| r2 emssr | 221 | |
| r2 emssr | 222 | 生成元ごとに開く箱の本数は 16 §5 の表で決まる。読みの順に数えて合えば、 |
| r2 emssr | 223 | 画面の語と DAG の節点が一対一で結べる。判定値 Q の語は本数が固定でないので、 |
| r2 emssr | 224 | その場合は結ばずに ok = False を返す。 |
| r2 emssr | 225 | """ |
| r2 emssr | 226 | n, spans = 0, [] |
| r2 emssr | 227 | for w in ws: |
| r2 emssr | 228 | if w["boxes"] is None: |
| r2 emssr | 229 | return {"ok": False, "why": "箱の本数が固定でない語がある", "spans": []} |
| r2 emssr | 230 | spans.append([n, n + w["boxes"]]) |
| r2 emssr | 231 | n += w["boxes"] |
| r2 emssr | 232 | tail = a["nBox"] - n |
| r2 emssr | 233 | if tail < 0: |
| r2 emssr | 234 | return {"ok": False, "why": "箱が語の総和に足りない", "spans": []} |
| r2 emssr | 235 | return {"ok": True, "spans": spans, "tail": [n, a["nBox"]]} |
| r2 emssr | 236 | |
| r2 emssr | 237 | |
| r2 emssr | 238 | # ===== 第四段:lane64 の image(20 §7)===== |
| r2 emssr | 239 | |
| r2 emssr | 240 | def image(vcpu, img): |
| r2 emssr | 241 | """block への分け方(式 7.4)と、block の中の層(式 7.1、7.2)""" |
| r2 emssr | 242 | prog = vcpu.decode(img) |
| r2 emssr | 243 | _ent, _idx, bl = vcpu.blocks(prog) |
| r2 emssr | 244 | out = [] |
| r2 emssr | 245 | for pc, body, term, _stop in bl: |
| r2 emssr | 246 | lay = vcpu.layers(prog, body) |
| r2 emssr | 247 | out.append({"pc": pc, "n": len(body), |
| r2 emssr | 248 | "term": vcpu.NAME[prog[term][0]] if term is not None else "落ちる", |
| r2 emssr | 249 | "layers": [len(x) for x in lay]}) |
| r2 emssr | 250 | kinds = {} |
| r2 emssr | 251 | for ins in prog: |
| r2 emssr | 252 | kinds[vcpu.NAME[ins[0]]] = kinds.get(vcpu.NAME[ins[0]], 0) + 1 |
| r2 emssr | 253 | return {"bytes": len(img), "insns": len(prog), "blocks": out, "kinds": kinds} |
| r2 emssr | 254 | |
| r2 emssr | 255 | |
| r2 emssr | 256 | # ===== 二進有理数(01 §1、20 §0.3)===== |
| r2 emssr | 257 | |
| r2 emssr | 258 | def dyad(num, d): |
| r2 emssr | 259 | """x/2^δ を約分して (分子, 分母, 十進) にする""" |
| r2 emssr | 260 | while d > 0 and num % 2 == 0: |
| r2 emssr | 261 | num //= 2 |
| r2 emssr | 262 | d -= 1 |
| r2 emssr | 263 | den = 1 << d |
| r2 emssr | 264 | return {"num": num, "den": den, "dec": num / den if den else 0.0} |
| r2 emssr | 265 | |
| r2 emssr | 266 | |
| r2 emssr | 267 | # ===== 読む前の診断 ===== |
| r2 emssr | 268 | # |
| r2 emssr | 269 | # commonc は誤りを全部「報告 42」で返す。どこを直せばよいかが分からないので、 |
| r2 emssr | 270 | # 平文の側で分かる範囲を先に見る。ここで見るのは三つだけになる。 |
| r2 emssr | 271 | # |
| r2 emssr | 272 | # 1. 音節表の外の綴り 19 式 4.1 |
| r2 emssr | 273 | # 2. 机が足りない 平文は Γ⁻ = I から始まる(16 §1.1) |
| r2 emssr | 274 | # 3. 型の食い違い Bit を語へ書く、Ω の閉じへ Dyad を渡す |
| r2 emssr | 275 | # |
| r2 emssr | 276 | # 断定できない所は黙る。commonc の判定を上書きしない。 |
| r2 emssr | 277 | |
| r2 emssr | 278 | # 語が出す値の型。分からない語は None にして、その先の判定をやめる |
| r2 emssr | 279 | _CLASS = { |
| r2 emssr | 280 | "hu": "dyad", "no": "dyad", "ha": "dyad", "ti": "dyad", "se": "dyad", |
| r2 emssr | 281 | "mi": "dyad", "mo": "dyad", |
| r2 emssr | 282 | "hi": "bit", "so": "bit", "ne": "bit", "ra": "bit", "go": "bit", |
| r2 emssr | 283 | "to": "judge", "nu": "judge", "yu": "judge", "ye": "judge", "yo": "judge", |
| r2 emssr | 284 | "ri": "judge", "ru": "judge", "na": "judge", "ni": "judge", |
| r2 emssr | 285 | "re": "trace", "sa": "trace", "si": "trace", "ke": "trace", |
| r2 emssr | 286 | "su": "trace", "ro": "trace", "wa": "trace", |
| r2 emssr | 287 | "wi": "point", "ko": "point", "ta": "point", "de": "point", "do": "point", |
| r2 emssr | 288 | "wu": "reflection", "we": "reflection", "wo": "reflection", "ga": "reflection", |
| r2 emssr | 289 | "gi": "point", |
| r2 emssr | 290 | } |
| r2 emssr | 291 | |
| r2 emssr | 292 | _TYPE_NAME = {"dyad": "数", "bit": "判定", "judge": "判定値 𝒬"} |
| r2 emssr | 293 | |
| r2 emssr | 294 | |
| r2 emssr | 295 | def check(text, table=None): |
| r2 emssr | 296 | """平文を読む前に見る。直す場所が分かる文言を返す。問題が無ければ None""" |
| r2 emssr | 297 | try: |
| r2 emssr | 298 | syl = generators.stream(text) |
| r2 emssr | 299 | except ValueError as e: |
| r2 emssr | 300 | return str(e) |
| r2 emssr | 301 | |
| r2 emssr | 302 | front, layer = [], [] |
| r2 emssr | 303 | for spelling, _sym, pin, pout, _bx, _cls, _n in generators.read(syl, table or {}): |
| r2 emssr | 304 | if spelling == "ka": |
| r2 emssr | 305 | msg, front = _check_layer(front, layer) |
| r2 emssr | 306 | if msg: |
| r2 emssr | 307 | return msg |
| r2 emssr | 308 | layer = [] |
| r2 emssr | 309 | continue |
| r2 emssr | 310 | layer.append((spelling, pin, pout)) |
| r2 emssr | 311 | msg, _front = _check_layer(front, layer) |
| r2 emssr | 312 | return msg |
| r2 emssr | 313 | |
| r2 emssr | 314 | |
| r2 emssr | 315 | def _check_layer(front, layer): |
| r2 emssr | 316 | cur, out = 0, [] |
| r2 emssr | 317 | for spelling, pin, pout in layer: |
| r2 emssr | 318 | take = 1 if spelling == "ki" else pin |
| r2 emssr | 319 | got = [] |
| r2 emssr | 320 | for _ in range(take): |
| r2 emssr | 321 | if cur >= len(front): |
| r2 emssr | 322 | return ("机に置いた物が足りない。「%s」は %d つ取るが、机にはそれだけ無い。" |
| r2 emssr | 323 | "平文は空の机から始まるので、足りない分は hu で立てる" % (spelling, take)), front |
| r2 emssr | 324 | got.append(front[cur]) |
| r2 emssr | 325 | cur += 1 |
| r2 emssr | 326 | if spelling == "mu" and len(got) == 2 and got[1] in ("bit", "judge"): |
| r2 emssr | 327 | return ("%s を語へ書けない。mu が取る値は数でなければならない。" |
| r2 emssr | 328 | "mo を挟んで数へ戻す" % _TYPE_NAME[got[1]]), front |
| r2 emssr | 329 | if spelling == "yi" and got and got[0] == "dyad": |
| r2 emssr | 330 | return ("Ω の閉じ yi は判定を取る。いま机の上にあるのは数なので、" |
| r2 emssr | 331 | "hi などの判定をそのまま渡す"), front |
| r2 emssr | 332 | if spelling == "ki": |
| r2 emssr | 333 | out += got |
| r2 emssr | 334 | else: |
| r2 emssr | 335 | out += [_CLASS.get(spelling, None)] * pout |
| r2 emssr | 336 | return None, out + front[cur:] |