I think byte codes are overkill. Just construct an expression tree and evaluate it. Here's the basics:

Code:

enum op { add, sub, mul, div, constant, X };
struct expression_node
{
enum op operator;
double value;
struct expression_node *lhs;
struct expression_node *rhs;
};
double eval( struct expression_node *node, double Xvalue )
{
if( node->operator == add )
return eval( node->lhs, Xvalue ) + eval( node->rhs, Xvalue );
if( node->operator == sub )
return eval( node->lhs, Xvalue ) - eval( node->rhs, Xvalue );
if( node->operator == mul )
return eval( node->lhs, Xvalue ) * eval( node->rhs, Xvalue );
if( node->operator == div )
return eval( node->lhs, Xvalue ) / eval( node->rhs, Xvalue );
if( node->operator == constant )
return node->value;
if( node->operator == X )
return Xvalue;
assert( ( "Operator is not recognized", 0 ) );
}

Then in your parser, build up this tree, then call eval() on it. To fiddle the X value, just pass in what you want it to be.