カンマ演算子も使えるようにする
実はカンマ(,)も演算子です
このカンマ演算子を使えるようにしてみましょう
仕組み
カンマ演算子も使えるようにしたパーサが処理すべき式は必ず次のような形式になっています
完結式 ::= 部分式_comma
部分式_comma ::= 部分式_add_sub 部分式_comma_
部分式_comma_ ::= 演算子_comma 部分式_add_sub 部分式_comma_
演算子_comma ::= ,
部分式_add_sub ::= 部分式_mul_div_mod 部分式_add_sub_
部分式_add_sub_ ::= 演算子_add_sub 部分式_mul_div_mod 部分式_add_sub
演算子_add_sub ::= + あるいは −
部分式_mul_div_mod ::= 定数式 部分式_mul_div_mod_
部分式_mul_div_mod_ ::= 演算子_mul_div_mod 定数式 部分式_mul_div_mod_
演算子_mul_div_mod ::= * あるいは / あるいは %
定数式 ::= 数値 あるいは ( 部分式_comma )
数値 ::= 16進数 あるいは 8進数 あるいは 10進数
16進数 ::= 0x[0-9a-fA-F]+
8進数 ::= 0[0-7]*
10進数 ::= [1-9][0-9]*
今追加しようとしている「カンマ演算子」は既に実装してある「足し算・引き算」よりも優先順位が低いので「完結式」と「足し算・引き算」との評価との間に「カンマ」の処理を割り込ませます
つまり full_expression と constant から呼び出していた operator_add_sub の代わりに operator_comma を呼ぶようにするだけです
簡単ですね
では実装してみましょう
実装
次のメソッドを追加しましょう
class string_calc : protected istringstream<char> { . . . bool operator_comma( any_value_t* presult ); . . . }; bool string_calc::constant( any_value_t* presult ){ bool success = true; if( !skipspace()){ error_unexpected_eof(); success = false; } else{ char c = at( 0, SEEK_CUR ); if( c == '(' ){ size_type offset_prev = tell(); seek( 1, SEEK_CUR ); success = operator_comma( presult ); if( success ){ skipspace(); if( getch() != ')' ){ seek( offset_prev, SEEK_SET ); error_unbalanced_parenthesis(); success = false; } } } else if( isdigit( c )){ success = operator_new_number( presult ); } else{ error_illegal_character( c ); success = false; } } return success; } bool string_calc::operator_comma( any_value_t* presult ){ bool success = true; while( skipspace()){ success = operator_add_sub( presult ); if( !success ){ break; } skipspace(); char c = getch(); if( c != ',' ){ ungetch( c ); break; } } return success; } bool string_calc::full_expression( any_value_t* presult ){ return operator_comma( presult ); }