実数も使えるようにする

これまでは使える数値は整数だけで実数を指定する方法がありませんでした
実数も使えるようにしてみましょう

仕組み

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


完結式 ::= 部分式_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 ::= 部分式_unary 部分式_mul_div_mod_
部分式_mul_div_mod_ ::= 演算子_mul_div_mod 部分式_unary 部分式_mul_div_mod_
演算子_mul_div_mod ::= * あるいは / あるいは %
部分式_unary ::= 演算子_unary 定数式
演算子_unary ::= + あるいは − あるいは ~ あるいは !
定数式 ::= 数値 あるいは ( 部分式_comma )
数値  ::= 実数 あるいは 整数
実数  ::= [0-9]*.[0-9]+ あるいは [0-9]+. あるいは [0-9]*.?[0-9]+[eE] ± [0-9]+ あるいは [0-9]+.[eE] ± [0-9]+
整数  ::= 16進数 あるいは 8進数 あるいは 10進数
16進数 ::= 0x[0-9​a-f​A-F]+
8進数 ::= 0[0-7]*
10進数 ::= [1-9][0-9]*

実数として有効な形式かどうかのチェックなどは面倒なのでとりあえず strtod にでもやらせておきましょう
「数値」の評価に関するところだけなので any_value_t クラスを実数対応にしたら、パーサ側では strtol に加えて strtod を呼ぶようにすればいいだけです
簡単ですね
では実装してみましょう

実装

bool	string_calc::operator_new_number( any_value_t*	presult ){
	bool	success = true;
	if( !skipspace()){
		error_unexpected_eof();
		success = false;
	}
	else{
		const char*	s = getp();
		char*	endp = const_cast<char*>(s);
		strtol( s, &endp, 0 );
		if(( *endp == '.' )||( *endp == 'e' )||( *endp == 'E' )){
			strtod( s, &endp );
			size_type	cch = endp - s;
			if( !cch ){
				error_illegal_character( *s );
				success = false;
			}
			else{
				std::string	value = gets( cch );
				if( presult ){
					presult->assign( TYPEOF_FLOAT, value );
				}
			}
		}
		else{
			size_type	cch = endp - s;
			std::string	value = gets( cch );
			if( presult ){
				presult->assign( TYPEOF_INTEGER, value );
			}
		}
	}
	return	success;
}
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();
				c = getch();
				if( c != ')' ){
					error_illegal_character( c );
					seek( offset_prev, SEEK_SET );
					error_unbalanced_parenthesis();
					success = false;
				}
			}
		}
		else if( isdigit( c ) <strong>||( c == '.' )</strong>){
			success = operator_new_number( presult );
		}
		else{
			error_illegal_character( c );
			success = false;
		}
	}
	return	success;
}

any_value_t を実数対応に改造しましょう

#define	TYPEOF_INTEGER	"Integer"
#define	TYPEOF_FLOAT	"Float"

