Parser - Expressions
Constants, identifier references, binary and unary ops
This commit is contained in:
parent
ab999d222b
commit
a9bd3cf507
2 changed files with 485 additions and 6 deletions
307
opast.cc
307
opast.cc
|
@ -179,6 +179,108 @@ T_ProgramInstrNode::T_ProgramInstrNode(
|
|||
{ }
|
||||
|
||||
|
||||
/*= T_SetInstrNode ===========================================================*/
|
||||
|
||||
T_SetInstrNode::T_SetInstrNode(
|
||||
T_InstrListNode& parent ,
|
||||
T_SRDToken const& idToken ) noexcept
|
||||
: A_InstructionNode( OP_PROGRAM , parent ) ,
|
||||
id_( idToken.stringValue( ) ) ,
|
||||
idLocation_( idToken.location( ) )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_ConstantExprNode =======================================================*/
|
||||
|
||||
T_ConstantExprNode::T_ConstantExprNode(
|
||||
A_Node& parent ,
|
||||
T_SRDToken const& token ) noexcept
|
||||
: A_ExpressionNode( EXPR_CONST , parent ) ,
|
||||
wasFloat_( token.type( ) == E_SRDTokenType::FLOAT ) ,
|
||||
vFloat_( token.floatValue( ) ) ,
|
||||
vInt_( token.longValue( ) )
|
||||
{
|
||||
location( ) = token.location( );
|
||||
}
|
||||
|
||||
T_ConstantExprNode::T_ConstantExprNode(
|
||||
A_Node& parent ,
|
||||
double value ) noexcept
|
||||
: A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( true ) ,
|
||||
vFloat_( value ) , vInt_( (int64_t) value )
|
||||
{ }
|
||||
|
||||
T_ConstantExprNode::T_ConstantExprNode(
|
||||
A_Node& parent ,
|
||||
int64_t value ) noexcept
|
||||
: A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( false ) ,
|
||||
vFloat_( value ) , vInt_( value )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_IdentifierExprNode =====================================================*/
|
||||
|
||||
T_IdentifierExprNode::T_IdentifierExprNode(
|
||||
A_Node& parent ,
|
||||
T_SRDToken const& token ) noexcept
|
||||
: T_IdentifierExprNode( parent , token.stringValue( ) )
|
||||
{
|
||||
location( ) = token.location( );
|
||||
}
|
||||
|
||||
T_IdentifierExprNode::T_IdentifierExprNode(
|
||||
A_Node& parent ,
|
||||
T_String const& id ) noexcept
|
||||
: A_ExpressionNode( EXPR_ID , parent ) , id_( id )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_UnaryOperatorNode ======================================================*/
|
||||
|
||||
T_UnaryOperatorNode::T_UnaryOperatorNode(
|
||||
A_Node& parent ,
|
||||
const E_Operator op ) noexcept
|
||||
: A_ExpressionNode( ([op]() {
|
||||
switch ( op ) {
|
||||
case NEG: return EXPR_NEG;
|
||||
case INV: return EXPR_INV;
|
||||
case NOT: return EXPR_NOT;
|
||||
case SIN: return EXPR_SIN;
|
||||
case COS: return EXPR_COS;
|
||||
case TAN: return EXPR_TAN;
|
||||
case SQRT: return EXPR_SQRT;
|
||||
case EXP: return EXPR_EXP;
|
||||
case LN: return EXPR_LN;
|
||||
}
|
||||
std::abort( );
|
||||
})( ) , parent ) , op_( op )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_BinaryOperatorNode =====================================================*/
|
||||
|
||||
T_BinaryOperatorNode::T_BinaryOperatorNode(
|
||||
A_Node& parent ,
|
||||
const E_Operator op ) noexcept
|
||||
: A_ExpressionNode( ([op]() {
|
||||
switch ( op ) {
|
||||
case ADD: return EXPR_ADD;
|
||||
case SUB: return EXPR_SUB;
|
||||
case MUL: return EXPR_MUL;
|
||||
case DIV: return EXPR_DIV;
|
||||
case POW: return EXPR_POW;
|
||||
case CMP_EQ: return EXPR_CMP_EQ;
|
||||
case CMP_NE: return EXPR_CMP_NE;
|
||||
case CMP_GT: return EXPR_CMP_GT;
|
||||
case CMP_GE: return EXPR_CMP_GE;
|
||||
case CMP_LT: return EXPR_CMP_LT;
|
||||
case CMP_LE: return EXPR_CMP_LE;
|
||||
}
|
||||
std::abort( );
|
||||
})( ) , parent ) , op_( op )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_Parser =================================================================*/
|
||||
|
||||
namespace {
|
||||
|
@ -190,10 +292,11 @@ struct T_ParserImpl_
|
|||
PIPELINE ,
|
||||
PROFILE ,
|
||||
PROGRAM ,
|
||||
SET ,
|
||||
};
|
||||
|
||||
const T_KeyValueTable< T_String , E_InstrType > instrMap{ ([]() {
|
||||
T_KeyValueTable< T_String , E_InstrType > temp;
|
||||
T_KeyValueTable< T_String , E_InstrType > temp{ 256 , 64 , 64 };
|
||||
const auto add{ [&temp]( char const* name , E_InstrType it ) {
|
||||
temp.add( T_String::Pooled( name ) , it );
|
||||
} };
|
||||
|
@ -202,6 +305,49 @@ struct T_ParserImpl_
|
|||
add( "pipeline" , E_InstrType::PIPELINE );
|
||||
add( "profiling" , E_InstrType::PROFILE );
|
||||
add( "program" , E_InstrType::PROGRAM );
|
||||
add( "set" , E_InstrType::SET );
|
||||
|
||||
return temp;
|
||||
})( ) };
|
||||
|
||||
const T_KeyValueTable< T_String , T_UnaryOperatorNode::E_Operator > unaryOpMap{ ([]() {
|
||||
T_KeyValueTable< T_String , T_UnaryOperatorNode::E_Operator > temp{ 64 , 32 , 32 };
|
||||
const auto add{ [&temp]( char const* name ,
|
||||
const T_UnaryOperatorNode::E_Operator it ) {
|
||||
temp.add( T_String::Pooled( name ) , it );
|
||||
} };
|
||||
|
||||
add( "neg" , T_UnaryOperatorNode::NEG );
|
||||
add( "inv" , T_UnaryOperatorNode::INV );
|
||||
add( "not" , T_UnaryOperatorNode::NOT );
|
||||
add( "sin" , T_UnaryOperatorNode::SIN );
|
||||
add( "cos" , T_UnaryOperatorNode::COS );
|
||||
add( "tan" , T_UnaryOperatorNode::TAN );
|
||||
add( "sqrt" , T_UnaryOperatorNode::SQRT );
|
||||
add( "exp" , T_UnaryOperatorNode::EXP );
|
||||
add( "ln" , T_UnaryOperatorNode::LN );
|
||||
|
||||
return temp;
|
||||
})( ) };
|
||||
|
||||
const T_KeyValueTable< T_String , T_BinaryOperatorNode::E_Operator > binOpMap{ ([]() {
|
||||
T_KeyValueTable< T_String , T_BinaryOperatorNode::E_Operator > temp{ 64 , 32 , 32 };
|
||||
const auto add{ [&temp]( char const* name ,
|
||||
const T_BinaryOperatorNode::E_Operator it ) {
|
||||
temp.add( T_String::Pooled( name ) , it );
|
||||
} };
|
||||
|
||||
add( "add" , T_BinaryOperatorNode::ADD );
|
||||
add( "sub" , T_BinaryOperatorNode::SUB );
|
||||
add( "mul" , T_BinaryOperatorNode::MUL );
|
||||
add( "div" , T_BinaryOperatorNode::DIV );
|
||||
add( "pow" , T_BinaryOperatorNode::POW );
|
||||
add( "cmp-eq" , T_BinaryOperatorNode::CMP_EQ );
|
||||
add( "cmp-ne" , T_BinaryOperatorNode::CMP_NE );
|
||||
add( "cmp-gt" , T_BinaryOperatorNode::CMP_GT );
|
||||
add( "cmp-ge" , T_BinaryOperatorNode::CMP_GE );
|
||||
add( "cmp-lt" , T_BinaryOperatorNode::CMP_LT );
|
||||
add( "cmp-le" , T_BinaryOperatorNode::CMP_LE );
|
||||
|
||||
return temp;
|
||||
})( ) };
|
||||
|
@ -236,6 +382,26 @@ struct T_ParserImpl_
|
|||
void parseProgramInstruction(
|
||||
T_InstrListNode& instructions ,
|
||||
T_SRDList const& input ) noexcept;
|
||||
void parseSetInstruction(
|
||||
T_InstrListNode& instructions ,
|
||||
T_SRDList const& input ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_OwnPtr< A_ExpressionNode > parseExpression(
|
||||
A_Node& parent ,
|
||||
T_SRDToken const& token ) noexcept;
|
||||
T_OwnPtr< A_ExpressionNode > parseOperation(
|
||||
A_Node& parent ,
|
||||
T_SRDList const& opList ) noexcept;
|
||||
T_OwnPtr< A_ExpressionNode > parseBinOp(
|
||||
A_Node& parent ,
|
||||
T_SRDList const& opList ,
|
||||
T_BinaryOperatorNode::E_Operator op ) noexcept;
|
||||
T_OwnPtr< A_ExpressionNode > parseUnaryOp(
|
||||
A_Node& parent ,
|
||||
T_SRDList const& opList ,
|
||||
T_UnaryOperatorNode::E_Operator op ) noexcept;
|
||||
};
|
||||
|
||||
T_ParserImpl_::T_ParserImpl_(
|
||||
|
@ -364,6 +530,9 @@ void T_ParserImpl_::parseInstructions(
|
|||
case E_InstrType::PROGRAM:
|
||||
parseProgramInstruction( instructions , ilist );
|
||||
break;
|
||||
case E_InstrType::SET:
|
||||
parseSetInstruction( instructions , ilist );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -474,6 +643,142 @@ void T_ParserImpl_::parseProgramInstruction(
|
|||
program.location( ) = input[ 0 ].location( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_ParserImpl_::parseSetInstruction(
|
||||
T_InstrListNode& instructions ,
|
||||
T_SRDList const& input ) noexcept
|
||||
{
|
||||
bool ok{ true };
|
||||
if ( input.size( ) == 1 ) {
|
||||
errors.addNew( "identifier and expression required" ,
|
||||
input[ 0 ].location( ) );
|
||||
return;
|
||||
}
|
||||
if ( input[ 1 ].type( ) != E_SRDTokenType::WORD ) {
|
||||
errors.addNew( "variable identifier expected" , input[ 1 ].location( ) );
|
||||
ok = false;
|
||||
}
|
||||
if ( input.size( ) == 2 ) {
|
||||
errors.addNew( "expression required" , input[ 0 ].location( ) );
|
||||
}
|
||||
if ( input.size( ) > 3 ) {
|
||||
errors.addNew( "too many arguments" , input[ 3 ].location( ) );
|
||||
}
|
||||
if ( !ok ) {
|
||||
return;
|
||||
}
|
||||
|
||||
T_SetInstrNode& set{ instructions.add< T_SetInstrNode >( input[ 1 ] ) };
|
||||
set.location( ) = input[ 0 ].location( );
|
||||
if ( input.size( ) > 2 ) {
|
||||
auto expr( parseExpression( set , input[ 2 ] ) );
|
||||
if ( expr ) {
|
||||
set.setExpression( std::move( expr ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseExpression(
|
||||
A_Node& parent ,
|
||||
T_SRDToken const& token ) noexcept
|
||||
{
|
||||
if ( token.isNumeric( ) ) {
|
||||
return NewOwned< T_ConstantExprNode >( parent , token );
|
||||
}
|
||||
if ( token.type( ) == E_SRDTokenType::WORD || token.type( ) == E_SRDTokenType::VAR ) {
|
||||
return NewOwned< T_IdentifierExprNode >( parent , token );
|
||||
}
|
||||
|
||||
if ( token.type( ) == E_SRDTokenType::LIST && !token.list( ).empty( ) ) {
|
||||
return parseOperation( parent , token.list( ) );
|
||||
}
|
||||
|
||||
errors.addNew( "invalid expression" , token.location( ) );
|
||||
return {};
|
||||
}
|
||||
|
||||
T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseOperation(
|
||||
A_Node& parent ,
|
||||
T_SRDList const& opList ) noexcept
|
||||
{
|
||||
T_SRDToken const& opId( opList[ 0 ] );
|
||||
if ( opId.type( ) != E_SRDTokenType::WORD ) {
|
||||
errors.addNew( "operator expected" , opId.location( ) );
|
||||
return {};
|
||||
}
|
||||
|
||||
if ( binOpMap.contains( opId.stringValue( ) ) ) {
|
||||
return parseBinOp( parent , opList ,
|
||||
*binOpMap.get( opId.stringValue( ) ) );
|
||||
}
|
||||
if ( unaryOpMap.contains( opId.stringValue( ) ) ) {
|
||||
return parseUnaryOp( parent , opList ,
|
||||
*unaryOpMap.get( opId.stringValue( ) ) );
|
||||
}
|
||||
|
||||
errors.addNew( "unknown operator" , opId.location( ) );
|
||||
return {};
|
||||
}
|
||||
|
||||
T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseBinOp(
|
||||
A_Node& parent ,
|
||||
T_SRDList const& opList ,
|
||||
T_BinaryOperatorNode::E_Operator op ) noexcept
|
||||
{
|
||||
if ( opList.size( ) < 3 ) {
|
||||
errors.addNew( "not enough arguments" , opList[ 0 ].location( ) );
|
||||
} else if ( opList.size( ) > 3 ) {
|
||||
errors.addNew( "too many arguments" , opList[ 3 ].location( ) );
|
||||
}
|
||||
|
||||
T_OwnPtr< T_BinaryOperatorNode > opNode{
|
||||
NewOwned< T_BinaryOperatorNode >( parent , op ) };
|
||||
opNode->location( ) = opList[ 0 ].location( );
|
||||
|
||||
if ( opList.size( ) > 1 ) {
|
||||
auto left{ parseExpression( *opNode , opList[ 1 ] ) };
|
||||
if ( left ) {
|
||||
opNode->setLeft( std::move( left ) );
|
||||
}
|
||||
}
|
||||
if ( opList.size( ) > 2 ) {
|
||||
auto right{ parseExpression( *opNode , opList[ 2 ] ) };
|
||||
if ( right ) {
|
||||
opNode->setRight( std::move( right ) );
|
||||
}
|
||||
}
|
||||
|
||||
return opNode;
|
||||
}
|
||||
|
||||
T_OwnPtr< A_ExpressionNode > T_ParserImpl_::parseUnaryOp(
|
||||
A_Node& parent ,
|
||||
T_SRDList const& opList ,
|
||||
T_UnaryOperatorNode::E_Operator op ) noexcept
|
||||
{
|
||||
if ( opList.size( ) < 2 ) {
|
||||
errors.addNew( "not enough arguments" , opList[ 0 ].location( ) );
|
||||
} else if ( opList.size( ) > 2 ) {
|
||||
errors.addNew( "too many arguments" , opList[ 2 ].location( ) );
|
||||
}
|
||||
|
||||
T_OwnPtr< T_UnaryOperatorNode > opNode{
|
||||
NewOwned< T_UnaryOperatorNode >( parent , op ) };
|
||||
opNode->location( ) = opList[ 0 ].location( );
|
||||
|
||||
if ( opList.size( ) > 1 ) {
|
||||
auto argument{ parseExpression( *opNode , opList[ 1 ] ) };
|
||||
if ( argument ) {
|
||||
opNode->setArgument( std::move( argument ) );
|
||||
}
|
||||
}
|
||||
|
||||
return opNode;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
|
184
opast.hh
184
opast.hh
|
@ -27,12 +27,20 @@ class A_Node
|
|||
OP_PROFILE , // Profiling block
|
||||
OP_PROGRAM , // Shader program declaration
|
||||
OP_SET , // Set instruction
|
||||
// Unary operators
|
||||
EXPR_NEG , EXPR_INV , EXPR_NOT ,
|
||||
EXPR_SIN , EXPR_COS , EXPR_TAN ,
|
||||
EXPR_SQRT , EXPR_EXP , EXPR_LN ,
|
||||
// Binary operators
|
||||
EXPR_ADD , EXPR_SUB ,
|
||||
EXPR_MUL , EXPR_DIV ,
|
||||
EXPR_POW ,
|
||||
// Binary operators - comparisons
|
||||
EXPR_CMP_EQ , EXPR_CMP_NE ,
|
||||
EXPR_CMP_GT , EXPR_CMP_GE ,
|
||||
EXPR_CMP_LT , EXPR_CMP_LE ,
|
||||
//
|
||||
EXPR_ADD , // Binary ops: add
|
||||
EXPR_MUL , // Binary ops: mul
|
||||
EXPR_SUB , // Binary ops: sub
|
||||
EXPR_DIV , // Binary ops: div
|
||||
EXPR_VAR , // Variable access
|
||||
EXPR_ID , // Variable access
|
||||
EXPR_CONST , // Numeric constant
|
||||
};
|
||||
|
||||
|
@ -64,6 +72,7 @@ class A_Node
|
|||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Base class for instruction nodes
|
||||
class A_InstructionNode : public A_Node
|
||||
{
|
||||
protected:
|
||||
|
@ -205,6 +214,18 @@ class T_FuncNode : public A_FuncNode
|
|||
T_SRDToken const& token ) noexcept;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Base class for expressions
|
||||
class A_ExpressionNode : public A_Node
|
||||
{
|
||||
protected:
|
||||
A_ExpressionNode( E_Type type ,
|
||||
A_Node& parent ) noexcept
|
||||
: A_Node( type , &parent )
|
||||
{ }
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
// Pipeline declaration instruction
|
||||
|
@ -276,6 +297,159 @@ class T_ProgramInstrNode : public A_InstructionNode
|
|||
T_SRDToken const& pathToken ) noexcept;
|
||||
};
|
||||
|
||||
// Setting a global variable
|
||||
class T_SetInstrNode : public A_InstructionNode
|
||||
{
|
||||
private:
|
||||
T_String id_;
|
||||
T_SRDLocation idLocation_;
|
||||
T_OwnPtr< A_ExpressionNode > expression_;
|
||||
|
||||
public:
|
||||
T_SetInstrNode( T_InstrListNode& parent ,
|
||||
T_SRDToken const& idToken ) noexcept;
|
||||
|
||||
T_String const& identifier( ) const noexcept
|
||||
{ return id_; }
|
||||
T_SRDLocation const& idLocation( ) const noexcept
|
||||
{ return idLocation_; }
|
||||
|
||||
void setExpression( T_OwnPtr< A_ExpressionNode > expression ) noexcept
|
||||
{ expression_ = std::move( expression ); }
|
||||
|
||||
bool hasExpression( ) const noexcept
|
||||
{ return bool( expression_ ); }
|
||||
A_ExpressionNode const& expression( ) const noexcept
|
||||
{ return *expression_; }
|
||||
A_ExpressionNode& expression( ) noexcept
|
||||
{ return *expression_; }
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
// A constant value
|
||||
class T_ConstantExprNode : public A_ExpressionNode
|
||||
{
|
||||
private:
|
||||
bool wasFloat_;
|
||||
double vFloat_;
|
||||
int64_t vInt_;
|
||||
|
||||
public:
|
||||
T_ConstantExprNode( A_Node& parent ,
|
||||
T_SRDToken const& token ) noexcept;
|
||||
|
||||
T_ConstantExprNode( A_Node& parent ,
|
||||
int64_t value ) noexcept;
|
||||
T_ConstantExprNode( A_Node& parent ,
|
||||
double value ) noexcept;
|
||||
|
||||
bool wasFloat( ) const noexcept
|
||||
{ return wasFloat_; }
|
||||
double floatValue( ) const noexcept
|
||||
{ return vFloat_; }
|
||||
int64_t intValue( ) const noexcept
|
||||
{ return vInt_; }
|
||||
};
|
||||
|
||||
// An identifier used in an expression
|
||||
class T_IdentifierExprNode : public A_ExpressionNode
|
||||
{
|
||||
private:
|
||||
T_String id_;
|
||||
|
||||
public:
|
||||
T_IdentifierExprNode( A_Node& parent ,
|
||||
T_SRDToken const& token ) noexcept;
|
||||
T_IdentifierExprNode( A_Node& parent ,
|
||||
T_String const& id ) noexcept;
|
||||
|
||||
T_String const& id( ) const noexcept
|
||||
{ return id_; }
|
||||
};
|
||||
|
||||
// A unary operator
|
||||
class T_UnaryOperatorNode : public A_ExpressionNode
|
||||
{
|
||||
public:
|
||||
enum E_Operator {
|
||||
NEG , INV , NOT ,
|
||||
SIN , COS , TAN ,
|
||||
SQRT , EXP , LN
|
||||
};
|
||||
|
||||
private:
|
||||
E_Operator op_;
|
||||
T_OwnPtr< A_ExpressionNode > argument_;
|
||||
|
||||
public:
|
||||
T_UnaryOperatorNode(
|
||||
A_Node& parent ,
|
||||
const E_Operator op ) noexcept;
|
||||
|
||||
E_Operator op( ) const noexcept
|
||||
{ return op_; }
|
||||
|
||||
void setArgument( T_OwnPtr< A_ExpressionNode > argument ) noexcept
|
||||
{ argument_ = std::move( argument ); }
|
||||
|
||||
bool hasArgument( ) const noexcept
|
||||
{ return bool( argument_ ); }
|
||||
|
||||
A_ExpressionNode const& argument( ) const noexcept
|
||||
{ return *argument_; }
|
||||
A_ExpressionNode& argument( ) noexcept
|
||||
{ return *argument_; }
|
||||
};
|
||||
|
||||
// A binary operator
|
||||
class T_BinaryOperatorNode : public A_ExpressionNode
|
||||
{
|
||||
public:
|
||||
enum E_Operator {
|
||||
ADD , SUB ,
|
||||
MUL , DIV ,
|
||||
POW ,
|
||||
|
||||
CMP_EQ , CMP_NE ,
|
||||
CMP_GT , CMP_GE ,
|
||||
CMP_LT , CMP_LE ,
|
||||
};
|
||||
|
||||
private:
|
||||
E_Operator op_;
|
||||
T_OwnPtr< A_ExpressionNode > left_;
|
||||
T_OwnPtr< A_ExpressionNode > right_;
|
||||
|
||||
public:
|
||||
T_BinaryOperatorNode(
|
||||
A_Node& parent ,
|
||||
const E_Operator op ) noexcept;
|
||||
|
||||
E_Operator op( ) const noexcept
|
||||
{ return op_; }
|
||||
|
||||
void setLeft( T_OwnPtr< A_ExpressionNode > left ) noexcept
|
||||
{ left_ = std::move( left ); }
|
||||
void setRight( T_OwnPtr< A_ExpressionNode > right ) noexcept
|
||||
{ right_ = std::move( right ); }
|
||||
|
||||
bool hasLeft( ) const noexcept
|
||||
{ return bool( left_ ); }
|
||||
bool hasRight( ) const noexcept
|
||||
{ return bool( right_ ); }
|
||||
|
||||
A_ExpressionNode const& left( ) const noexcept
|
||||
{ return *left_; }
|
||||
A_ExpressionNode& left( ) noexcept
|
||||
{ return *left_; }
|
||||
|
||||
A_ExpressionNode const& right( ) const noexcept
|
||||
{ return *right_; }
|
||||
A_ExpressionNode& right( ) noexcept
|
||||
{ return *right_; }
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
class T_Parser : public A_PrivateImplementation
|
||||
|
|
Loading…
Reference in a new issue