OSDN Git Service

First commitment for the BlackTank LPC1769.
[blacktank/blacktank.git] / kernel / cfg / toppers / builtin_function.cpp
1 /*
2  *  TOPPERS Software
3  *      Toyohashi Open Platform for Embedded Real-Time Systems
4  *
5  *  Copyright (C) 2007-2009 by TAKAGI Nobuhisa
6  * 
7  *  上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
8  *  ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9  *  変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
12  *      スコード中に含まれていること.
13  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
16  *      の無保証規定を掲載すること.
17  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
19  *      と.
20  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
22  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
23  *        報告すること.
24  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26  *      また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27  *      由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
28  *      免責すること.
29  * 
30  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32  *  に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33  *  アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
34  *  の責任を負わない.
35  * 
36  */
37 #include <cstdlib>
38 #include <cerrno>
39 #include <string>
40 #include <vector>
41 #include <utility>
42 #include <algorithm>
43 #include <ostream>
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>
51 #include <cstdio>
52
53 namespace toppers
54 {
55   namespace
56   {
57     typedef macro_processor::element element;
58     typedef macro_processor::var_t var_t;
59     typedef macro_processor::context context;
60
61     inline std::tr1::int64_t get_i( var_t const& var, context const* p_ctx )
62     {
63       return macro_processor::to_integer( var, p_ctx );
64     }
65     inline std::string get_s( var_t const& var, context const* p_ctx )
66     {
67       return macro_processor::to_string( var, p_ctx );
68     }
69
70   }
71
72   /*!
73     *  \brief  引数の個数チェック
74     *  \param[in]  line    行番号情報
75     *  \param[in]  arity   引数の個数
76     *  \param[in]  valid   期待している引数の個数
77     *  \param[in]  function_name 組み込み関数名
78     */
79   bool macro_processor::check_arity( text_line const& line, std::size_t arity, std::size_t valid, char const* function_name )
80   {
81     bool result = false;
82     if ( arity < valid )
83     {
84       error( line, _( "too few arguments for `%1%\'" ), function_name );
85     }
86     else if ( arity > valid )
87     {
88       error( line, _( "too many arguments for `%1%\'" ), function_name );
89     }
90     else
91     {
92       result = true;
93     }
94     return result;
95   }
96
97   /*!
98    *  \brief  変数ダンプのための<<演算子
99    *  \param[in,out]  ostr  出力ストリーム
100    *  \param[in]      arg   変数を参照するためのペア
101    *  \return         ostrを返す
102    *  \note 現在の実装では、arg.second は使用していない。
103    */
104   std::ostream& operator<<( std::ostream& ostr, std::pair< var_t const*, context const* > const& arg )
105   {
106     for ( var_t::const_iterator iter( arg.first->begin() ), last( arg.first->end() ); iter != last; ++iter )
107     {
108       if ( !iter->s.empty() )
109       {
110         ostr << iter->s;
111       }
112       else if ( iter->i )
113       {
114         ostr << iter->i.get();
115       }
116       if ( boost::next( iter ) != last )
117       {
118         ostr << ",";
119       }
120     }
121     return ostr;
122   }
123
124   /*!
125    *  \brief  順序リストの長さ
126    *  \param[in]  line      行番号
127    *  \param[in]  arg_list  マクロ実引数リスト
128    *  \param[in]  p_ctx     マクロコンテキスト
129    *  \retval     マクロ返却値
130    *  第1マクロ実引数として指定した順序付きリストの要素数を返す。
131    *  第1マクロ実引数が順序付きリストでない場合は1を返す。また、第1マクロ実引数が無効な変数の場合は0を返す。
132    */
133   var_t bf_length( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
134   {
135     element e;
136     if ( macro_processor::check_arity( line, arg_list.size(), 1, "LENGTH" ) )
137     {
138       std::tr1::int64_t size = arg_list.front().size();
139       e.i = size;
140     }
141     return var_t( 1, e );
142   }
143
144   /*!
145    *  \brief  文字列の一致判定
146    *  \param[in]  line      行番号
147    *  \param[in]  arg_list  マクロ実引数リスト
148    *  \param[in]  p_ctx     マクロコンテキスト
149    *  \retval     マクロ返却値
150    *  第1マクロ実引数と第2マクロ実引数を文字列として比較し、一致する場合は真を、そうでなければ偽を返す。
151    */
152   var_t bf_eq( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
153   {
154     element e;
155     if ( macro_processor::check_arity( line, arg_list.size(), 2, "EQ" ) )
156     {
157       e.i = get_s( arg_list[ 0 ], p_ctx ) == get_s( arg_list[ 1 ], p_ctx );
158     }
159     return var_t( 1, e );
160   }
161
162   /*!
163    *  \brief  代替値
164    *  \param[in]  line      行番号
165    *  \param[in]  arg_list  マクロ実引数リスト
166    *  \param[in]  p_ctx     マクロコンテキスト
167    *  \retval     マクロ返却値
168    *  第1マクロ実引数が無効な変数の場合は第2実引数を返す。その他は第1実引数を返す。
169    */
170   var_t bf_alt( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
171   {
172     element e;
173     if ( macro_processor::check_arity( line, arg_list.size(), 2, "ALT" ) )
174     {
175       if ( !arg_list[0].empty() )
176       {
177         return arg_list[ 0 ];
178       }
179       else
180       {
181         return arg_list[ 1 ];                
182       }
183     }
184     return var_t( 1, e );
185   }
186
187   /*!
188    *  \brief  順序リストの整列
189    *  \param[in]  line      行番号
190    *  \param[in]  arg_list  マクロ実引数リスト
191    *  \param[in]  p_ctx     マクロコンテキスト
192    *  \retval     マクロ返却値
193    *  第1マクロ実引数として与えた順序付きリストの各要素を、第2マクロ実引数の添え字とした場合の変数を評価し、
194    *  その評価結果に基づき昇順に整列する。
195    *
196    *  \code
197    *  $FOO[1] = 20$
198    *  $FOO[2] = 10$
199    *  $FOO[3] = 30$
200    *  $SORT({ 1,2,3 }, "FOO")$
201    *  → { 2,1,3 }
202    *  \endcode
203    */
204   var_t bf_sort( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
205   {
206     var_t result;
207     if ( macro_processor::check_arity( line, arg_list.size(), 2, "SORT" ) )
208     {
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;
212
213       for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter )
214       {
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() )
219         {
220           return var_t();
221         }
222         if ( !m_iter->second.empty() )
223         {
224           temp.push_back( std::make_pair( m_iter->second.front(), order ) );
225         }
226       }
227
228       std::stable_sort( temp.begin(), temp.end() );
229
230       for ( std::vector< std::pair< element, std::tr1::int64_t > >::const_iterator iter( temp.begin() ), last( temp.end() );
231             iter != last;
232             ++iter )
233       {
234         element e;
235         e.i = iter->second;
236         result.push_back( e );
237       }
238     }
239     return result;
240   }
241
242   /*!
243    *  \brief  環境変数の取得
244    *  \param[in]  line      行番号
245    *  \param[in]  arg_list  マクロ実引数リスト
246    *  \param[in]  p_ctx     マクロコンテキスト
247    *  \retval     マクロ返却値
248    *  第1マクロ実引数で指定した環境変数の値を返す。
249    */
250   var_t bf_environ( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
251   {
252     element e;
253     if ( macro_processor::check_arity( line, arg_list.size(), 1, "ENVIRON" ) )
254     {
255       std::string name = get_s( arg_list[ 0 ], p_ctx );
256       char const* env = std::getenv( name.c_str() );
257       if ( env == 0 )
258       {
259         return var_t();
260       }
261       e.s = env;
262       errno = 0;
263       char* endptr;
264       if ( std::tr1::int64_t value = std::strtol( env, &endptr, 0 ) )
265       {
266         if ( *endptr == '\0' && errno == 0 )
267         {
268           e.i = value;
269         }
270       }
271     }
272     return var_t( 1, e );
273   }
274
275   /*!
276    *  \brief  値の生成
277    *  \param[in]  line      行番号
278    *  \param[in]  arg_list  マクロ実引数リスト
279    *  \param[in]  p_ctx     マクロコンテキスト
280    *  \retval     マクロ返却値
281    *  第1マクロ実引数をテキスト、第2マクロ実引数を数値として、値を生成する。
282    */
283   var_t bf_value( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
284   {
285     element e;
286     if ( macro_processor::check_arity( line, arg_list.size(), 2, "VALUE" ) )
287     {
288       if ( !arg_list[0].empty() )
289       {
290         e.s = get_s( arg_list[ 0 ], p_ctx );
291       }
292       if ( !arg_list[1].empty() )
293       {
294         e.i = get_i( arg_list[ 1 ], p_ctx );
295       }
296     }
297     return var_t( 1, e );
298   }
299
300   /*!
301    *  \brief  文字列の連結
302    *  \param[in]  line      行番号
303    *  \param[in]  arg_list  マクロ実引数リスト
304    *  \param[in]  p_ctx     マクロコンテキスト
305    *  \retval     マクロ返却値
306    *  第1マクロ実引数と第2マクロ実引数を連結して新しい文字列を生成する。
307    */
308   var_t bf_concat( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
309   {
310     element e;
311     if ( macro_processor::check_arity( line, arg_list.size(), 2, "CAT" ) )
312     {
313       e.s = get_s( arg_list[ 0 ], p_ctx ) + get_s( arg_list[ 1 ], p_ctx );
314     }
315     return var_t( 1, e );
316   }
317
318   /*!
319    *  \brief  順序リストの終端に要素を追加
320    *  \param[in]  line      行番号
321    *  \param[in]  arg_list  マクロ実引数リスト
322    *  \param[in]  p_ctx     マクロコンテキスト
323    *  \retval     マクロ返却値
324    *  第1マクロ実引数と第2マクロ実引数を連結して新しい順序付きリストを生成する。
325    */
326   var_t bf_append( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
327   {
328     var_t result;
329     if ( macro_processor::check_arity( line, arg_list.size(), 2, "APPEND" ) )
330     {
331       result = arg_list[ 0 ];
332       result.insert( result.end(), arg_list[ 1 ].begin(), arg_list[1].end() );
333     }
334     return result;
335   }
336
337   /*!
338    *  \brief  順序リストの指定要素の参照
339    *  \param[in]  line      行番号
340    *  \param[in]  arg_list  マクロ実引数リスト
341    *  \param[in]  p_ctx     マクロコンテキスト
342    *  \retval     マクロ返却値
343    *  第1マクロ実引数で指定した順序リストの、第2マクロ実引数で指定した要素を返す。
344    */
345   var_t bf_at( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
346   {
347     element e;
348     if ( macro_processor::check_arity( line, arg_list.size(), 2, "CAT" ) )
349     {
350       try
351       {
352         e = arg_list[ 0 ].at( static_cast< std::vector< var_t >::size_type >( get_i( arg_list[1], p_ctx ) ) );
353       }
354       catch ( std::out_of_range& )
355       {
356         // 添え字が不正
357         // 特に何もしない → この時点で e が空値であることを期待
358       }
359     }
360     return var_t( 1, e );
361   }
362
363   /*!
364    *  \brief  テキストの翻訳
365    *  \param[in]  line      行番号
366    *  \param[in]  arg_list  マクロ実引数リスト
367    *  \param[in]  p_ctx     マクロコンテキスト
368    *  \retval     マクロ返却値
369    *  第1マクロ実引数で指定した文字列を翻訳する。
370    */
371   var_t bf_gettext( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
372   {
373     element e;
374     if ( macro_processor::check_arity( line, arg_list.size(), 1, "GETTEXT" ) )
375     {
376       std::string message = get_s( arg_list[ 0 ], p_ctx );
377       e.s = gettext( message );
378     }
379     return var_t( 1, e );
380   }
381
382   /*!
383    *  \brief  マクロ実引数の書式化
384    *  \param[in]  line      行番号
385    *  \param[in]  arg_list  マクロ実引数リスト
386    *  \param[in]  p_ctx     マクロコンテキスト
387    *  \retval     マクロ返却値
388    *  第1マクロ実引数で指定した初期化文字列によって、第2マクロ実引数以降を書式化する。
389    *  書式化文字列は、%nが使えないことを除き、printf関数のスーパーセットである。
390    *  正確な仕様は、boost::formatを参照のこと。
391    */
392   var_t bf_format( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
393   {
394     element e;
395     std::size_t arity = arg_list.size();
396     if ( arity < 1 )
397     {
398       error( line, _( "too few arguments for `%1%\'" ), "FORMAT" );
399     }
400     std::string format_str = get_s( arg_list[ 0 ], p_ctx );
401 #if 0
402     std::string debug_str = format_str;
403     if ( debug_str == "0x%08x" )
404       toppers::trace("%s", debug_str.c_str() );
405 #endif
406     boost::format fmt( format_str );
407     for ( std::size_t i = 1; i < arity; i++ )
408     {
409       std::pair< var_t const*, context const* > arg( &arg_list[i], p_ctx );
410       fmt % arg;
411     }
412         e.s = fmt.str();
413     return var_t( 1, e );
414   }
415
416   /*!
417    *  \brief  順序付きリスト内の探索
418    *  \param[in]  line      行番号
419    *  \param[in]  arg_list  マクロ実引数リスト
420    *  \param[in]  p_ctx     マクロコンテキスト
421    *  \retval     マクロ返却値
422    *  第1マクロ実引数で指定した順序付きリストに含まれる第2マクロ実引数で指定した値に等しい要素を、
423    *  先頭から順に探索する。
424    *  等しい要素が見つかればその要素へのインデックスを、そうでなければ空値を返す。
425    */
426   var_t bf_find( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
427   {
428     element e;
429     if ( macro_processor::check_arity( line, arg_list.size(), 2, "FIND" ) )
430     {
431       var_t list( arg_list[ 0 ] );
432       std::tr1::int64_t value( get_i( arg_list[ 1 ], p_ctx ) );
433
434       for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter )
435       {
436         if ( iter->i.get() == value ) // 発見!
437         {
438           e.i = iter - list.begin();  // iter は RandomAccessIterator
439           return var_t( 1, e );
440         }
441       }
442     }
443     return var_t();
444   }
445
446   /*!
447    *  \brief  範囲指定による順序付きリスト
448    *  \param[in]  line      行番号
449    *  \param[in]  arg_list  マクロ実引数リスト
450    *  \param[in]  p_ctx     マクロコンテキスト
451    *  \retval     マクロ返却値
452    *  第1マクロ実引数で最初の値を、第2マクロ実引数で最後の値を指定する。
453    *  { 最初の値, 最初の値 + 1, ... 最後の値 }
454    *  となる順序付きリストを生成する。
455    *  引数が正しくない場合は空値を返す。
456    */
457   var_t bf_range( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
458   {
459     var_t result;
460     if ( macro_processor::check_arity( line, arg_list.size(), 2, "RANGE" ) )
461     {
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 ) );
464
465       for ( ; arg1 <= arg2; ++arg1 )
466       {
467         element e;
468         e.i = arg1;
469         result.push_back( e );
470       }
471     }
472     return result;
473   }
474
475   /*!
476    *  \brief  全変数のダンプ
477    *  \param[in]  line      行番号
478    *  \param[in]  arg_list  マクロ実引数リスト
479    *  \param[in]  p_ctx     マクロコンテキスト
480    *  \retval     マクロ返却値
481    *  マクロ実引数を指定した場合、その文字列属性で指定したファイルにダンプした文字列を追記する。
482    *  ファイル名として、"stdout"を指定した場合は標準出力、"stderr"を指定した場合は標準エラーに出力する。
483    *  ファイル名を省略した場合は"stderr"を指定したものとして振舞う。
484    */
485   var_t bf_dump( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
486   {
487     std::size_t arity = arg_list.size();
488
489     if ( arity > 1 )
490     {
491       error( line, _( "too many arguments for `%1%\'" ), "DUMP" );
492     }
493
494     std::string dump_str;
495
496     // 全変数をなめる
497     for ( std::map< std::string, var_t >::const_iterator iter( p_ctx->var_map.begin() ), last( p_ctx->var_map.end() );
498           iter != last;
499           ++iter )
500     {
501       dump_str += "$" + iter->first + "$ = { ";
502       if ( !iter->second.empty() )
503       {
504         // 各変数の全要素
505         for ( var_t::const_iterator iter2( iter->second.begin() ), last2( iter->second.end() );
506               iter2 != last2;
507               ++iter2 )
508         {
509           dump_str += "\"" + iter2->s + "\"(";
510           if ( iter2->i ) // 値属性があれば...
511           {
512             dump_str += boost::lexical_cast< std::string >( *iter2->i );
513           }
514           dump_str += "), ";
515         }
516       }
517       dump_str += " }\n";
518     }
519
520     std::string filename( "stderr" );
521     if ( arity == 1 )
522     {
523       filename = get_s( arg_list[ 0 ], p_ctx );
524     }
525     if ( filename == "stdout" )
526     {
527       fputs( dump_str.c_str(), stdout );
528     }
529     else if ( filename == "stderr" )
530     {
531       fputs( dump_str.c_str(), stderr );
532     }
533     else
534     {
535       std::FILE* stream = std::fopen( filename.c_str(), "a" );
536       if ( stream != 0 )
537       {
538         fputs( dump_str.c_str(), stream );
539         std::fclose( stream );
540       }
541     }
542     element e;
543     return var_t( 1, e );
544   }
545
546   /*!
547    *  \brief  変数のトレース
548    *  \param[in]  line      行番号
549    *  \param[in]  arg_list  マクロ実引数リスト
550    *  \param[in]  p_ctx     マクロコンテキスト
551    *  \retval     マクロ返却値
552    *  第1マクロ実引数で指定した変数の内容をトレースする。
553    *  第2マクロ実引数を指定した場合、その文字列属性で指定したファイルにトレース内容を追記する。
554    *  ファイル名として、"stdout"を指定した場合は標準出力、"stderr"を指定した場合は標準エラーに出力する。
555    *  ファイル名を省略した場合は"stderr"を指定したものとして振舞う。
556    */
557   var_t bf_trace( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
558   {
559     std::size_t arity = arg_list.size();
560
561     if ( arity < 1 )
562     {
563       error( line, _( "too few arguments for `%1%\'" ), "TRACE" );
564     }
565     else if ( arity > 2 )
566     {
567       error( line, _( "too many arguments for `%1%\'" ), "TRACE" );
568     }
569
570     var_t value( arg_list[ 0 ] );
571
572     std::string trace_str = "{ ";
573     for ( var_t::const_iterator iter( value.begin() ), last( value.end() );
574           iter != last;
575           ++iter )
576     {
577       trace_str += "\"" + iter->s + "\"(";
578       if ( iter->i ) // 値属性があれば...
579       {
580         trace_str += boost::lexical_cast< std::string >( *iter->i ) + " as integer";
581       }
582       else if ( !iter->v.empty() )
583       {
584         trace_str += "\"" + boost::lexical_cast< std::string >( iter->v ) + "\" as string";
585       }
586       trace_str += "), ";
587     }
588     trace_str += " }\n";
589
590     std::string filename( "stderr" );
591     if ( arity == 2 )
592     {
593       filename = get_s( arg_list[ 1 ], p_ctx );
594     }
595     if ( filename == "stdout" )
596     {
597       fputs( trace_str.c_str(), stdout );
598     }
599     else if ( filename == "stderr" )
600     {
601       fputs( trace_str.c_str(), stderr );
602     }
603     else
604     {
605       std::FILE* stream = std::fopen( filename.c_str(), "a" );
606       if ( stream != 0 )
607       {
608         fputs( trace_str.c_str(), stream );
609         std::fclose( stream );
610       }
611     }
612
613     element e;
614     return var_t( 1, e );
615   }
616
617   /*!
618    *  \brief  文字列のエスケープ
619    *  \param[in]  line      行番号
620    *  \param[in]  arg_list  マクロ実引数リスト
621    *  \param[in]  p_ctx     マクロコンテキスト
622    *  \retval     マクロ返却値
623    */
624   var_t bf_escstr( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
625   {
626     element e;
627     if ( macro_processor::check_arity( line, arg_list.size(), 1, "ESCSTR" ) )
628     {
629       std::string str( get_s( arg_list[ 0 ], p_ctx ) );
630       e.s = quote_string( str );
631     }
632     return var_t( 1, e );
633   }
634
635   /*!
636    *  \brief  文字列のエスケープ解除
637    *  \param[in]  line      行番号
638    *  \param[in]  arg_list  マクロ実引数リスト
639    *  \param[in]  p_ctx     マクロコンテキスト
640    *  \retval     マクロ返却値
641    */
642   var_t bf_unescstr( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
643   {
644     element e;
645     if ( macro_processor::check_arity( line, arg_list.size(), 1, "UNESCSTR" ) )
646     {
647       std::string str( get_s( arg_list[ 0 ], p_ctx ) );
648       e.s = expand_quote( str );
649     }
650     return var_t( 1, e );
651   }
652
653   /*!
654    *  \brief  関数の呼び出し
655    *  \param[in]  line      行番号
656    *  \param[in]  arg_list  マクロ実引数リスト
657    *  \param[in]  p_ctx     マクロコンテキスト
658    *  \retval     マクロ返却値
659    */
660   var_t bf_call( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
661   {
662     return macro_processor::call_user_function( line, arg_list, p_ctx );
663   }
664
665   namespace
666   {
667     struct bf_functor : std::binary_function< element const&, element const&, bool >
668     {
669     public:
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 )
672       {
673       }
674       bool operator()( element const& lhs, element const& rhs )
675       {
676         std::vector< var_t > arg_list;
677         arg_list.reserve( 3 );
678
679         element e;
680         e.s = func_name_;
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 );
686
687         var_t r = bf_call( line_, arg_list, p_ctx_ );
688         bool result = 0;
689         if ( !r.empty() )
690         {
691                         int retval = static_cast< int >( *r.front().i );
692           result = ( *r.front().i < 0 );
693         }
694         return result;
695       }
696     private:
697       std::string func_name_;
698       context* p_ctx_;
699       text_line line_;
700     };
701   }
702
703   /*!
704    *  \brief  ソート
705    *  \param[in]  line      行番号
706    *  \param[in]  arg_list  マクロ実引数リスト
707    *  \param[in]  p_ctx     マクロコンテキスト
708    *  \retval     マクロ返却値
709    */
710   var_t bf_lsort( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
711   {
712     if ( macro_processor::check_arity( line, arg_list.size(), 2, "LSORT" ) )
713     {
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 ) );
717       return temp;
718     }
719     element e;
720     return var_t( 1, e );
721   }
722
723   /*!
724    *  \brief  関数かどうかの判別
725    *  \param[in]  line      行番号
726    *  \param[in]  arg_list  マクロ実引数リスト
727    *  \param[in]  p_ctx     マクロコンテキスト
728    *  \retval     マクロ返却値
729    */
730   var_t bf_isfunction( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
731   {
732     element e;
733     if ( macro_processor::check_arity( line, arg_list.size(), 1, "ISFUNCTION" ) )
734     {
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() )
737       {
738         e.i = 1;
739       }
740       else
741       {
742         e.i = 0;
743       }
744     }
745     return var_t( 1, e );
746   }
747
748   /*!
749    *  \brief  順序付きリストの並びを逆にする
750    *  \param[in]  line      行番号
751    *  \param[in]  arg_list  マクロ実引数リスト
752    *  \param[in]  p_ctx     マクロコンテキスト
753    *  \retval     マクロ返却値
754    */
755   var_t bf_reverse( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
756   {
757     var_t result;
758     if ( macro_processor::check_arity( line, arg_list.size(), 1, "REVERSE" ) )
759     {
760       result = arg_list[ 0 ];
761       std::reverse(result.begin(), result.end());
762     }
763     return result;
764   }
765
766   /*!
767    *  \brief  何もしない組み込み関数
768    *  \param[in]  line      行番号
769    *  \param[in]  arg_list  マクロ実引数リスト
770    *  \param[in]  p_ctx     マクロコンテキスト
771    *  \retval     マクロ返却値
772    *  この組み込み関数は何も行わない。また、マクロ実引数のチェックも行わない。
773    *  NOOP関数は常に "" を返す。
774    *  \note       空値を返さないのは、$NOOP()$のような使い方をしたときでも不正な参照が起こらないようにするため。
775    */
776   var_t bf_noop( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
777   {
778     element e;
779     return var_t( 1, e );
780   }
781
782   macro_processor::func_t const macro_processor::builtin_function_table[] =
783   {
784     { "LENGTH", bf_length },
785     { "EQ", bf_eq },
786     { "ALT", bf_alt },
787     { "SORT", bf_sort },
788     { "ENVIRON", bf_environ },
789     { "VALUE", bf_value },
790     { "CONCAT", bf_concat },
791     { "APPEND", bf_append },
792     { "AT", bf_at },
793     { "GETTEXT", bf_gettext },
794     { "_", bf_gettext },  // GETTEXTのシノニム
795     { "FORMAT", bf_format },
796     { "FIND", bf_find },
797     { "RANGE", bf_range },
798     { "DUMP", bf_dump },
799     { "TRACE", bf_trace },
800     { "ESCSTR", bf_escstr },
801     { "UNESCSTR", bf_unescstr },
802     { "CALL", bf_call },
803     { "LSORT", bf_lsort },
804     { "ISFUNCTION", bf_isfunction },
805     { "REVERSE", bf_reverse },
806     { "NOOP", bf_noop },
807     { "", 0 },
808   };
809
810 }