tutorial 2 -- hello world γ

次はセマンティックアクションの引数です。

文法ファイル

%token Hello<std::string> World<std::string>;
%namespace hello_world;
%dont_use_stl;

HelloWorld<std::string> : [Greet] Hello(0) World(1);

hello1と違うのは、

の2点です。

1行目のトークンに対する型指定によって、caperはHello => std::string, World => std::stringという型を認識します。これにより、後の文法でこれらのトークンが出てきた場合、その値の型は関連付けられた型に等しいとみなして処理を行います。

5行目では、Greet呼び出し時の引数の指定を行っています。(数値)の部分がそれです。この数値は何番目の引数になるかということをあらわしています。(数値)がついていない記号はセマンティックアクション呼び出し時に用いられません。この定義では、Greetの0番目の引数がHelloに対応する値、1番目の引数がWorldに対応する値であることを示していることになります。

呼び出しファイル

#include <string>
#include <iostream>
#include "hello2.hpp"

struct SemanticAction {
    void syntax_error(){}
    void stack_overflow(){}
    void upcast( std::string& x, const std::string& y ) { x = y; }
    void downcast( std::string& x, const std::string& y ) { x = y; }

    std::string Greet( const std::string& x, const std::string& y )
    {
        std::cout << x << y << std::endl; return "";
    }
};

int main( int, char** )
{
    SemanticAction sa;
    hello_world::Parser< std::string, SemanticAction > parser( sa );

    parser.post( hello_world::token_Hello, "Guten Tag, " );
    parser.post( hello_world::token_World, "Welt" );
    parser.post( hello_world::token_eof, "" );

    return 0;
}

セマンティックアクションが少し複雑になっています。

今回導入された"downcast"は、ParserValue型から各記号の個別の型への安全な変換を提供する関数です。ちょうどupcastの反対の動作を行うためのものです。今回は「値集合全体を表す型」がstd::stringであり、「個別な型」もstd::stringしか使われていない(Hello, World, HelloWorldのいずれもstd::string型)ので、"void downcast( std::string& x, const std::string& y ) { x = y; }"の一行で終わりです。

Greetのシグネチャは以下のようになっています。

std::string Greet( const std::string& x, const std::string& y );
		

ここでは、文法ファイルで指定したように、xHelloに関連付けられた値を、yWorldに関連付けられた値をそれぞれ表しています。そしてこの関数の戻り値は、パーサによって、HelloWorldに関連付けられることになります。

今回のmain関数では、トークンをpostするときに"Guten Tag, ", "Welt"という値を渡しています。つまり、この値が、HelloWorld受理時に、HelloWorldに関連付けられた値として用いられることになるのです。

実行

% ./hello2
Guten Tag, Welt