diff --git a/opast.cc b/opast.cc index abc23e0..720b3fe 100644 --- a/opast.cc +++ b/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 /*----------------------------------------------------------------------------*/ diff --git a/opast.hh b/opast.hh index d059db1..f84a43d 100644 --- a/opast.hh +++ b/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