class any_value_t {
	std::string	m_name;
	std::string	m_value;
public:
	std::string	get_value() const {
		return	m_value;
	}
	void	put_value( const std::string&	value_new ){
		m_value = value_new;
	}
	std::string	get_name() const {
		return	m_name;
	}
	void	put_name( const std::string&	name_new ){
		m_name = name_new;
	}
	bool	defined() const {
		return	!m_name.empty();
	}
	any_value_t&	assign( const std::string&	name, const std::string&	value ){
		m_name = name;
		m_value = value;
		return	*this;
	}
	void	undef(){
		m_name.clear();
		m_value.clear();
	}
	bool	is_float() const {
		return	( m_name == TYPEOF_FLOAT );
	}
	double	operator_typecast_to_double() const {
		const char*	p = &m_value[0];
		char*	endp = const_cast<char*>(p);
		return	strtod( p, &endp );
	}
	long	operator_typecast_to_long() const {
		if( is_float()){
			return	( long )operator_typecast_to_double();
		}
		else{
			const char*	p = &m_value[0];
			char*	endp = const_cast<char*>(p);
			return	strtol( p, &endp, 0 );
		}
	}
	unsigned long	operator_typecast_to_ulong() const {
		if( is_float()){
			return	( unsigned long )operator_typecast_to_double();
		}
		else{
			const char*	p = &m_value[0];
			char*	endp = const_cast<char*>(p);
			return	strtoul( p, &endp, 0 );
		}
	}
	any_value_t&	operator_assign( const any_value_t&	rhs ){
		return	operator=( rhs );
	}
	any_value_t&	operator_assign_add( const any_value_t&	rhs ){
		if( is_float() || rhs.is_float()){
			double	l = operator_typecast_to_double();
			double	r = rhs.operator_typecast_to_double();
			l += r;
			return	assign( TYPEOF_FLOAT, stringprintf( "%g", l ));
		}
		else{
			long	l = operator_typecast_to_long();
			long	r = rhs.operator_typecast_to_long();
			l += r;
			return	assign( TYPEOF_INTEGER, stringprintf( "%d", l ));
		}
	}
	any_value_t&	operator_assign_sub( const any_value_t&	rhs ){
		if( is_float() || rhs.is_float()){
			double	l = operator_typecast_to_double();
			double	r = rhs.operator_typecast_to_double();
			l -= r;
			return	assign( TYPEOF_FLOAT, stringprintf( "%g", l ));
		}
		else{
			long	l = operator_typecast_to_long();
			long	r = rhs.operator_typecast_to_long();
			l -= r;
			return	assign( TYPEOF_INTEGER, stringprintf( "%d", l ));
		}
	}
	any_value_t&	operator_assign_mul( const any_value_t&	rhs ){
		if( is_float() || rhs.is_float()){
			double	l = operator_typecast_to_double();
			double	r = rhs.operator_typecast_to_double();
			l *= r;
			return	assign( TYPEOF_FLOAT, stringprintf( "%g", l ));
		}
		else{
			long	l = operator_typecast_to_long();
			long	r = rhs.operator_typecast_to_long();
			l *= r;
			return	assign( TYPEOF_INTEGER, stringprintf( "%d", l ));
		}
	}
	any_value_t&	operator_assign_div( const any_value_t&	rhs ){
		if( is_float() || rhs.is_float()){
			double	l = operator_typecast_to_double();
			double	r = rhs.operator_typecast_to_double();
			l /= r;
			return	assign( TYPEOF_FLOAT, stringprintf( "%g", l ));
		}
		else{
			long	l = operator_typecast_to_long();
			long	r = rhs.operator_typecast_to_long();
			l /= r;
			return	assign( TYPEOF_INTEGER, stringprintf( "%d", l ));
		}
	}
	any_value_t&	operator_assign_mod( const any_value_t&	rhs ){
		long	l = operator_typecast_to_long();
		long	r = rhs.operator_typecast_to_long();
		l %= r;
		return	assign( TYPEOF_INTEGER, stringprintf( "%d", l ));
	}
	any_value_t	operator_add( const any_value_t&	rhs ) const {
		any_value_t	result = *this;
		return	result.operator_assign_add( rhs );
	}
	any_value_t	operator_sub( const any_value_t&	rhs ) const {
		any_value_t	result = *this;
		return	result.operator_assign_sub( rhs );
	}
	any_value_t	operator_mul( const any_value_t&	rhs ) const {
		any_value_t	result = *this;
		return	result.operator_assign_mul( rhs );
	}
	any_value_t	operator_div( const any_value_t&	rhs ) const {
		any_value_t	result = *this;
		return	result.operator_assign_div( rhs );
	}
	any_value_t	operator_mod( const any_value_t&	rhs ) const {
		any_value_t	result = *this;
		return	result.operator_assign_mod( rhs );
	}
	any_value_t	operator_unary_plus() const {
		if( is_float()){
			any_value_t	result = *this;
			return	result.assign( TYPEOF_FLOAT, stringprintf( "%g", +result.operator_typecast_to_double()));
		}
		else{
			any_value_t	result = *this;
			return	result.assign( TYPEOF_INTEGER, stringprintf( "%d", +result.operator_typecast_to_long()));
		}
	}
	any_value_t	operator_unary_minus() const {
		if( is_float()){
			any_value_t	result = *this;
			return	result.assign( TYPEOF_FLOAT, stringprintf( "%g", -result.operator_typecast_to_double()));
		}
		else{
			any_value_t	result = *this;
			return	result.assign( TYPEOF_INTEGER, stringprintf( "%d", -result.operator_typecast_to_long()));
		}
	}
	any_value_t	operator_unary_conditional_not() const {
		if( is_float()){
			any_value_t	result = *this;
			return	result.assign( TYPEOF_FLOAT, ( result.operator_typecast_to_double() != 0.0 ) ? "1" : "0" );
		}
		else{
			any_value_t	result = *this;
			return	result.assign( TYPEOF_INTEGER, !operator_typecast_to_bool() ? "1" : "0" );
		}
	}
	any_value_t	operator_unary_logical_not() const {
		any_value_t	result = *this;
		return	result.assign( TYPEOF_INTEGER, stringprintf( "%u", ~result.operator_typecast_to_ulong()));
	}
	
	bool	operator_typecast_to_bool() const {
		return	!!operator_typecast_to_long();
	}
	operator bool() const {
		return	operator_typecast_to_bool();
	}
	
	any_value_t&	operator=( const any_value_t&	rhs ){
		if( this != &rhs ){
			m_name = rhs.m_name;
			m_value = rhs.m_value;
		}
		return	*this;
	}
	any_value_t():
	m_name(),
	m_value()
	{
	}
	any_value_t( const any_value_t&	rhs ):
	m_name(rhs.m_name),
	m_value(rhs.m_value)
	{
	}
	any_value_t( const std::string&	name, const std::string&	value ):
	m_name(name),
	m_value(value)
	{
	}
};

練習

ここまでの機能でだいたい電卓が作れそうなくらいにはなりました
初心者の方などはこの辺りで関数電卓でも作ってみるといいですよ