📦 Out of Context リポジトリ

リポジトリ / emssr / independent_common_compiler

r2
r2 emssr1
# -*- coding: utf-8 -*-
r2 emssr2
"""採用語彙の表(`.dic`)を読む。見出しは be bo pa pi pu pe po の七音で綴り、中身はこの言語の文で書く。
r2 emssr3
r2 emssr4
    pepe	hu ka, he ka, no ka, he ka, no ka, he ka, no ka.
r2 emssr5
    popo	pepe ka, ki hu ka, no ka.
r2 emssr6
    pupu	=40                                   数だけの語は = で書ける(綴りは spell)
r2 emssr7
r2 emssr8
表を読むのは commonc で、この module は行を並べるだけになる(16 式 1.5: Lex ⊆ Σ* × C)。
r2 emssr9
`=N` の行は数を綴った文へ置き換えて渡す。`#` の行と空行は落とす。
r2 emssr10
r2 emssr11
辞書の語は全部 I → D で、番地を机に一つ置く。値にするのは文の中の mi、
r2 emssr12
書くのは 値 ka, 番地 ka, mu ka になる。Python が観測を語へ写すときの番地は
r2 emssr13
addresses() の表から取る。
r2 emssr14
"""
r2 emssr15
r2 emssr16
import re
r2 emssr17
r2 emssr18
LETTERS = ("be", "bo", "pa", "pi", "pu", "pe", "po")
r2 emssr19
r2 emssr20
r2 emssr21
def spell(n):
r2 emssr22
    """整数を基準の音節で綴る。二進の Horner: 上の桁から「もういちど、あわせる」で倍にし、
r2 emssr23
    桁が 1 なら「ひとつ、あわせる」を足す。"""
r2 emssr24
    if n < 0:
r2 emssr25
        return spell(-n) + ", ha ka"
r2 emssr26
    if n == 0:
r2 emssr27
        return "hu ka, he ka, ki ha ka, no ka"
r2 emssr28
    out = ["hu ka"]
r2 emssr29
    for bit in bin(n)[3:]:
r2 emssr30
        out.append("he ka, no ka")
r2 emssr31
        if bit == "1":
r2 emssr32
            out.append("ki hu ka, no ka")
r2 emssr33
    return ", ".join(out)
r2 emssr34
r2 emssr35
r2 emssr36
def spelled(name):
r2 emssr37
    return len(name) % 2 == 0 and all(name[i:i + 2] in LETTERS for i in range(0, len(name), 2))
r2 emssr38
r2 emssr39
r2 emssr40
def entries(dic):
r2 emssr41
    """(行番号, 見出し, 文) の列。# 行と空行は飛ばす。=N は綴った文にする"""
r2 emssr42
    out = []
r2 emssr43
    for n, line in enumerate(open(dic, encoding="utf-8"), 1):
r2 emssr44
        line = line.rstrip("\n")
r2 emssr45
        if not line.strip() or line.lstrip().startswith("#"):
r2 emssr46
            continue
r2 emssr47
        name, _, body = line.partition("\t")
r2 emssr48
        name, body = name.strip(), body.strip()
r2 emssr49
        if not spelled(name):
r2 emssr50
            raise ValueError("%s:%d: 見出し %s は be bo pa pi pu pe po で綴る" % (dic, n, name))
r2 emssr51
        if body.startswith("="):
r2 emssr52
            body = spell(int(body[1:])) + "."
r2 emssr53
        out.append((n, name, body))
r2 emssr54
    return out
r2 emssr55
r2 emssr56
r2 emssr57
def lexicon(dic):
r2 emssr58
    """commonc へ渡す表の文字列。一行が 見出し ⟨tab⟩ 文 ⟨改行⟩"""
r2 emssr59
    return "".join(name + "\t" + body + "\n" for _, name, body in entries(dic))
r2 emssr60
r2 emssr61
r2 emssr62
def addresses(dic):
r2 emssr63
    """数だけの語(=N)の表 {見出し: N}"""
r2 emssr64
    out = {}
r2 emssr65
    for line in open(dic, encoding="utf-8"):
r2 emssr66
        line = line.rstrip("\n")
r2 emssr67
        if not line.strip() or line.lstrip().startswith("#"):
r2 emssr68
            continue
r2 emssr69
        name, _, body = line.partition("\t")
r2 emssr70
        if body.strip().startswith("="):
r2 emssr71
            out[name.strip()] = int(body.strip()[1:])
r2 emssr72
    return out
r2 emssr73
r2 emssr74
r2 emssr75
_TOKEN = re.compile(r"[a-z]+")
r2 emssr76
r2 emssr77
r2 emssr78
def expanded_syllables(dic, body):
r2 emssr79
    """表を展開した後の音節の数。commonc の配列の刻み B を決めるためだけに数える"""
r2 emssr80
    size = {}
r2 emssr81
    for _, name, text in entries(dic):
r2 emssr82
        size[name] = _count(text, size)
r2 emssr83
    return _count(body, size)
r2 emssr84
r2 emssr85
r2 emssr86
def _count(text, size):
r2 emssr87
    total = 0
r2 emssr88
    for tok in _TOKEN.findall(text):
r2 emssr89
        if tok in size:
r2 emssr90
            total += size[tok]
r2 emssr91
        else:
r2 emssr92
            total += (len(tok) + 1) // 2
r2 emssr93
    return total