cpp-peglib/tutorial/chap_01.md

137 lines
5.2 KiB
Markdown
Raw Normal View History

2015-08-10 03:53:21 +00:00
# まずはHello world
2015-08-07 03:10:21 +00:00
2015-08-10 04:35:04 +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-07 03:10:21 +00:00
using namespace std;
2015-08-08 03:50:27 +00:00
// 文法定義
const auto grammar = R"(
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
int main(void)
{
2015-08-08 03:50:27 +00:00
// 文法を読み込んでパーサーを生成
peglib::peg parser(grammar);
// 文法に誤りがあったかチェック
if (!parser) {
cerr << "grammar error..." << endl;
return -1;
}
while (true) {
// 文字列を一行読み込み
cout << "> ";
string line;
getline(cin, line);
// ユーザーからの入力をパース
if (parser.parse(line.c_str())) {
cout << "OK" << endl;
} else {
cout << "NG" << endl;
}
}
return 0;
2015-08-07 03:10:21 +00:00
}
```
2015-08-08 23:17:43 +00:00
このコードを`hello.cc`に保存してそれからコンパイルしてみましょう。このコードはPEGパーサライブラリを使用するので[ここから](https://raw.githubusercontent.com/yhirose/cpp-peglib/master/peglib.h)`peglib.h`ダウンロードして`hello.cc`があるディレクトリに保存してください。
2015-08-07 03:10:21 +00:00
2015-08-08 23:17:43 +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-08 23:17:43 +00:00
cl -DUNICODE /EHsc hello.cc User32.lib
2015-08-07 03:10:21 +00:00
2015-08-08 23:17:43 +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-10 03:53:21 +00:00
見事にPEG版Hello worldをクリアですプログラムを終了したい時は`Ctrl+C`を押してください。)
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
```cpp
const auto grammar = R"(
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-10 03:53:21 +00:00
脇にそれますがこの文法には一つ大きなバグがあります。実は「helloworld!」のように言葉をくっつけて入力しても結果が「OK」になってしまいます。このバグの解決法は後の章で説明します。
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-08 03:50:27 +00:00
peglib::peg parser(grammar);
2015-08-07 03:10:21 +00:00
2015-08-08 23:17:43 +00:00
// 文法に誤りがあったかチェック
2015-08-08 03:50:27 +00:00
if (!parser) {
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-08 23:17:43 +00:00
最後に`parser.parse`メソッドを呼び、ユーザーの入力した文字列をパースします。成功すると`true`が返ります。
2015-08-08 03:50:27 +00:00
```cpp
2015-08-08 23:17:43 +00:00
// ユーザーからの入力をパース
2015-08-08 03:50:27 +00:00
if (parser.parse(line.c_str())) {
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-10 04:35:04 +00:00
では最初にPEG記法を使ってどのように言語を定義していくのか見てみましょう。