括弧も使えるようにする
演算子の優先順位というものを理解したところで、今度は括弧が使えるようにしてみましょう
仕組み
括弧も使えるようにしたパーサが処理すべき式は必ず次のような形式になっています
完結式 ::= 部分式_add_sub
部分式_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 ::= * あるいは / あるいは %
定数式 ::= 数値 あるいは ( 部分式_add_sub )
数値 ::= 16進数 あるいは 8進数 あるいは 10進数
16進数 ::= 0x[0-9a-fA-F]+
8進数 ::= 0[0-7]*
10進数 ::= [1-9][0-9]*
つまり constant に来たときに注目している文字が '(' だったら「部分式_add_sub」用の関数 operator_add_sub を呼び出し、そうでなければ今まで通り strtol を呼び出すだけです
簡単ですね
では実装してみましょう
実装
次のメソッドを追加しましょう
class string_calc : protected istringstream<char> { . . . void error_unbalanced_parenthesis(); . . . }; void string_calc::error_unbalanced_parenthesis(){ // 対応する () が見つからないから終わり OutputDebugString( "error: unbalanced parenthesis." ); } 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_add_sub( presult ); if( success ){ skipspace(); c = getch(); if( c != ')' ){ error_illegal_character( c ); 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; }