source: cfg_itronx+oil_gcc/toppers/builtin_function.cpp@ 165

Last change on this file since 165 was 54, checked in by ertl-ishikawa, 12 years ago

cfg+oil対応コンフィギュレータを追加

File size: 27.3 KB
Line 
1/*
2 * TOPPERS Software
3 * Toyohashi Open Platform for Embedded Real-Time Systems
4 *
5 * Copyright (C) 2007-2011 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 <cstdio>
38#include <cstdlib>
39#include <cerrno>
40#include <string>
41#include <vector>
42#include <utility>
43#include <algorithm>
44#include <iostream>
45#include "toppers/macro_processor.hpp"
46#include "toppers/diagnostics.hpp"
47#include "toppers/gettext.hpp"
48#include "toppers/cpp.hpp"
49#include <boost/format.hpp>
50#include <boost/utility.hpp>
51#include <boost/lexical_cast.hpp>
52#include <boost/xpressive/xpressive.hpp>
53
54namespace toppers
55{
56 namespace
57 {
58 typedef macro_processor::element element;
59 typedef macro_processor::var_t var_t;
60 typedef macro_processor::context context;
61
62 inline std::tr1::int64_t get_i( var_t const& var, context const* p_ctx )
63 {
64 return macro_processor::to_integer( var, p_ctx );
65 }
66 inline std::string get_s( var_t const& var, context const* p_ctx )
67 {
68 return macro_processor::to_string( var, p_ctx );
69 }
70
71 }
72
73 /*!
74 * \brief 引数の個数チェック
75 * \param[in] line 行番号情報
76 * \param[in] arity 引数の個数
77 * \param[in] valid 期待している引数の個数
78 * \param[in] function_name 組み込み関数名
79 */
80 bool macro_processor::check_arity( text_line const& line, std::size_t arity, std::size_t valid, char const* function_name )
81 {
82 bool result = false;
83 if ( arity < valid )
84 {
85 error( line, _( "too few arguments for `%1%\'" ), function_name );
86 }
87 else if ( arity > valid )
88 {
89 error( line, _( "too many arguments for `%1%\'" ), function_name );
90 }
91 else
92 {
93 result = true;
94 }
95 return result;
96 }
97
98 /*!
99 * \brief 変数ダンプのための<<演算子
100 * \param[in,out] ostr 出力ストリーム
101 * \param[in] arg 変数を参照するためのペア
102 * \return ostrを返す
103 * \note 現在の実装では、arg.second は使用していない。
104 */
105 std::ostream& operator<<( std::ostream& ostr, std::pair< var_t const*, context const* > const& arg )
106 {
107 for ( var_t::const_iterator iter( arg.first->begin() ), last( arg.first->end() ); iter != last; ++iter )
108 {
109 if ( !iter->s.empty() )
110 {
111 ostr << iter->s;
112 }
113 else if ( iter->i )
114 {
115 ostr << iter->i.get();
116 }
117 if ( boost::next( iter ) != last )
118 {
119 ostr << ",";
120 }
121 }
122 return ostr;
123 }
124
125 /*!
126 * \brief 順序リストの長さ
127 * \param[in] line 行番号
128 * \param[in] arg_list マクロ実引数リスト
129 * \param[in] p_ctx マクロコンテキスト
130 * \retval マクロ返却値
131 * 第1マクロ実引数として指定した順序付きリストの要素数を返す。
132 * 第1マクロ実引数が順序付きリストでない場合は1を返す。また、第1マクロ実引数が無効な変数の場合は0を返す。
133 */
134 var_t bf_length( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
135 {
136 element e;
137 if ( macro_processor::check_arity( line, arg_list.size(), 1, "LENGTH" ) )
138 {
139 std::tr1::int64_t size = arg_list.front().size();
140 e.i = size;
141 }
142 return var_t( 1, e );
143 }
144
145 /*!
146 * \brief 文字列の一致判定
147 * \param[in] line 行番号
148 * \param[in] arg_list マクロ実引数リスト
149 * \param[in] p_ctx マクロコンテキスト
150 * \retval マクロ返却値
151 * 第1マクロ実引数と第2マクロ実引数を文字列として比較し、一致する場合は真を、そうでなければ偽を返す。
152 */
153 var_t bf_eq( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
154 {
155 element e;
156 if ( macro_processor::check_arity( line, arg_list.size(), 2, "EQ" ) )
157 {
158 e.i = get_s( arg_list[ 0 ], p_ctx ) == get_s( arg_list[ 1 ], p_ctx );
159 }
160 return var_t( 1, e );
161 }
162
163 /*!
164 * \brief 代替値
165 * \param[in] line 行番号
166 * \param[in] arg_list マクロ実引数リスト
167 * \param[in] p_ctx マクロコンテキスト
168 * \retval マクロ返却値
169 * 第1マクロ実引数が無効な変数の場合は第2実引数を返す。その他は第1実引数を返す。
170 */
171 var_t bf_alt( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
172 {
173 element e;
174 if ( macro_processor::check_arity( line, arg_list.size(), 2, "ALT" ) )
175 {
176 if ( !arg_list[0].empty() )
177 {
178 return arg_list[ 0 ];
179 }
180 else
181 {
182 return arg_list[ 1 ];
183 }
184 }
185 return var_t( 1, e );
186 }
187
188 /*!
189 * \brief 順序リストの整列
190 * \param[in] line 行番号
191 * \param[in] arg_list マクロ実引数リスト
192 * \param[in] p_ctx マクロコンテキスト
193 * \retval マクロ返却値
194 * 第1マクロ実引数として与えた順序付きリストの各要素を、第2マクロ実引数の添え字とした場合の変数を評価し、
195 * その評価結果に基づき昇順に整列する。
196 *
197 * \example
198 * $FOO[1] = 20$
199 * $FOO[2] = 10$
200 * $FOO[3] = 30$
201 * $SORT({ 1,2,3 }, "FOO")$
202 * → { 2,1,3 }
203 * \endexample
204 */
205 var_t bf_sort( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
206 {
207 var_t result;
208 if ( macro_processor::check_arity( line, arg_list.size(), 2, "SORT" ) )
209 {
210 var_t list( arg_list[ 0 ] );
211 std::string field( get_s( arg_list[ 1 ], p_ctx ) );
212 std::vector< std::pair< element, std::tr1::int64_t > > temp;
213
214 for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter )
215 {
216 std::tr1::int64_t order = iter->i.get();
217 std::string name( ( boost::format( "%s[%d]" ) % field % order ).str() );
218 std::map< std::string, var_t >::const_iterator m_iter( p_ctx->var_map.find( name ) );
219 if ( m_iter == p_ctx->var_map.end() )
220 {
221 return var_t();
222 }
223 if ( !m_iter->second.empty() )
224 {
225 temp.push_back( std::make_pair( m_iter->second.front(), order ) );
226 }
227 }
228
229 std::stable_sort( temp.begin(), temp.end() );
230
231 for ( std::vector< std::pair< element, std::tr1::int64_t > >::const_iterator iter( temp.begin() ), last( temp.end() );
232 iter != last;
233 ++iter )
234 {
235 element e;
236 e.i = iter->second;
237 result.push_back( e );
238 }
239 }
240 return result;
241 }
242
243 /*!
244 * \brief 環境変数の取得
245 * \param[in] line 行番号
246 * \param[in] arg_list マクロ実引数リスト
247 * \param[in] p_ctx マクロコンテキスト
248 * \retval マクロ返却値
249 * 第1マクロ実引数で指定した環境変数の値を返す。
250 */
251 var_t bf_environ( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
252 {
253 element e;
254 if ( macro_processor::check_arity( line, arg_list.size(), 1, "ENVIRON" ) )
255 {
256 std::string name = get_s( arg_list[ 0 ], p_ctx );
257 char const* env = std::getenv( name.c_str() );
258 if ( env == 0 )
259 {
260 return var_t();
261 }
262 e.s = env;
263 errno = 0;
264 char* endptr;
265 if ( std::tr1::int64_t value = std::strtol( env, &endptr, 0 ) )
266 {
267 if ( *endptr == '\0' && errno == 0 )
268 {
269 e.i = value;
270 }
271 }
272 }
273 return var_t( 1, e );
274 }
275
276 /*!
277 * \brief 値の生成
278 * \param[in] line 行番号
279 * \param[in] arg_list マクロ実引数リスト
280 * \param[in] p_ctx マクロコンテキスト
281 * \retval マクロ返却値
282 * 第1マクロ実引数をテキスト、第2マクロ実引数を数値として、値を生成する。
283 */
284 var_t bf_value( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
285 {
286 element e;
287 if ( macro_processor::check_arity( line, arg_list.size(), 2, "VALUE" ) )
288 {
289 if ( !arg_list[0].empty() )
290 {
291 e.s = get_s( arg_list[ 0 ], p_ctx );
292 }
293 if ( !arg_list[1].empty() )
294 {
295 e.i = get_i( arg_list[ 1 ], p_ctx );
296 }
297 }
298 return var_t( 1, e );
299 }
300
301 /*!
302 * \brief 文字列の連結
303 * \param[in] line 行番号
304 * \param[in] arg_list マクロ実引数リスト
305 * \param[in] p_ctx マクロコンテキスト
306 * \retval マクロ返却値
307 * 第1マクロ実引数と第2マクロ実引数を連結して新しい文字列を生成する。
308 */
309 var_t bf_concat( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
310 {
311 element e;
312 if ( macro_processor::check_arity( line, arg_list.size(), 2, "CONCAT" ) )
313 {
314 e.s = get_s( arg_list[ 0 ], p_ctx ) + get_s( arg_list[ 1 ], p_ctx );
315 }
316 return var_t( 1, e );
317 }
318
319 /*!
320 * \brief 順序リストの終端に要素を追加
321 * \param[in] line 行番号
322 * \param[in] arg_list マクロ実引数リスト
323 * \param[in] p_ctx マクロコンテキスト
324 * \retval マクロ返却値
325 * 第1マクロ実引数と第2マクロ実引数以降を連結して新しい順序付きリストを生成する。
326 */
327 var_t bf_append( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
328 {
329 var_t result;
330 var_t::size_type const n = arg_list.size();
331 if ( n < 2 )
332 {
333 error( line, _( "too few arguments for `%1%\'" ), "APPEND" );
334 }
335 else
336 {
337 result = arg_list[ 0 ];
338 for ( var_t::size_type i = 1; i < n; i++)
339 {
340 result.insert( result.end(), arg_list[ i ].begin(), arg_list[ i ].end() );
341 }
342 }
343 return result;
344 }
345
346 /*!
347 * \brief 順序リストの指定要素の参照
348 * \param[in] line 行番号
349 * \param[in] arg_list マクロ実引数リスト
350 * \param[in] p_ctx マクロコンテキスト
351 * \retval マクロ返却値
352 * 第1マクロ実引数で指定した順序リストの、第2マクロ実引数で指定した要素を返す。
353 */
354 var_t bf_at( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
355 {
356 element e;
357 if ( macro_processor::check_arity( line, arg_list.size(), 2, "AT" ) )
358 {
359 try
360 {
361 e = arg_list[ 0 ].at( static_cast< std::vector< var_t >::size_type >( get_i( arg_list[1], p_ctx ) ) );
362 }
363 catch ( std::out_of_range& )
364 {
365 // 添え字が不正
366 // 特に何もしない → この時点で e が空値であることを期待
367 }
368 }
369 return var_t( 1, e );
370 }
371
372 /*!
373 * \brief テキストの翻訳
374 * \param[in] line 行番号
375 * \param[in] arg_list マクロ実引数リスト
376 * \param[in] p_ctx マクロコンテキスト
377 * \retval マクロ返却値
378 * 第1マクロ実引数で指定した文字列を翻訳する。
379 */
380 var_t bf_gettext( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
381 {
382 element e;
383 if ( macro_processor::check_arity( line, arg_list.size(), 1, "GETTEXT" ) )
384 {
385 std::string message = get_s( arg_list[ 0 ], p_ctx );
386 e.s = gettext( message );
387 }
388 return var_t( 1, e );
389 }
390
391 /*!
392 * \brief マクロ実引数の書式化
393 * \param[in] line 行番号
394 * \param[in] arg_list マクロ実引数リスト
395 * \param[in] p_ctx マクロコンテキスト
396 * \retval マクロ返却値
397 * 第1マクロ実引数で指定した初期化文字列によって、第2マクロ実引数以降を書式化する。
398 * 書式化文字列は、%nが使えないことを除き、printf関数のスーパーセットである。
399 * 正確な仕様は、boost::formatを参照のこと。
400 */
401 var_t bf_format( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
402 {
403 element e;
404 std::size_t arity = arg_list.size();
405 if ( arity < 1 )
406 {
407 error( line, _( "too few arguments for `%1%\'" ), "FORMAT" );
408 }
409 std::string format_str = get_s( arg_list[ 0 ], p_ctx );
410#if 0
411 std::string debug_str = format_str;
412 if ( debug_str == "0x%08x" )
413 toppers::trace("%s", debug_str.c_str() );
414#endif
415 boost::format fmt( format_str );
416 for ( std::size_t i = 1; i < arity; i++ )
417 {
418 std::pair< var_t const*, context const* > arg( &arg_list[i], p_ctx );
419 fmt % arg;
420 }
421 e.s = fmt.str();
422 return var_t( 1, e );
423 }
424
425 /*!
426 * \brief 順序付きリスト内の探索
427 * \param[in] line 行番号
428 * \param[in] arg_list マクロ実引数リスト
429 * \param[in] p_ctx マクロコンテキスト
430 * \retval マクロ返却値
431 * 第1マクロ実引数で指定した順序付きリストに含まれる第2マクロ実引数で指定した値に等しい要素を、
432 * 先頭から順に探索する。
433 * 等しい要素が見つかればその要素へのインデックスを、そうでなければ空値を返す。
434 */
435 var_t bf_find( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
436 {
437 element e;
438 if ( macro_processor::check_arity( line, arg_list.size(), 2, "FIND" ) )
439 {
440 var_t list( arg_list[ 0 ] );
441
442 if ( !arg_list[ 1 ].empty() )
443 {
444 element key( arg_list[ 1 ].front() );
445
446 if ( !key.i ) // 整数値が設定されていなければ...
447 {
448 std::string value( key.s );
449
450 for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter )
451 {
452 if ( iter->s == value ) // 発見!
453 {
454 e.i = iter - list.begin(); // iter は RandomAccessIterator
455 return var_t( 1, e );
456 }
457 }
458 }
459 else
460 {
461 std::tr1::int64_t value( key.i.get() );
462
463 for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter )
464 {
465 if ( iter->i && iter->i.get() == value ) // 発見!
466 {
467 e.i = iter - list.begin(); // iter は RandomAccessIterator
468 return var_t( 1, e );
469 }
470 }
471 }
472 }
473 }
474 return var_t();
475 }
476
477 /*!
478 * \brief 範囲指定による順序付きリスト
479 * \param[in] line 行番号
480 * \param[in] arg_list マクロ実引数リスト
481 * \param[in] p_ctx マクロコンテキスト
482 * \retval マクロ返却値
483 * 第1マクロ実引数で最初の値を、第2マクロ実引数で最後の値を指定する。
484 * { 最初の値, 最初の値 + 1, ... 最後の値 }
485 * となる順序付きリストを生成する。
486 * 引数が正しくない場合は空値を返す。
487 */
488 var_t bf_range( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
489 {
490 var_t result;
491 if ( macro_processor::check_arity( line, arg_list.size(), 2, "RANGE" ) )
492 {
493 std::tr1::int64_t arg1( get_i( arg_list[ 0 ], p_ctx ) );
494 std::tr1::int64_t arg2( get_i( arg_list[ 1 ], p_ctx ) );
495
496 for ( ; arg1 <= arg2; ++arg1 )
497 {
498 element e;
499 e.i = arg1;
500 result.push_back( e );
501 }
502 }
503 return result;
504 }
505
506 /*!
507 * \brief 全変数のダンプ
508 * \param[in] line 行番号
509 * \param[in] arg_list マクロ実引数リスト
510 * \param[in] p_ctx マクロコンテキスト
511 * \retval マクロ返却値
512 * マクロ実引数を指定した場合、その文字列属性で指定したファイルにダンプした文字列を追記する。
513 * ファイル名として、"stdout"を指定した場合は標準出力、"stderr"を指定した場合は標準エラーに出力する。
514 * ファイル名を省略した場合は"stderr"を指定したものとして振舞う。
515 */
516 var_t bf_dump( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
517 {
518 std::size_t arity = arg_list.size();
519
520 if ( arity > 1 )
521 {
522 error( line, _( "too many arguments for `%1%\'" ), "DUMP" );
523 }
524
525 std::string dump_str;
526
527 // 全変数をなめる
528 for ( std::map< std::string, var_t >::const_iterator iter( p_ctx->var_map.begin() ), last( p_ctx->var_map.end() );
529 iter != last;
530 ++iter )
531 {
532 dump_str += "$" + iter->first + "$ = { ";
533 if ( !iter->second.empty() )
534 {
535 // 各変数の全要素
536 for ( var_t::const_iterator iter2( iter->second.begin() ), last2( iter->second.end() );
537 iter2 != last2;
538 ++iter2 )
539 {
540 dump_str += "\"" + iter2->s + "\"(";
541 if ( iter2->i ) // 値属性があれば...
542 {
543 dump_str += boost::lexical_cast< std::string >( *iter2->i );
544 }
545 dump_str += "), ";
546 }
547 }
548 dump_str += " }\n";
549 }
550
551 std::string filename( "stderr" );
552 if ( arity == 1 )
553 {
554 filename = get_s( arg_list[ 0 ], p_ctx );
555 }
556 if ( filename == "stdout" )
557 {
558 std::fputs( dump_str.c_str(), stdout );
559 std::fflush( stdout );
560 }
561 else if ( filename == "stderr" )
562 {
563 std::fputs( dump_str.c_str(), stderr );
564 std::fflush( stderr );
565 }
566 else
567 {
568 std::FILE* stream = std::fopen( filename.c_str(), "a" );
569 if ( stream != 0 )
570 {
571 std::fputs( dump_str.c_str(), stream );
572 std::fclose( stream );
573 }
574 }
575 element e;
576 return var_t( 1, e );
577 }
578
579 /*!
580 * \brief 変数のトレース
581 * \param[in] line 行番号
582 * \param[in] arg_list マクロ実引数リスト
583 * \param[in] p_ctx マクロコンテキスト
584 * \retval マクロ返却値
585 * 第1マクロ実引数で指定した変数の内容をトレースする。
586 * 第2マクロ実引数を指定した場合、その文字列属性で指定したファイルにトレース内容を追記する。
587 * ファイル名として、"stdout"を指定した場合は標準出力、"stderr"を指定した場合は標準エラーに出力する。
588 * ファイル名を省略した場合は"stderr"を指定したものとして振舞う。
589 */
590 var_t bf_trace( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
591 {
592 std::size_t arity = arg_list.size();
593
594 if ( arity < 1 )
595 {
596 error( line, _( "too few arguments for `%1%\'" ), "TRACE" );
597 }
598 else if ( arity > 2 )
599 {
600 error( line, _( "too many arguments for `%1%\'" ), "TRACE" );
601 }
602
603 var_t value( arg_list[ 0 ] );
604
605 std::string trace_str = "{ ";
606 for ( var_t::const_iterator iter( value.begin() ), last( value.end() );
607 iter != last;
608 ++iter )
609 {
610 trace_str += "\"" + iter->s + "\"(";
611 if ( iter->i ) // 値属性があれば...
612 {
613 trace_str += boost::lexical_cast< std::string >( *iter->i ) + " as integer";
614 }
615 else if ( !iter->v.empty() )
616 {
617 trace_str += "\"" + boost::lexical_cast< std::string >( iter->v ) + "\" as string";
618 }
619 trace_str += "), ";
620 }
621 trace_str += " }\n";
622
623 std::string filename( "stderr" );
624 if ( arity == 2 )
625 {
626 filename = get_s( arg_list[ 1 ], p_ctx );
627 }
628 if ( filename == "stdout" )
629 {
630 std::fputs( trace_str.c_str(), stdout );
631 std::fflush( stdout );
632 }
633 else if ( filename == "stderr" )
634 {
635 std::fputs( trace_str.c_str(), stderr );
636 std::fflush( stderr );
637 }
638 else
639 {
640 std::FILE* stream = std::fopen( filename.c_str(), "a" );
641 if ( stream != 0 )
642 {
643 std::fputs( trace_str.c_str(), stream );
644 std::fclose( stream );
645 }
646 }
647
648 element e;
649 return var_t( 1, e );
650 }
651
652 /*!
653 * \brief 文字列のエスケープ
654 * \param[in] line 行番号
655 * \param[in] arg_list マクロ実引数リスト
656 * \param[in] p_ctx マクロコンテキスト
657 * \retval マクロ返却値
658 */
659 var_t bf_escstr( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
660 {
661 element e;
662 if ( macro_processor::check_arity( line, arg_list.size(), 1, "ESCSTR" ) )
663 {
664 std::string str( get_s( arg_list[ 0 ], p_ctx ) );
665 e.s = quote_string( str );
666 }
667 return var_t( 1, e );
668 }
669
670 /*!
671 * \brief 文字列のエスケープ解除
672 * \param[in] line 行番号
673 * \param[in] arg_list マクロ実引数リスト
674 * \param[in] p_ctx マクロコンテキスト
675 * \retval マクロ返却値
676 */
677 var_t bf_unescstr( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
678 {
679 element e;
680 if ( macro_processor::check_arity( line, arg_list.size(), 1, "UNESCSTR" ) )
681 {
682 std::string str( get_s( arg_list[ 0 ], p_ctx ) );
683 if ( !str.empty() )
684 {
685 e.s = expand_quote( str );
686 }
687 }
688 return var_t( 1, e );
689 }
690
691 /*!
692 * \brief 関数の呼び出し
693 * \param[in] line 行番号
694 * \param[in] arg_list マクロ実引数リスト
695 * \param[in] p_ctx マクロコンテキスト
696 * \retval マクロ返却値
697 */
698 var_t bf_call( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
699 {
700 return macro_processor::call_user_function( line, arg_list, p_ctx );
701 }
702
703 namespace
704 {
705 struct bf_functor : std::binary_function< element const&, element const&, bool >
706 {
707 public:
708 bf_functor( text_line const& line, std::string const& func_name, context* p_ctx )
709 : line_( line ), func_name_( func_name ), p_ctx_( p_ctx )
710 {
711 }
712 bool operator()( element const& lhs, element const& rhs )
713 {
714 std::vector< var_t > arg_list;
715 arg_list.reserve( 3 );
716
717 element e;
718 e.s = func_name_;
719 arg_list.push_back( var_t( 1, e ) );
720 arg_list.push_back( var_t( 1, lhs ) );
721 arg_list.push_back( var_t( 1, rhs ) );
722 int arg1 = static_cast< int >( *lhs.i );
723 int arg2 = static_cast< int >( *rhs.i );
724
725 var_t r = bf_call( line_, arg_list, p_ctx_ );
726 bool result = 0;
727 if ( !r.empty() )
728 {
729 int retval = static_cast< int >( *r.front().i );
730 result = ( *r.front().i < 0 );
731 }
732 return result;
733 }
734 private:
735 std::string func_name_;
736 context* p_ctx_;
737 text_line line_;
738 };
739 }
740
741 /*!
742 * \brief ソート
743 * \param[in] line 行番号
744 * \param[in] arg_list マクロ実引数リスト
745 * \param[in] p_ctx マクロコンテキスト
746 * \retval マクロ返却値
747 */
748 var_t bf_lsort( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
749 {
750 if ( macro_processor::check_arity( line, arg_list.size(), 2, "LSORT" ) )
751 {
752 var_t temp( arg_list[ 0 ] );
753 std::string compare( arg_list[ 1 ].front().s );
754 std::stable_sort( temp.begin(), temp.end(), bf_functor( line, compare, p_ctx ) );
755 return temp;
756 }
757 element e;
758 return var_t( 1, e );
759 }
760
761 /*!
762 * \brief 関数かどうかの判別
763 * \param[in] line 行番号
764 * \param[in] arg_list マクロ実引数リスト
765 * \param[in] p_ctx マクロコンテキスト
766 * \retval マクロ返却値
767 */
768 var_t bf_isfunction( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
769 {
770 element e;
771 if ( macro_processor::check_arity( line, arg_list.size(), 1, "ISFUNCTION" ) )
772 {
773 std::string func_name( get_s( arg_list[ 0 ], p_ctx ) );
774 if ( p_ctx->func_map.find( func_name ) != p_ctx->func_map.end() )
775 {
776 e.i = 1;
777 }
778 else
779 {
780 e.i = 0;
781 }
782 }
783 return var_t( 1, e );
784 }
785
786 /*!
787 * \brief 順序付きリストの並びを逆にする
788 * \param[in] line 行番号
789 * \param[in] arg_list マクロ実引数リスト
790 * \param[in] p_ctx マクロコンテキスト
791 * \retval マクロ返却値
792 */
793 var_t bf_reverse( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
794 {
795 var_t result;
796 if ( macro_processor::check_arity( line, arg_list.size(), 1, "REVERSE" ) )
797 {
798 result = arg_list[ 0 ];
799 std::reverse(result.begin(), result.end());
800 }
801 return result;
802 }
803
804 /*!
805 * \brief 正規表現を用いた置換
806 * \param[in] line 行番号
807 * \param[in] arg_list マクロ実引数リスト
808 * \param[in] p_ctx マクロコンテキスト
809 * \retval マクロ返却値
810 * 第1マクロ実引数で指定した文字列のうち、第2マクロ実引数で指定した正規表現にマッチする箇所を第3マクロ実引数の内容で置換する。
811 * 正規表現はECMAScript互換とする。
812 */
813 var_t bf_regex_replace( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
814 {
815 element e;
816 if ( macro_processor::check_arity( line, arg_list.size(), 3, "REGEX_REPLACE" ) )
817 {
818 e.s = boost::xpressive::regex_replace( get_s( arg_list[ 0 ], p_ctx ),
819 boost::xpressive::sregex::compile( get_s( arg_list[ 1 ], p_ctx ) ),
820 get_s( arg_list[ 2 ], p_ctx ) );
821 }
822 return var_t( 1, e );
823 }
824
825 /*!
826 * \brief 配列の全削除
827 * \param[in] line 行番号
828 * \param[in] arg_list マクロ実引数リスト
829 * \param[in] p_ctx マクロコンテキスト
830 * \retval マクロ返却値
831 * 第1マクロ実引数で指定した名前の配列を全削除する。
832 */
833 var_t bf_clean( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
834 {
835 element e;
836 if ( macro_processor::check_arity( line, arg_list.size(), 1, "CLEAN" ) )
837 {
838 std::string name = get_s( arg_list[ 0 ], p_ctx ) + "[";
839 for ( std::map< std::string, var_t >::iterator it = p_ctx->var_map.lower_bound( name );
840 it != p_ctx->var_map.end();
841 ++it )
842 {
843 if ( std::strncmp( it->first.c_str(), name.c_str(), name.size() ) != 0 )
844 break;
845 it->second = var_t();
846 }
847 }
848 return var_t( 1, e );
849 }
850
851 /*!
852 * \brief マクロプロセッサの終了
853 * \param[in] line 行番号
854 * \param[in] arg_list マクロ実引数リスト
855 * \param[in] p_ctx マクロコンテキスト
856 * \retval マクロ返却値
857 * マクロプロセッサを終了する。
858 */
859 var_t bf_die( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
860 {
861 element e;
862 if ( macro_processor::check_arity( line, arg_list.size(), 0, "DIE" ) )
863 {
864 throw macro_processor::die_terminate();
865 }
866 return var_t( 1, e );
867 }
868
869 /*!
870 * \brief 何もしない組み込み関数
871 * \param[in] line 行番号
872 * \param[in] arg_list マクロ実引数リスト
873 * \param[in] p_ctx マクロコンテキスト
874 * \retval マクロ返却値
875 * この組み込み関数は何も行わない。また、マクロ実引数のチェックも行わない。
876 * NOOP関数は常に "" を返す。
877 * \note 空値を返さないのは、$NOOP()$のような使い方をしたときでも不正な参照が起こらないようにするため。
878 */
879 var_t bf_noop( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx )
880 {
881 element e;
882 return var_t( 1, e );
883 }
884
885 macro_processor::func_t const macro_processor::builtin_function_table[] =
886 {
887 { "LENGTH", bf_length },
888 { "EQ", bf_eq },
889 { "ALT", bf_alt },
890 { "SORT", bf_sort },
891 { "ENVIRON", bf_environ },
892 { "VALUE", bf_value },
893 { "CONCAT", bf_concat },
894 { "APPEND", bf_append },
895 { "AT", bf_at },
896 { "GETTEXT", bf_gettext },
897 { "_", bf_gettext }, // GETTEXTのシノニム
898 { "FORMAT", bf_format },
899 { "FIND", bf_find },
900 { "RANGE", bf_range },
901 { "DUMP", bf_dump },
902 { "TRACE", bf_trace },
903 { "ESCSTR", bf_escstr },
904 { "UNESCSTR", bf_unescstr },
905 { "CALL", bf_call },
906 { "LSORT", bf_lsort },
907 { "ISFUNCTION", bf_isfunction },
908 { "REVERSE", bf_reverse },
909 { "REGEX_REPLACE", bf_regex_replace },
910 { "CLEAN", bf_clean },
911 { "DIE", bf_die },
912 { "NOOP", bf_noop },
913 { "", 0 },
914 };
915
916}
Note: See TracBrowser for help on using the repository browser.