特徴
自然な日本語に見えて、読み方はひと通りにしか決まらない──そのための言語設計です。
文章がそのままプログラム
字下げも括弧も使いません。「〜を受け取ったとき、」「〜ならば、」「〜を送る。」といった日本語の言い回しで構造を表します。
アクターとメッセージ
処理の単位は独立したアクター。状態を共有せず、メッセージを送り合って協調します。このページの中で実際に動かせます。
二つの書き方を行き来
文章形式と、字下げで構造を示す構造化形式。どちらで書いても同じ構文木になり、片方からもう片方を機械的に作れます。
一文方式
「〜ならば、」の本体はその一文だけ。二文以上は「次のことを行う。…以上。」で囲みます。これで日本語の曖昧さを文法から締め出します。
衝突 0 の LR(1) 文法
文法は bison で検査済み。衝突は 0 件で、正しい文章なら読み方は必ずひと通りに決まります(全 85 規則)。
名前は宣言から切り出す
日本語には空白がないので、宣言された名前(「先のフォーク」など)と予約語を、長いものから優先して切り出します。
二つの書き方
5 人の哲学者問題の「フォーク」アクターを、二つの形式で並べました。左を解析すると右が得られ、右を逆変換すると左に戻ります。
文章形式(インデントなし)
フォークというアクターを定義する。 フォークは番号と使用中と待ち行列を持つ。 番号の初期値は0とし、使用中の初期値はいいえとし、待ち行列の初期値は空とする。 フォークが「取りたい」というメッセージと哲学者を受け取ったとき、使用中がいいえならば、使用中をはいに変更し、哲学者に「渡す」というメッセージを送る。そうでなければ、哲学者を待ち行列の末尾に追加する。 フォークが「返す」というメッセージを受け取ったとき、待ち行列が空でなければ、待ち行列の先頭から次の哲学者を取り出し、次の哲学者に「渡す」というメッセージを送る。そうでなければ、使用中をいいえに変更する。 これでフォークの定義を終わる。
構造化形式(インデントあり)
「フォーク」というアクターを定義する。
状態は 番号、使用中、待ち行列。
初期状態は
番号 は 0。
使用中 は いいえ。
待ち行列 は 空。
以上。
「取りたい」と 哲学者 を受け取ったとき、
もし 使用中 が いいえ ならば、
使用中 は はい。
哲学者 に「渡す」を送る。
そうでなければ、
待ち行列 に 哲学者 を追加する。
以上。
以上。
「返す」を受け取ったとき、
もし 待ち行列 が 空 でない ならば、
次の哲学者 は 待ち行列 の先頭を取り出す。
次の哲学者 に「渡す」を送る。
そうでなければ、
使用中 は いいえ。
以上。
以上。
定義を終わる。哲学者は、番号の小さいフォークから先に取ります。そのため哲学者5だけはフォーク1を先に取り、全員が片方のフォークを握って待ち合う輪ができません(デッドロックしない)。フォークもアクターなので、隣り合わない哲学者は同時に食事できます。全文は「試してみる」の見本で読めます。
試してみる
サーバは使いません。このページに入っている解析器・逆変換器・実行系が、ブラウザの中で変換し、実行します。どちらの欄も書き換えられます。
逆変換で戻ってくるのは標準の書き方です。「その哲学者」の「その」や、文をどこで「。」で切ったかは構文木に残らないので、元の言い回しとは少し違うことがあります。構造化形式のほうは、往復しても一字も変わりません。
実行は、文章形式の欄のプログラムを構文木にして解釈します。アクターはそれぞれ受信箱を持ち、届いたメッセージを一通ずつ処理します。どのアクターが次に動くかは「動く順」で選びます。「ばらばら」は種つきの乱数なので、同じ種なら何度でも同じ動きを再現できます。種を変えると、並列ならではの別の動きになります。
文法
文章形式の文法は、文脈自由文法(BNF)で書けます。インデントを使わないので、Python のような字下げの扱いも要りません。
- 文は「。」で終わる。一つの文の中では、動作を連用形(「変更し、」)でつなぎ、終止形(「送る。」)で閉じる。
- 一文方式:「〜ならば、」「そうでなければ、」「〜について、」の本体は、その一文だけ。二文以上は「次のことを行う。 … 以上。」で囲む。
- 条件の入れ子は「次のことを行う。」の中に書く。こうすると「そうでなければ」がどの「ならば」に付くか迷う余地がない。
- 受信節(「〜を受け取ったとき、」)の本体は、次の受信節か「これで〜の定義を終わる。」まで。
- 名前はアクター名・状態・受信の引数・「〜と名付ける」「〜を取り出す」で導入され、字句解析は予約語と宣言済みの名前を最長一致で切り出す。
BNF 全 85 規則を見る(bison の文法から自動生成)
1 <プログラム> ::= <定義の並び> "実行を始める。" <文の並び> "これで" "実行を終わる。" 2 <定義の並び> ::= ε 3 | <定義の並び> <アクター定義> 4 <アクター定義> ::= "名前" "というアクターを定義する。" <状態宣言> <定義本体> "これで" "名前" "の定義を終わる。" 5 <状態宣言> ::= "名前" "は" <名前の並び> "を持つ。" 6 <名前の並び> ::= "名前" 7 | <名前の並び> "と" "名前" 8 <定義本体> ::= ε 9 | <定義本体> <定義の項目> 10 <定義の項目> ::= <初期値文> 11 | <受信の頭> <文> 12 | <文> 13 <初期値文> ::= <初期値の並び> "とする。" 14 <初期値の並び> ::= <初期値> 15 | <初期値の並び> "とし、" <初期値> 16 <初期値> ::= <式の並び> "の初期値は" <式> 17 <受信の頭> ::= <式> "が" "「文字列」" "というメッセージ" "を受け取ったとき、" 18 | <式> "が" "「文字列」" "というメッセージ" "と" "名前" "を受け取ったとき、" 19 <文の並び> ::= ε 20 | <文の並び> <文> 21 <文> ::= <一文の中身> "。" 22 | "その後、" <一文の中身> "。" 23 | <条件文> 24 | "その後、" <条件文> 25 | <繰り返し文> 26 <一文の中身> ::= <終止節> 27 | <連用節> "、" <一文の中身> 28 <条件文> ::= <条件> <本体> 29 | <条件> <本体> "そうでなければ、" <本体> 30 <本体> ::= <一文の中身> "。" 31 | "次のことを行う。" <文の並び> "以上。" 32 <条件> ::= <式> "が" <式> "ならば、" 33 | <式> "が" <式> "でなければ、" 34 | <式> "が" <式> "より小さければ、" 35 <繰り返し文> ::= "数" "から" "数" "までの各番号について、" <本体> 36 <終止節> ::= <表示の前半> "表示する" 37 | <送信の前半> "送る" 38 | <変更の前半> "変更する|設定する" 39 | <加算の前半> "加える" 40 | <追加の前半> "追加する" 41 | <取り出しの前半> "取り出す" 42 | <名付けの前半> "名付ける" 43 <連用節> ::= <表示の前半> "表示し" 44 | <送信の前半> "送り" 45 | <変更の前半> "変更し|設定し" 46 | <加算の前半> "加え" 47 | <追加の前半> "追加し" 48 | <取り出しの前半> "取り出し" 49 | <名付けの前半> "名付け" 50 <表示の前半> ::= <式の並び> "を" 51 <送信の前半> ::= <式の並び> "に" "「文字列」" "というメッセージ" <添え物> "を" 52 | <式の並び> "に" "それぞれ" "「文字列」" "というメッセージ" <添え物> "を" 53 | <式> "の全員" "に" "「文字列」" "というメッセージ" <添え物> "を" 54 <添え物> ::= ε 55 | "と" <式> 56 <変更の前半> ::= <式の並び> "を" <式> "に" 57 <加算の前半> ::= <式の並び> "に" <式> "を" 58 <追加の前半> ::= <式の並び> "を" <式> "に" 59 | <式の並び> "を" <式> "の末尾" "に" 60 <取り出しの前半> ::= <式> "の先頭から" "名前" "を" 61 <名付けの前半> ::= <作るもの> "、" "名前" "と" 62 <作るもの> ::= "名前" "というアクター" "を" "1つ" "生成し" 63 | <式の並び> "を" "用意し" 64 <式の並び> ::= <式> 65 | <式の並び> "と" <式> 66 <式> ::= <項> 67 <項> ::= "名前" 68 | "その" "名前" 69 | "数" 70 | "「文字列」" 71 | "「文字列」" "という文字列" 72 | "はい" 73 | "いいえ" 74 | "なし" 75 | "空" 76 | "空の配列" 77 | "自分" 78 | "自分自身" 79 | "現在の番号" 80 | <項> "の" "名前" 81 | <項> "の" <位置> "番目" 82 <位置> ::= "数" 83 | "現在の番号" 84 | "(" <式> ")" 85 | "(" <式> "に" <式> "を" "加えた数" ")"
「次のことを行う。」で囲まずに条件を直接入れ子にできる版も作りました。この版は if‑then‑else の衝突がちょうど 1 件出ます。C 言語と同じく「一番近い『ならば』に付く」と決めれば、読み方はひと通りに決まります。この版は、文章の読み手がそう読むとは限らないので、標準にはしていません。
検証
「通るはず」ではなく、道具で確かめた結果です(2026 年 11 月 11 日)。
| 確かめたこと | 結果 |
|---|---|
| bison 3.8.2 で文法を検査(LALR(1)) | 衝突 0(状態 171) |
| 条件を直接入れ子にできる版の文法 | 衝突 1(else の付き先だけ) |
| 見本 4 本(文法違反の例を除く)を「文章 → 構造化 → 文章 → 構造化」と往復 | 構造化形式は 4 本とも一字一句同じ |
| 逆変換した文章をもう一度変換 | 4 本とも変わらない |
| このページの変換器(JavaScript)と C 版・Python 版の出力の突き合わせ(見本 5 本) | 5 本とも一致 (違反の例は両方とも同じ所で止まる) |
| 5 人の哲学者(番号の小さいフォークから取る版)を、乱数の種 1〜1000 で実行 | 1000 回とも全員が 3 回食べて満腹で終了 |
| 同じ問題で、全員が左のフォークから取る版を種 1〜1000 で実行 | 721 回はデッドロックで停止 (止まると待ちの輪を表示) |
| 哲学者の文章から文を消す・入れ替える・重ねた変異 300 本を、両方の解析器に通す | 300 本とも判定と出力が一致 (通った 103/弾いた 197) |
このページの解析器は、bison に渡した文法ファイルそのものから jison(bison 互換の生成器)で作っています。手で別の解析器を書いていないので、文法がずれることはありません。