3 * Toyohashi Open Platform for Embedded Real-Time Systems
5 * Copyright (C) 2007-2009 by TAKAGI Nobuhisa
7 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
8 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
13 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
17 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
20 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
22 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
24 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
30 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
44 #include "toppers/macro_processor.hpp"
45 #include "toppers/diagnostics.hpp"
46 #include "toppers/gettext.hpp"
47 #include "toppers/cpp.hpp"
48 #include <boost/format.hpp>
49 #include <boost/utility.hpp>
50 #include <boost/lexical_cast.hpp>
57 typedef macro_processor::element element;
58 typedef macro_processor::var_t var_t;
59 typedef macro_processor::context context;
61 inline std::tr1::int64_t get_i( var_t const& var, context const* p_ctx )
63 return macro_processor::to_integer( var, p_ctx );
65 inline std::string get_s( var_t const& var, context const* p_ctx )
67 return macro_processor::to_string( var, p_ctx );
74 * \param[in] line 行番号情報
75 * \param[in] arity 引数の個数
76 * \param[in] valid 期待している引数の個数
77 * \param[in] function_name 組み込み関数名
79 bool macro_processor::check_arity( text_line const& line, std::size_t arity, std::size_t valid, char const* function_name )
84 error( line, _( "too few arguments for `%1%\'" ), function_name );
86 else if ( arity > valid )
88 error( line, _( "too many arguments for `%1%\'" ), function_name );
98 * \brief 変数ダンプのための<<演算子
99 * \param[in,out] ostr 出力ストリーム
100 * \param[in] arg 変数を参照するためのペア
102 * \note 現在の実装では、arg.second は使用していない。
104 std::ostream& operator<<( std::ostream& ostr, std::pair< var_t const*, context const* > const& arg )
106 for ( var_t::const_iterator iter( arg.first->begin() ), last( arg.first->end() ); iter != last; ++iter )
108 if ( !iter->s.empty() )
114 ostr << iter->i.get();
116 if ( boost::next( iter ) != last )
126 * \param[in] line 行番号
127 * \param[in] arg_list マクロ実引数リスト
128 * \param[in] p_ctx マクロコンテキスト
130 * 第1マクロ実引数として指定した順序付きリストの要素数を返す。
131 * 第1マクロ実引数が順序付きリストでない場合は1を返す。また、第1マクロ実引数が無効な変数の場合は0を返す。
133 var_t bf_length( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
136 if ( macro_processor::check_arity( line, arg_list.size(), 1, "LENGTH" ) )
138 std::tr1::int64_t size = arg_list.front().size();
141 return var_t( 1, e );
146 * \param[in] line 行番号
147 * \param[in] arg_list マクロ実引数リスト
148 * \param[in] p_ctx マクロコンテキスト
150 * 第1マクロ実引数と第2マクロ実引数を文字列として比較し、一致する場合は真を、そうでなければ偽を返す。
152 var_t bf_eq( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
155 if ( macro_processor::check_arity( line, arg_list.size(), 2, "EQ" ) )
157 e.i = get_s( arg_list[ 0 ], p_ctx ) == get_s( arg_list[ 1 ], p_ctx );
159 return var_t( 1, e );
164 * \param[in] line 行番号
165 * \param[in] arg_list マクロ実引数リスト
166 * \param[in] p_ctx マクロコンテキスト
168 * 第1マクロ実引数が無効な変数の場合は第2実引数を返す。その他は第1実引数を返す。
170 var_t bf_alt( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
173 if ( macro_processor::check_arity( line, arg_list.size(), 2, "ALT" ) )
175 if ( !arg_list[0].empty() )
177 return arg_list[ 0 ];
181 return arg_list[ 1 ];
184 return var_t( 1, e );
189 * \param[in] line 行番号
190 * \param[in] arg_list マクロ実引数リスト
191 * \param[in] p_ctx マクロコンテキスト
193 * 第1マクロ実引数として与えた順序付きリストの各要素を、第2マクロ実引数の添え字とした場合の変数を評価し、
200 * $SORT({ 1,2,3 }, "FOO")$
204 var_t bf_sort( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
207 if ( macro_processor::check_arity( line, arg_list.size(), 2, "SORT" ) )
209 var_t list( arg_list[ 0 ] );
210 std::string field( get_s( arg_list[ 1 ], p_ctx ) );
211 std::vector< std::pair< element, std::tr1::int64_t > > temp;
213 for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter )
215 std::tr1::int64_t order = iter->i.get();
216 std::string name( ( boost::format( "%s[%d]" ) % field % order ).str() );
217 std::map< std::string, var_t >::const_iterator m_iter( p_ctx->var_map.find( name ) );
218 if ( m_iter == p_ctx->var_map.end() )
222 if ( !m_iter->second.empty() )
224 temp.push_back( std::make_pair( m_iter->second.front(), order ) );
228 std::stable_sort( temp.begin(), temp.end() );
230 for ( std::vector< std::pair< element, std::tr1::int64_t > >::const_iterator iter( temp.begin() ), last( temp.end() );
236 result.push_back( e );
244 * \param[in] line 行番号
245 * \param[in] arg_list マクロ実引数リスト
246 * \param[in] p_ctx マクロコンテキスト
248 * 第1マクロ実引数で指定した環境変数の値を返す。
250 var_t bf_environ( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
253 if ( macro_processor::check_arity( line, arg_list.size(), 1, "ENVIRON" ) )
255 std::string name = get_s( arg_list[ 0 ], p_ctx );
256 char const* env = std::getenv( name.c_str() );
264 if ( std::tr1::int64_t value = std::strtol( env, &endptr, 0 ) )
266 if ( *endptr == '\0' && errno == 0 )
272 return var_t( 1, e );
277 * \param[in] line 行番号
278 * \param[in] arg_list マクロ実引数リスト
279 * \param[in] p_ctx マクロコンテキスト
281 * 第1マクロ実引数をテキスト、第2マクロ実引数を数値として、値を生成する。
283 var_t bf_value( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
286 if ( macro_processor::check_arity( line, arg_list.size(), 2, "VALUE" ) )
288 if ( !arg_list[0].empty() )
290 e.s = get_s( arg_list[ 0 ], p_ctx );
292 if ( !arg_list[1].empty() )
294 e.i = get_i( arg_list[ 1 ], p_ctx );
297 return var_t( 1, e );
302 * \param[in] line 行番号
303 * \param[in] arg_list マクロ実引数リスト
304 * \param[in] p_ctx マクロコンテキスト
306 * 第1マクロ実引数と第2マクロ実引数を連結して新しい文字列を生成する。
308 var_t bf_concat( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
311 if ( macro_processor::check_arity( line, arg_list.size(), 2, "CAT" ) )
313 e.s = get_s( arg_list[ 0 ], p_ctx ) + get_s( arg_list[ 1 ], p_ctx );
315 return var_t( 1, e );
319 * \brief 順序リストの終端に要素を追加
320 * \param[in] line 行番号
321 * \param[in] arg_list マクロ実引数リスト
322 * \param[in] p_ctx マクロコンテキスト
324 * 第1マクロ実引数と第2マクロ実引数を連結して新しい順序付きリストを生成する。
326 var_t bf_append( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
329 if ( macro_processor::check_arity( line, arg_list.size(), 2, "APPEND" ) )
331 result = arg_list[ 0 ];
332 result.insert( result.end(), arg_list[ 1 ].begin(), arg_list[1].end() );
338 * \brief 順序リストの指定要素の参照
339 * \param[in] line 行番号
340 * \param[in] arg_list マクロ実引数リスト
341 * \param[in] p_ctx マクロコンテキスト
343 * 第1マクロ実引数で指定した順序リストの、第2マクロ実引数で指定した要素を返す。
345 var_t bf_at( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
348 if ( macro_processor::check_arity( line, arg_list.size(), 2, "CAT" ) )
352 e = arg_list[ 0 ].at( static_cast< std::vector< var_t >::size_type >( get_i( arg_list[1], p_ctx ) ) );
354 catch ( std::out_of_range& )
357 // 特に何もしない → この時点で e が空値であることを期待
360 return var_t( 1, e );
365 * \param[in] line 行番号
366 * \param[in] arg_list マクロ実引数リスト
367 * \param[in] p_ctx マクロコンテキスト
369 * 第1マクロ実引数で指定した文字列を翻訳する。
371 var_t bf_gettext( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
374 if ( macro_processor::check_arity( line, arg_list.size(), 1, "GETTEXT" ) )
376 std::string message = get_s( arg_list[ 0 ], p_ctx );
377 e.s = gettext( message );
379 return var_t( 1, e );
384 * \param[in] line 行番号
385 * \param[in] arg_list マクロ実引数リスト
386 * \param[in] p_ctx マクロコンテキスト
388 * 第1マクロ実引数で指定した初期化文字列によって、第2マクロ実引数以降を書式化する。
389 * 書式化文字列は、%nが使えないことを除き、printf関数のスーパーセットである。
390 * 正確な仕様は、boost::formatを参照のこと。
392 var_t bf_format( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
395 std::size_t arity = arg_list.size();
398 error( line, _( "too few arguments for `%1%\'" ), "FORMAT" );
400 std::string format_str = get_s( arg_list[ 0 ], p_ctx );
402 std::string debug_str = format_str;
403 if ( debug_str == "0x%08x" )
404 toppers::trace("%s", debug_str.c_str() );
406 boost::format fmt( format_str );
407 for ( std::size_t i = 1; i < arity; i++ )
409 std::pair< var_t const*, context const* > arg( &arg_list[i], p_ctx );
413 return var_t( 1, e );
418 * \param[in] line 行番号
419 * \param[in] arg_list マクロ実引数リスト
420 * \param[in] p_ctx マクロコンテキスト
422 * 第1マクロ実引数で指定した順序付きリストに含まれる第2マクロ実引数で指定した値に等しい要素を、
424 * 等しい要素が見つかればその要素へのインデックスを、そうでなければ空値を返す。
426 var_t bf_find( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
429 if ( macro_processor::check_arity( line, arg_list.size(), 2, "FIND" ) )
431 var_t list( arg_list[ 0 ] );
432 std::tr1::int64_t value( get_i( arg_list[ 1 ], p_ctx ) );
434 for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter )
436 if ( iter->i.get() == value ) // 発見!
438 e.i = iter - list.begin(); // iter は RandomAccessIterator
439 return var_t( 1, e );
447 * \brief 範囲指定による順序付きリスト
448 * \param[in] line 行番号
449 * \param[in] arg_list マクロ実引数リスト
450 * \param[in] p_ctx マクロコンテキスト
452 * 第1マクロ実引数で最初の値を、第2マクロ実引数で最後の値を指定する。
453 * { 最初の値, 最初の値 + 1, ... 最後の値 }
457 var_t bf_range( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
460 if ( macro_processor::check_arity( line, arg_list.size(), 2, "RANGE" ) )
462 std::tr1::int64_t arg1( get_i( arg_list[ 0 ], p_ctx ) );
463 std::tr1::int64_t arg2( get_i( arg_list[ 1 ], p_ctx ) );
465 for ( ; arg1 <= arg2; ++arg1 )
469 result.push_back( e );
477 * \param[in] line 行番号
478 * \param[in] arg_list マクロ実引数リスト
479 * \param[in] p_ctx マクロコンテキスト
481 * マクロ実引数を指定した場合、その文字列属性で指定したファイルにダンプした文字列を追記する。
482 * ファイル名として、"stdout"を指定した場合は標準出力、"stderr"を指定した場合は標準エラーに出力する。
483 * ファイル名を省略した場合は"stderr"を指定したものとして振舞う。
485 var_t bf_dump( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
487 std::size_t arity = arg_list.size();
491 error( line, _( "too many arguments for `%1%\'" ), "DUMP" );
494 std::string dump_str;
497 for ( std::map< std::string, var_t >::const_iterator iter( p_ctx->var_map.begin() ), last( p_ctx->var_map.end() );
501 dump_str += "$" + iter->first + "$ = { ";
502 if ( !iter->second.empty() )
505 for ( var_t::const_iterator iter2( iter->second.begin() ), last2( iter->second.end() );
509 dump_str += "\"" + iter2->s + "\"(";
510 if ( iter2->i ) // 値属性があれば...
512 dump_str += boost::lexical_cast< std::string >( *iter2->i );
520 std::string filename( "stderr" );
523 filename = get_s( arg_list[ 0 ], p_ctx );
525 if ( filename == "stdout" )
527 fputs( dump_str.c_str(), stdout );
529 else if ( filename == "stderr" )
531 fputs( dump_str.c_str(), stderr );
535 std::FILE* stream = std::fopen( filename.c_str(), "a" );
538 fputs( dump_str.c_str(), stream );
539 std::fclose( stream );
543 return var_t( 1, e );
548 * \param[in] line 行番号
549 * \param[in] arg_list マクロ実引数リスト
550 * \param[in] p_ctx マクロコンテキスト
552 * 第1マクロ実引数で指定した変数の内容をトレースする。
553 * 第2マクロ実引数を指定した場合、その文字列属性で指定したファイルにトレース内容を追記する。
554 * ファイル名として、"stdout"を指定した場合は標準出力、"stderr"を指定した場合は標準エラーに出力する。
555 * ファイル名を省略した場合は"stderr"を指定したものとして振舞う。
557 var_t bf_trace( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
559 std::size_t arity = arg_list.size();
563 error( line, _( "too few arguments for `%1%\'" ), "TRACE" );
565 else if ( arity > 2 )
567 error( line, _( "too many arguments for `%1%\'" ), "TRACE" );
570 var_t value( arg_list[ 0 ] );
572 std::string trace_str = "{ ";
573 for ( var_t::const_iterator iter( value.begin() ), last( value.end() );
577 trace_str += "\"" + iter->s + "\"(";
578 if ( iter->i ) // 値属性があれば...
580 trace_str += boost::lexical_cast< std::string >( *iter->i ) + " as integer";
582 else if ( !iter->v.empty() )
584 trace_str += "\"" + boost::lexical_cast< std::string >( iter->v ) + "\" as string";
590 std::string filename( "stderr" );
593 filename = get_s( arg_list[ 1 ], p_ctx );
595 if ( filename == "stdout" )
597 fputs( trace_str.c_str(), stdout );
599 else if ( filename == "stderr" )
601 fputs( trace_str.c_str(), stderr );
605 std::FILE* stream = std::fopen( filename.c_str(), "a" );
608 fputs( trace_str.c_str(), stream );
609 std::fclose( stream );
614 return var_t( 1, e );
619 * \param[in] line 行番号
620 * \param[in] arg_list マクロ実引数リスト
621 * \param[in] p_ctx マクロコンテキスト
624 var_t bf_escstr( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
627 if ( macro_processor::check_arity( line, arg_list.size(), 1, "ESCSTR" ) )
629 std::string str( get_s( arg_list[ 0 ], p_ctx ) );
630 e.s = quote_string( str );
632 return var_t( 1, e );
637 * \param[in] line 行番号
638 * \param[in] arg_list マクロ実引数リスト
639 * \param[in] p_ctx マクロコンテキスト
642 var_t bf_unescstr( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
645 if ( macro_processor::check_arity( line, arg_list.size(), 1, "UNESCSTR" ) )
647 std::string str( get_s( arg_list[ 0 ], p_ctx ) );
648 e.s = expand_quote( str );
650 return var_t( 1, e );
655 * \param[in] line 行番号
656 * \param[in] arg_list マクロ実引数リスト
657 * \param[in] p_ctx マクロコンテキスト
660 var_t bf_call( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
662 return macro_processor::call_user_function( line, arg_list, p_ctx );
667 struct bf_functor : std::binary_function< element const&, element const&, bool >
670 bf_functor( text_line const& line, std::string const& func_name, context* p_ctx )
671 : line_( line ), func_name_( func_name ), p_ctx_( p_ctx )
674 bool operator()( element const& lhs, element const& rhs )
676 std::vector< var_t > arg_list;
677 arg_list.reserve( 3 );
681 arg_list.push_back( var_t( 1, e ) );
682 arg_list.push_back( var_t( 1, lhs ) );
683 arg_list.push_back( var_t( 1, rhs ) );
684 int arg1 = static_cast< int >( *lhs.i );
685 int arg2 = static_cast< int >( *rhs.i );
687 var_t r = bf_call( line_, arg_list, p_ctx_ );
691 int retval = static_cast< int >( *r.front().i );
692 result = ( *r.front().i < 0 );
697 std::string func_name_;
705 * \param[in] line 行番号
706 * \param[in] arg_list マクロ実引数リスト
707 * \param[in] p_ctx マクロコンテキスト
710 var_t bf_lsort( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
712 if ( macro_processor::check_arity( line, arg_list.size(), 2, "LSORT" ) )
714 var_t temp( arg_list[ 0 ] );
715 std::string compare( arg_list[ 1 ].front().s );
716 std::stable_sort( temp.begin(), temp.end(), bf_functor( line, compare, p_ctx ) );
720 return var_t( 1, e );
725 * \param[in] line 行番号
726 * \param[in] arg_list マクロ実引数リスト
727 * \param[in] p_ctx マクロコンテキスト
730 var_t bf_isfunction( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
733 if ( macro_processor::check_arity( line, arg_list.size(), 1, "ISFUNCTION" ) )
735 std::string func_name( get_s( arg_list[ 0 ], p_ctx ) );
736 if ( p_ctx->func_map.find( func_name ) != p_ctx->func_map.end() )
745 return var_t( 1, e );
749 * \brief 順序付きリストの並びを逆にする
750 * \param[in] line 行番号
751 * \param[in] arg_list マクロ実引数リスト
752 * \param[in] p_ctx マクロコンテキスト
755 var_t bf_reverse( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
758 if ( macro_processor::check_arity( line, arg_list.size(), 1, "REVERSE" ) )
760 result = arg_list[ 0 ];
761 std::reverse(result.begin(), result.end());
768 * \param[in] line 行番号
769 * \param[in] arg_list マクロ実引数リスト
770 * \param[in] p_ctx マクロコンテキスト
772 * この組み込み関数は何も行わない。また、マクロ実引数のチェックも行わない。
774 * \note 空値を返さないのは、$NOOP()$のような使い方をしたときでも不正な参照が起こらないようにするため。
776 var_t bf_noop( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
779 return var_t( 1, e );
782 macro_processor::func_t const macro_processor::builtin_function_table[] =
784 { "LENGTH", bf_length },
788 { "ENVIRON", bf_environ },
789 { "VALUE", bf_value },
790 { "CONCAT", bf_concat },
791 { "APPEND", bf_append },
793 { "GETTEXT", bf_gettext },
794 { "_", bf_gettext }, // GETTEXTのシノニム
795 { "FORMAT", bf_format },
797 { "RANGE", bf_range },
799 { "TRACE", bf_trace },
800 { "ESCSTR", bf_escstr },
801 { "UNESCSTR", bf_unescstr },
803 { "LSORT", bf_lsort },
804 { "ISFUNCTION", bf_isfunction },
805 { "REVERSE", bf_reverse },