tutorial 1 -- hello world β

次は規則を受理したときにテキストを表示するようにしてみましょう。

セマンティックアクションについての学習です。

文法ファイル

%token Hello World;
%namespace hello_world;
%dont_use_stl;

HelloWorld<int> : [Greet] Hello World;

hello0.cpgとの違いは、5行目で"[Greet]"とセマンティックアクションが指定されていることだけです。これで、"HelloWorld"規則が受理されたときに、SemanticActionGreetメンバ関数が呼ばれることになります。

呼び出しファイル

#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;

この定義から、

ということが決定されます(引数については後のチュートリアルで説明します)。

実行

以上によって、規則受理時にGreetが実行されます。標準出力には"hello world"と出力されるはずです。