括弧も使えるようにする

演算子の優先順位というものを理解したところで、今度は括弧が使えるようにしてみましょう

仕組み

括弧も使えるようにしたパーサが処理すべき式は必ず次のような形式になっています


完結式 ::= 部分式_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-9​a-f​A-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;
}