diff --git a/tutorial/chap_01.md b/tutorial/chap_01.md new file mode 100644 index 0000000..6f90b01 --- /dev/null +++ b/tutorial/chap_01.md @@ -0,0 +1,87 @@ +はろーわーるど! +============== + +まずはRubyでお馴染みの`irb`のようなREPL(Read-Eval-Print-Loop)環境を実現します。以下のソースコードを`repl.cc`に保存します。 + +```cpp +#include +#include "linenoise.hpp" + +using namespace std; + +int main(void) +{ + while (true) { + // 一行入力 + auto line = linenoise::Readline("> "); + + // 空行ならスキップ + if (line.empty()) { + break; + } + + // 入力テキストをそのまま出力 + cout << "echo: '" << line << "'" << endl; + + // 履歴に追加 + linenoise::AddHistory(line.c_str()); + } + return 0; +} +``` + +次に`linenoise.hpp`を[ここから](https://raw.githubusercontent.com/yhirose/cpp-linenoise/master/linenoise.hpp)ダウンロードして,`repl.cc`と同じディレクトリに保存します。私はこんな感じで`wget`を使いました。 + +``` +wget https://raw.githubusercontent.com/yhirose/cpp-linenoise/master/linenoise.hpp +``` + +続いてコンパイルです。わたしは`clang++`のパージョン3.5を使っています。 + +``` +clang++ -std='c++11' -o repl repl.cc +``` + +g++ 5.1では, + +``` +g++ -std='c+11 -o repl repl.cc' +``` + +Visual C++ 14 (Visual Studio 2015) では, + +``` +cl -DUNICODE /EHsc repl.cc User32.lib +``` + +とするとうまくいきました。 + +では生成された実行ファイル`repl`を実行してみましょう。 + +``` +./repl +``` + +REPLのプロンプト`>`が表示されるので,何か入力してリターンキーを押してみましょう。 + +``` +> はろーわーるど! +echo: 'はろーわーるど!' +> _ +``` + +プログラミング入門の定番「はろーわーるど!」が表示されました! + +実は入力したテキストは,履歴リストに追加されています。`Ctrl+P`か`↑`キーを押してみてください。 + +``` +> はろーわーるど!_ +``` + +このように`linenoise`ライブラリを使うと,以前に入力したテキストを呼び出すことができます。長い文字列を再度入力しなければならない時などはとても便利です。(`linenoise`に関する情報は[Githubのプロジェクトページ](https://github.com/yhirose/cpp-linenoise)をご覧ください。) + +`Ctrl+C`を押すとREPLから抜けることができます。 + +まだPEGについて何も出てきませんね...とりあえずPEGライブラリを[ここから](https://raw.githubusercontent.com/yhirose/cpp-peglib/master/peglib.h)ダウンロードして,後の章のために準備しておきましょう。このファイル`peglib.h`も同じディレクトリに保存してください。 + +これで必要な準備が終わりました! diff --git a/tutorial/code/repl.cc b/tutorial/code/repl.cc new file mode 100644 index 0000000..cf876cc --- /dev/null +++ b/tutorial/code/repl.cc @@ -0,0 +1,24 @@ +#include +#include "linenoise.hpp" + +using namespace std; + +int main(void) +{ + while (true) { + // テキスト入力 + auto line = linenoise::Readline("> "); + + // 空行ならスキップ + if (line.empty()) { + break; + } + + // 入力テキストをそのまま出力 + cout << "echo: '" << line << "'" << endl; + + // 履歴に追加 + linenoise::AddHistory(line.c_str()); + } + return 0; +} diff --git a/tutorial/intro.md b/tutorial/intro.md new file mode 100644 index 0000000..71a2ab4 --- /dev/null +++ b/tutorial/intro.md @@ -0,0 +1,16 @@ +前書き +===== + +今この本を手にとっているみなさんは「ぜひプログラミング言語を作ってみたい! 」と考えている方のお一人かもしれません。でも自分で言語を作ってみるなんて敷居が高過ぎる? 何を隠そう少し前の私も,『コンパイラ』と名の付く技術書をパラっと眺める度に,その理論の難解さに恐れを抱きました。Orz... + +少し前,仕事で数十万行にも及ぶ大きなデータファイルを作成する必要がありました。エディタを使って手作業するなら軽く数ヶ月かかってしまいます。それでは大変なので,設定ファイルを定義してプログラムにデータを生成させようということになりました。数千行の設定ファイルを作れば,ものの数分で膨大なデータを生成してくれるのです。 + +はたして「プログラミング言語のようなもの」を作ることになりました。「さて,どう実装する? YACCを使う? パーサーを手書きで書く? でも面倒で難しそう...」と悩みつつWebで検索していたところ,偶然[『PEG』](https://ja.wikipedia.org/wiki/Parsing_Expression_Grammar)という可愛らしい言葉が目に入りました。PEGとは「Parsing Expression Grammar」の略号です。調べてみると,難しそうなYACCより簡単に文法が定義でき,かつPEGをサポートするライブラリがパーサーを生成してくれるのです。さらに調べてみると,PEGライブラリ自体が比較的簡単に実装可能ということも発見しました! + +とりあえずいろんなWebの記事を漁りながら,仕事で使っているC++用のPEGライブラリを見よう見まねで作り始めました。はい,意外とあっさり実装できました。そのあと,設定ファイルの文法をデザインし(これがとても面白い!),そのパーサーをPEGライブラリでいとも簡単に作ることができました。 + +これが契機となって「自分にもプログラミング言語を作ることができるかも」と思えるようになりました。文法定義とパーサーの生成がとても簡単になったので,言語作成の敷居がぐっと下がったように感じたのです。さらにこのPEGライブラリをもっと使いやすくなるよう改良を重ね,実際に簡単な言語を作ってみました。これがとても面白い! + +恥ずかし話ですが,「字句解析,構文解析,構文木,意味解析,コード生成,最適化...」などの言語処理系の深い専門知識は今もって持ち合わせていません。PEGの[オリジナルの論文](http://bford.info/pub/lang/peg)も完璧に理解しているわけではありません。それでも言語処理系を作ることの楽しさを十分経験でき,さらにこの分野をもっと勉強したいというモチベーションを得ることもできました。 + +皆さんにもこの同じ喜びを味わっていただきたと思い,この文章を書いています。必要なのはテキストエディタ(当然Vimですよね?)とC++11対応のコンパイラだけです。最新のClang,GCC,Visual C++をお持ちであれば,さっそく始めましょう! diff --git a/tutorial/toc.md b/tutorial/toc.md new file mode 100644 index 0000000..baf6693 --- /dev/null +++ b/tutorial/toc.md @@ -0,0 +1,10 @@ +目次 +==== + + * [序文](intro.md) + * [目次](toc.md) + +章 +-- + + 1. [はろーわーるど!](chap_01.md)