2015-08-28 02:35:36 +00:00
|
|
|
|
# まずは"Hello world!"
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-28 02:35:36 +00:00
|
|
|
|
はじめに取り組むプログラムは,もちろん**Hello world!**ですよね。
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
2015-08-08 23:17:43 +00:00
|
|
|
|
では「hello world!」と正しく入力できたら「OK」,そうでなければ「NG」と表示するプログラムを作ってみましょう!以下がソースコードです。
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
|
|
|
|
```cpp
|
2015-08-08 03:50:27 +00:00
|
|
|
|
// hello.cc
|
2015-08-07 03:10:21 +00:00
|
|
|
|
#include <iostream>
|
2015-08-08 03:50:27 +00:00
|
|
|
|
#include "peglib.h"
|
2015-08-28 02:35:36 +00:00
|
|
|
|
#include "linenoise.hpp"
|
2015-08-07 03:10:21 +00:00
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
|
{
|
2015-08-08 03:50:27 +00:00
|
|
|
|
// 文法を読み込んでパーサーを生成
|
2015-08-28 02:35:36 +00:00
|
|
|
|
peg::parser parser(R"(
|
|
|
|
|
PROGRAM <- _ HELLO _ WORLD '!' _
|
|
|
|
|
HELLO <- [hH] 'ello'
|
|
|
|
|
WORLD <- [wW] 'orld'
|
|
|
|
|
_ <- [ \t]*
|
|
|
|
|
)");
|
|
|
|
|
|
|
|
|
|
if (!parser) { // 文法に誤りがあったかチェック
|
2015-08-08 03:50:27 +00:00
|
|
|
|
cerr << "grammar error..." << endl;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (true) {
|
2015-08-28 02:35:36 +00:00
|
|
|
|
auto line = linenoise::Readline("> "); // 文字列を一行読み込み
|
|
|
|
|
|
|
|
|
|
if (line == "exit") { break; } // 終了
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
2015-08-28 02:35:36 +00:00
|
|
|
|
if (parser.parse(line.c_str())) { // ユーザーからの入力をパース
|
2015-08-08 03:50:27 +00:00
|
|
|
|
cout << "OK" << endl;
|
|
|
|
|
} else {
|
|
|
|
|
cout << "NG" << endl;
|
|
|
|
|
}
|
2015-08-28 02:35:36 +00:00
|
|
|
|
|
|
|
|
|
linenoise::AddHistory(line.c_str()); // 入力履歴に追加
|
2015-08-08 03:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2015-08-07 03:10:21 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-08-28 02:35:36 +00:00
|
|
|
|
このコードを`hello.cc`として保存してください。このコードは以下の2つのライブラリを使用するので,ダウンロードして`hello.cc`と同じディレクトリに保存してください。
|
|
|
|
|
|
|
|
|
|
* cpp-peglib C++ PEG parser library - [peblib.h](https://raw.githubusercontent.com/yhirose/cpp-peglib/master/peglib.h)
|
|
|
|
|
* cpp-linenoise C++ Readline library - [linenoise.hpp](https://raw.githubusercontent.com/yhirose/cpp-linenoise/master/linenoise.hpp)
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-28 02:35:36 +00:00
|
|
|
|
ではコンパイルしましょう。コンパイル時にはC++11の機能を有効にする必要があります。`clang++`のパージョン3.5ではこんな感じになります。
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-08 23:17:43 +00:00
|
|
|
|
clang++ -std='c++11' -o hello hello.cc
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-08 03:50:27 +00:00
|
|
|
|
g++ 5.1でもほとんど同じで,
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-08 23:17:43 +00:00
|
|
|
|
g++ -std='c+11' -o hello hello.cc'
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
|
|
|
|
Visual C++ 14 (Visual Studio 2015) では,
|
|
|
|
|
|
2015-08-13 02:28:29 +00:00
|
|
|
|
cl /EHsc hello.cc
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-13 02:28:29 +00:00
|
|
|
|
とするだけでコンパイルできます。
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-10 03:53:21 +00:00
|
|
|
|
では生成された実行ファイルを実行してみましょう。画面に`>`が表示され,ユーザーに入力を促します。何か文字列を入力してリターンキーを押してみましょう。正確に「hello world!」と入力すると「OK」と表示されます。何かおかしな入力をすると「NG」になります。
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
|
|
|
|
```
|
2015-08-08 03:50:27 +00:00
|
|
|
|
> はろーわーるど!
|
|
|
|
|
NG
|
|
|
|
|
> hello world!
|
|
|
|
|
OK
|
2015-08-10 03:53:21 +00:00
|
|
|
|
> hello world!
|
2015-08-08 03:50:27 +00:00
|
|
|
|
OK
|
2015-08-07 03:10:21 +00:00
|
|
|
|
```
|
|
|
|
|
|
2015-08-28 02:35:36 +00:00
|
|
|
|
見事にPEG版Hello worldをクリアです!(プログラムを終了したい時は`exit`を入力してください。)
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-08 03:50:27 +00:00
|
|
|
|
--
|
|
|
|
|
|
2015-08-08 23:17:43 +00:00
|
|
|
|
では,このプログラムのPEGに関する部分を順を追ってみましょう。
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
2015-08-08 23:17:43 +00:00
|
|
|
|
まずはPEGライブラリを読み込みます。`peglib.h`はC++ header-only libraryですので,他にファイルは必要ありません。
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
#include "peglib.h"
|
2015-08-07 03:10:21 +00:00
|
|
|
|
```
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
2015-08-10 03:53:21 +00:00
|
|
|
|
続いてPEGで文法を定義します。この文法は「hello world!」という文字列を受け付けるだけのとても簡単なものです。入力文字列の前後や「hello」と「world」の間には,任意の長さのスペースやタブを入れることができます。(ちなみに「world」と「!」の間には入れることができません。)
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
2015-08-28 02:35:36 +00:00
|
|
|
|
```
|
2015-08-10 03:53:21 +00:00
|
|
|
|
PROGRAM <- _ 'hello' _ 'world' '!' _
|
2015-08-08 03:50:27 +00:00
|
|
|
|
_ <- [ \t]*
|
2015-08-07 03:10:21 +00:00
|
|
|
|
```
|
|
|
|
|
|
2015-08-08 03:50:27 +00:00
|
|
|
|
この文法を理解するPEGパーサーを生成しましょう。`peglib::peg`がパーサーです。先ほどの定義した文法をコンストラクタに渡してパーサーを生成します。
|
|
|
|
|
|
|
|
|
|
```cpp
|
2015-08-08 23:17:43 +00:00
|
|
|
|
// 文法を読み込んでパーサーを生成
|
2015-08-28 02:35:36 +00:00
|
|
|
|
peg::parser parser(R"(
|
|
|
|
|
PROGRAM <- _ HELLO _ WORLD '!' _
|
|
|
|
|
HELLO <- [hH] 'ello'
|
|
|
|
|
WORLD <- [wW] 'orld'
|
|
|
|
|
_ <- [ \t]*
|
|
|
|
|
)");
|
|
|
|
|
|
|
|
|
|
if (!parser) { // 文法に誤りがあったかチェック
|
2015-08-08 03:50:27 +00:00
|
|
|
|
cerr << "grammar error..." << endl;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2015-08-07 03:10:21 +00:00
|
|
|
|
```
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
2015-08-08 23:17:43 +00:00
|
|
|
|
文法にエラーがあると、上記のように`parser`オブジェクトの真偽値が'false'になります。
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
2015-08-12 19:13:11 +00:00
|
|
|
|
最後に`parse`メソッドを呼び、ユーザーの入力した文字列をパースします。成功すると`true`が返ります。
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
|
|
|
|
```cpp
|
2015-08-28 02:35:36 +00:00
|
|
|
|
if (parser.parse(line.c_str())) { // ユーザーからの入力をパース
|
2015-08-08 03:50:27 +00:00
|
|
|
|
cout << "OK" << endl;
|
|
|
|
|
} else {
|
|
|
|
|
cout << "NG" << endl;
|
|
|
|
|
}
|
2015-08-07 03:10:21 +00:00
|
|
|
|
```
|
|
|
|
|
|
2015-08-10 04:35:04 +00:00
|
|
|
|
これでパーサジェネレータを使う準備ができました。
|
|
|
|
|
|
|
|
|
|
実用的な言語の文法はずっと複雑ですし,パーサだけでコードを実行することできません。実際に動作する状態に持って行くには,さらに行うべきことがあります。インタープリタ型言語の場合,次のようなステップが必要です。
|
2015-08-08 03:50:27 +00:00
|
|
|
|
|
2015-08-08 23:17:43 +00:00
|
|
|
|
1. 言語の文法を定義する
|
|
|
|
|
2. パーサーを生成する
|
2015-08-10 03:53:21 +00:00
|
|
|
|
3. ソースコードをパースして、AST(抽象構文木)を生成する
|
2015-08-08 23:17:43 +00:00
|
|
|
|
4. ASTを実行するインタープリタを作成する
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-10 04:35:04 +00:00
|
|
|
|
PEGライブラリはステップ2と3のみ扱い,残りは自分で扱わなければなりません。しかし,この文法定義とインタープリタ作成の部分が個性を出せる一番面白いところで,デザインセンスと実装技術の見せ所です。
|
2015-08-07 03:10:21 +00:00
|
|
|
|
|
2015-08-12 19:13:11 +00:00
|
|
|
|
次章では,PEGがどんなものかを見てみましょう。
|