Parser - Expressions

Constants, identifier references, binary and unary ops
This commit is contained in:
Emmanuel BENOîT 2017-11-06 16:38:04 +01:00
parent ab999d222b
commit a9bd3cf507
2 changed files with 485 additions and 6 deletions

307
opast.cc
View file

@ -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
View file

@ -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