tutorial 1 -- hello world β
次は規則を受理したときにテキストを表示するようにしてみましょう。
セマンティックアクションについての学習です。
文法ファイル
%token Hello World; %namespace hello_world; %dont_use_stl; HelloWorld<int> : [Greet] Hello World;
hello0.cpg
との違いは、5行目で"[Greet]"
とセマンティックアクションが指定されていることだけです。これで、"HelloWorld"
規則が受理されたときに、SemanticAction
のGreet
メンバ関数が呼ばれることになります。
呼び出しファイル
#include <iostream> #include "hello1.hpp" struct SemanticAction { void syntax_error(){} void stack_overflow(){} void upcast( int& x, int y ) { x = y; } int Greet() { std::cout << "hello world" << std::endl; return 0; } }; int main( int, char** ) { SemanticAction sa; hello_world::Parser< int, SemanticAction > parser( sa ); parser.post( hello_world::token_Hello, 0 ); parser.post( hello_world::token_World, 0 ); parser.post( hello_world::token_eof, 0 ); return 0; }
こちらは、SemanticAction
に2行追加されています。
7行目のupcast
は、各非終端記号の型から、Parser
のインスタンス化のときにテンプレートパラメータとして与える「値集合すべてをあらわす型」への変換を提供する関数です。セマンティックアクション関数がひとつでもある場合、安全な型変換のためにこの関数が定義されていなければなりません。
このupcast
でy→xの変換を定義することになるのですが、今回は文法ファイルで定義したGreet
の受理結果を意味する"HelloWorld"
の型も、パーサの第1テンプレートパラメータとして指定した値集合全体の型もintですので、"void upcast( int& x, int y ) { x = y; }"
の1行で問題ありません。
9行目はこのチュートリアルの主目的のセマンティックアクションです。セマンティックアクション関数の引数・戻り値の型は文法規則での定義によります。ここでもう一度HelloWorld
の定義を見てみましょう。
HelloWorld<int> : [Greet] Hello World;
この定義から、
- この規則の型(=セマンティックアクションの戻り値)は
HelloWorld<int>
で指定したintである - 引数はない
実行
以上によって、規則受理時にGreet
が実行されます。標準出力には"hello world"
と出力されるはずです。