第5期サイボウズ・ラボユース成果報告会 言語処理系ゼミ
ユーザが構文を自由に変更できるプログラミング言語第5期サイボウズラボ・ユース成果報告会言語処理系ゼミ2016/03/30東京工業大学 理学部 情報科学科赤間 仁志
View Slide
目的● 構文を自由に変更できるプログラミング言語を作れないか?● ユーザが新しい構文を導入するメリット:○ 簡潔な見た目○ 少ない記述量で望んだ処理を行う● 書いてる途中にどんどん構文が変わっていく言語○ 面白そう○ 個人的な興味2
構文を変更できるとうれしい例 in C● 固定回数のループ文● forループ特有の条件部分を書かなくてよいfor (int i = 0; i < 10; i++) {printf(“Hello, %d\n”, i);}times(i, 10) {printf(“Hello, %d\n”, i);}Before After3#define times(i, n) \for (int i; i < (n); i++)
構文を変更できる言語の要件1. 処理系を変更することで構文を変更するのはダメ○ ユーザの手によって構文が変更できること2. 構文を追加することも,削除することもできること○ 不要になった構文もユーザの手で削除できる3. 構文を定義する構文も作成できること○ 構文の定義方法もユーザが作成可能4画像素材:http://www.irasutoya.com/
プログラミング言語Garbanzo(仮) ver. 2● 動的型つけ● インタプリタ方式○ いくつかの命令を搭載● 組み込みの構文は最小限○ ほぼ構文木をそのまま○ どんどん構文を拡張可能5{“@”: “print”,{“@”: “append”,“left”: “Hello”,“right”: ”World”}}画像素材:http://www.irasutoya.com/
一般的なインタプリタ構文解析器 評価器ASTソースコード結果“(3 + 4) * 6”*3 46+426
Garbanzoでの構文解析● 実行にともない,構文解析ルールを書き換える○ 文を1つずつ読み込んで実行● 構文解析器そのものがGarbanzoのプログラム○ Garbanzoの評価器の上で動作● 構文解析ルールはファーストクラスの値○ プログラム内で操作できる7プログラム構文を変更する宣言・命令新しい構文で記述したプログラム7
実行の流れ構文解析器評価器ASTソースコード結果構文解析実行ルールの追加・削除8
構文の定義● 組込の構文は,構文木をそのまま書くので,なんでもできる● けど長ったらしい9{"@": "set","object":{"@": "get","object":{"@": "get","object":{"@": "get","object":{"@": "get","object":{"@": "getenv"},"key": "/"},"key": "parser"},"key": "sentence"},"key": "children"},"key": "newline","value":{"@": "quote","value":{"@": "scope","body":{"0":{"@": "terminal","string": "\n"}}}}}
自動生成● 構文の定義をバージョン1のコードで自動生成○ 共通のランタイム● バージョン1(自作言語)でバージョン2(自作言語)の開発○ デバッガなし○ リファレンスなし○ 質問する相手なし● 生成された構文をGarbanzoの初期構文とする○ 標準ライブラリ的な構文10
自動生成● 構文の定義をバージョン1のコードで自動生成○ 共通のランタイム● バージョン1(自作言語)でバージョン2(自作言語)の開発○ デバッガなし○ リファレンスなし○ 質問する相手なし● 生成された構文をGarbanzoの初期構文とする○ 標準ライブラリ的な構文11ヤバい
初期構文を用いる例fib = fun(n)if n < 2n;else../fib(n - 1) + ../fib(n - 2);endend;/print(fib(7));12ここで利用している構文:● 数値リテラル● 代入● 匿名関数● if〜else文● 加算・減算● 関数呼び出し● etc.
構文の拡張例(カッコ)paren = block%/tokenize(/terminal("("));inner = %/parser/expression;%/tokenize(/terminal(")"));inner;end;/parser/expression/children/paren = paren;13ここで利用している構文:● block ~ end● 代入● 関数呼び出し● etc.
構文を拡張する構文● 構文の拡張はまだ煩雑● 構文を拡張する構文を作成● Schemeのマクロのような,パターンマッチ式での構文● 構文ルールの優先度(prec)も指定let:prec pattern1 pattern2 … patternN := template;● 初期構文を用いて約60行で実装14
構文を拡張する構文の使用例● 優先順位をまとめるためのカッコlet:0 “(“ inner:1000 “)” := inner;例: (4 + 5)● 添え字つきのアクセスlet:15 store:14 “[“ key:1000 “]” := /get(store, key);例: hoge[“key”]15
課題● 構文解析ルールの曖昧さへの対処○ ルールが合成可能な構文解析の方式が必要● Rubyでプロトタイプを実装したため,極めて低速○ のちのち他の言語で処理系を書き直す● 構文解析エラーのわかりやすさの向上16画像素材:http://www.irasutoya.com/
ラボユースでの活動● プログラミング言語処理系の開発○ プロトタイプ作成による試行錯誤● 情報処理学会 第57回プログラミング・シンポジウムに参加○ 論文を執筆○ 勉強になる17
まとめ● 構文を拡張可能なプログラミング言語Garbanzo(仮)を紹介● 構文解析ルールをユーザが動的に追加することで構文を変更● 構文を定義する構文も作成可能○ 構文の拡張をくり返すことができる● プログラミング・シンポジウムで発表○ 開発以外でもラボユースの活動を行う※適当につけた名前なので,カッコいい名前を募集中ですGitHub: https://github.com/akamah/garbanzo18
補足のスライド19
データ型● 文字列,数値,真偽値● 関数● データストア○ 順序をもったハッシュテーブル○ 構文木の構成などに利用20
細かな実行の流れ1. 特別な構文解析ルール sentence に従って入力から読み取る2. その結果を評価器に入力(eval)する○ この時,読み込んだプログラムが構文解析ルールを変更することがある3. 入力が空になるまで1から2をくり返す21
構文解析の実際● 構文解析ルール = Garbanzoのプログラム片● evalされると,構文解析を実行する● 構文解析専用の命令を評価器に搭載○ terminal: 指定された文字列を読み取る○ choice: 与えられた構文解析ルールを順に試す○ etc.22
構文解析器の変更● いくつかの構文解析ルール(= Garbanzoのプログラム)が既に存在● これら既に存在したルールの構文木を直接変更23
Ver. 1による自動生成の例integer = '/parser/integer = '{digit = [@: "quote", value: [@: "oneof", string: "0123456789"]]a = [@: "sub", left: [@: "tocode", string: %digit], right: [@: "tocode", string: "0"]]rest = [@: "many", parser: digit]ten = [@: "sub", left: [@: "tocode", string: "K"], right: [@: "tocode", string: "A"]]"generate";/foreach([store: rest, func: ^{n = [@: "sub", left: [@: "tocode", string: value], right: [@: "tocode", string: "0"]]../a = ../a * ../ten + n}]);a;}24