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
と違うのは、
- トークンに型がついている
-
Greet
に引数指定がある
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"
は、Parser
のValue
型から各記号の個別の型への安全な変換を提供する関数です。ちょうど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 );
ここでは、文法ファイルで指定したように、x
がHello
に関連付けられた値を、y
がWorld
に関連付けられた値をそれぞれ表しています。そしてこの関数の戻り値は、パーサによって、HelloWorld
に関連付けられることになります。
今回のmain
関数では、トークンをpost
するときに"Guten Tag, ", "Welt"
という値を渡しています。つまり、この値が、HelloWorld
受理時に、Hello
とWorld
に関連付けられた値として用いられることになるのです。
実行
% ./hello2 Guten Tag, Welt