// // Copyright (C) 2016-2018 Google, Inc. // Copyright (C) 2016 LunarG, Inc. // Copyright (C) 2023 Mobica Limited. // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // // Neither the name of Google, Inc., nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // // This is a set of mutually recursive methods implementing the HLSL grammar. // Generally, each returns // - through an argument: a type specifically appropriate to which rule it // recognized // - through the return value: true/false to indicate whether or not it // recognized its rule // // As much as possible, only grammar recognition should happen in this file, // with all other work being farmed out to hlslParseHelper.cpp, which in turn // will build the AST. // // The next token, yet to be "accepted" is always sitting in 'token'. // When a method says it accepts a rule, that means all tokens involved // in the rule will have been consumed, and none left in 'token'. // #include "hlslTokens.h" #include "hlslGrammar.h" #include "hlslAttributes.h" namespace glslang { // Root entry point to this recursive decent parser. // Return true if compilation unit was successfully accepted. bool HlslGrammar::parse() { … } void HlslGrammar::expected(const char* syntax) { … } void HlslGrammar::unimplemented(const char* error) { … } // IDENTIFIER // THIS // type that can be used as IDENTIFIER // // Only process the next token if it is an identifier. // Return true if it was an identifier. bool HlslGrammar::acceptIdentifier(HlslToken& idToken) { … } // compilationUnit // : declaration_list EOF // bool HlslGrammar::acceptCompilationUnit() { … } // Recognize the following, but with the extra condition that it can be // successfully terminated by EOF or '}'. // // declaration_list // : list of declaration_or_semicolon followed by EOF or RIGHT_BRACE // // declaration_or_semicolon // : declaration // : SEMICOLON // bool HlslGrammar::acceptDeclarationList(TIntermNode*& nodeList) { … } // sampler_state // : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE // // sampler_state_assignment // : sampler_state_identifier EQUAL value SEMICOLON // // sampler_state_identifier // : ADDRESSU // | ADDRESSV // | ADDRESSW // | BORDERCOLOR // | FILTER // | MAXANISOTROPY // | MAXLOD // | MINLOD // | MIPLODBIAS // bool HlslGrammar::acceptSamplerState() { … } // sampler_declaration_dx9 // : SAMPLER identifier EQUAL sampler_type sampler_state // bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/) { … } // declaration // : attributes attributed_declaration // | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE // // attributed_declaration // : sampler_declaration_dx9 post_decls SEMICOLON // | fully_specified_type // for cbuffer/tbuffer // | fully_specified_type declarator_list SEMICOLON // for non cbuffer/tbuffer // | fully_specified_type identifier function_parameters post_decls compound_statement // function definition // | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition // | typedef declaration // // declarator_list // : declarator COMMA declarator COMMA declarator... // zero or more declarators // // declarator // : identifier array_specifier post_decls // | identifier array_specifier post_decls EQUAL assignment_expression // | identifier function_parameters post_decls // function prototype // // Parsing has to go pretty far in to know whether it's a variable, prototype, or // function definition, so the implementation below doesn't perfectly divide up the grammar // as above. (The 'identifier' in the first item in init_declarator list is the // same as 'identifier' for function declarations.) // // This can generate more than one subtree, one per initializer or a function body. // All initializer subtrees are put in their own aggregate node, making one top-level // node for all the initializers. Each function created is a top-level node to grow // into the passed-in nodeList. // // If 'nodeList' is passed in as non-null, it must be an aggregate to extend for // each top-level node the declaration creates. Otherwise, if only one top-level // node in generated here, that is want is returned in nodeList. // bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList) { … } // control_declaration // : fully_specified_type identifier EQUAL expression // bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node) { … } // fully_specified_type // : type_specifier // | type_qualifier type_specifier // | type_specifier type_qualifier // bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributes& attributes) { … } bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributes& attributes, bool forbidDeclarators) { … } // type_qualifier // : qualifier qualifier ... // // Zero or more of these, so this can't return false. // bool HlslGrammar::acceptPreQualifier(TQualifier& qualifier) { … } // type_qualifier // : qualifier qualifier ... // // Zero or more of these, so this can't return false. // bool HlslGrammar::acceptPostQualifier(TQualifier& qualifier) { … } // layout_qualifier_list // : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN // // layout_qualifier // : identifier // | identifier EQUAL expression // // Zero or more of these, so this can't return false. // bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier) { … } // template_type // : FLOAT // | DOUBLE // | INT // | DWORD // | UINT // | BOOL // bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType, TPrecisionQualifier& precision) { … } // vector_template_type // : VECTOR // | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE // bool HlslGrammar::acceptVectorTemplateType(TType& type) { … } // matrix_template_type // : MATRIX // | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE // bool HlslGrammar::acceptMatrixTemplateType(TType& type) { … } // layout_geometry // : LINESTREAM // | POINTSTREAM // | TRIANGLESTREAM // bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry) { … } // tessellation_decl_type // : INPUTPATCH // | OUTPUTPATCH // bool HlslGrammar::acceptTessellationDeclType(TBuiltInVariable& patchType) { … } // tessellation_patch_template_type // : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE // bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type) { … } // stream_out_template_type // : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE // bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry) { … } // annotations // : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE // bool HlslGrammar::acceptAnnotations(TQualifier&) { … } // subpass input type // : SUBPASSINPUT // | SUBPASSINPUT VECTOR LEFT_ANGLE template_type RIGHT_ANGLE // | SUBPASSINPUTMS // | SUBPASSINPUTMS VECTOR LEFT_ANGLE template_type RIGHT_ANGLE bool HlslGrammar::acceptSubpassInputType(TType& type) { … } // sampler_type for DX9 compatibility // : SAMPLER // | SAMPLER1D // | SAMPLER2D // | SAMPLER3D // | SAMPLERCUBE bool HlslGrammar::acceptSamplerTypeDX9(TType &type) { … } // sampler_type // : SAMPLER // | SAMPLER1D // | SAMPLER2D // | SAMPLER3D // | SAMPLERCUBE // | SAMPLERSTATE // | SAMPLERCOMPARISONSTATE bool HlslGrammar::acceptSamplerType(TType& type) { … } // texture_type // | BUFFER // | TEXTURE1D // | TEXTURE1DARRAY // | TEXTURE2D // | TEXTURE2DARRAY // | TEXTURE3D // | TEXTURECUBE // | TEXTURECUBEARRAY // | TEXTURE2DMS // | TEXTURE2DMSARRAY // | RWBUFFER // | RWTEXTURE1D // | RWTEXTURE1DARRAY // | RWTEXTURE2D // | RWTEXTURE2DARRAY // | RWTEXTURE3D bool HlslGrammar::acceptTextureType(TType& type) { … } // If token is for a type, update 'type' with the type information, // and return true and advance. // Otherwise, return false, and don't advance bool HlslGrammar::acceptType(TType& type) { … } bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList) { … } // struct // : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE // | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE // | struct_type IDENTIFIER // use of previously declared struct type // // struct_type // : STRUCT // | CLASS // | CBUFFER // | TBUFFER // bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList) { … } // constantbuffer // : CONSTANTBUFFER LEFT_ANGLE type RIGHT_ANGLE bool HlslGrammar::acceptConstantBufferType(TType& type) { … } // texture_buffer // : TEXTUREBUFFER LEFT_ANGLE type RIGHT_ANGLE bool HlslGrammar::acceptTextureBufferType(TType& type) { … } // struct_buffer // : APPENDSTRUCTUREDBUFFER // | BYTEADDRESSBUFFER // | CONSUMESTRUCTUREDBUFFER // | RWBYTEADDRESSBUFFER // | RWSTRUCTUREDBUFFER // | STRUCTUREDBUFFER bool HlslGrammar::acceptStructBufferType(TType& type) { … } // struct_declaration_list // : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ... // // struct_declaration // : attributes fully_specified_type struct_declarator COMMA struct_declarator ... // | attributes fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition // // struct_declarator // : IDENTIFIER post_decls // | IDENTIFIER array_specifier post_decls // | IDENTIFIER function_parameters post_decls // member-function prototype // bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList, TVector<TFunctionDeclarator>& declarators) { … } // member_function_definition // | function_parameters post_decls compound_statement // // Expects type to have EvqGlobal for a static member and // EvqTemporary for non-static member. bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, TString& memberName, TFunctionDeclarator& declarator) { … } // function_parameters // : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN // | LEFT_PAREN VOID RIGHT_PAREN // bool HlslGrammar::acceptFunctionParameters(TFunction& function) { … } // default_parameter_declaration // : EQUAL conditional_expression // : EQUAL initializer bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node) { … } // parameter_declaration // : attributes attributed_declaration // // attributed_declaration // : fully_specified_type post_decls [ = default_parameter_declaration ] // | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ] // bool HlslGrammar::acceptParameterDeclaration(TFunction& function) { … } // Do the work to create the function definition in addition to // parsing the body (compound_statement). // // If 'deferredTokens' are passed in, just get the token stream, // don't process. // bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList, TVector<HlslToken>* deferredTokens) { … } bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList) { … } // Accept an expression with parenthesis around it, where // the parenthesis ARE NOT expression parenthesis, but the // syntactically required ones like in "if ( expression )". // // Also accepts a declaration expression; "if (int a = expression)". // // Note this one is not set up to be speculative; as it gives // errors if not found. // bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression) { … } // The top-level full expression recognizer. // // expression // : assignment_expression COMMA assignment_expression COMMA assignment_expression ... // bool HlslGrammar::acceptExpression(TIntermTyped*& node) { … } // initializer // : LEFT_BRACE RIGHT_BRACE // | LEFT_BRACE initializer_list RIGHT_BRACE // // initializer_list // : assignment_expression COMMA assignment_expression COMMA ... // bool HlslGrammar::acceptInitializer(TIntermTyped*& node) { … } // Accept an assignment expression, where assignment operations // associate right-to-left. That is, it is implicit, for example // // a op (b op (c op d)) // // assigment_expression // : initializer // | conditional_expression // | conditional_expression assign_op conditional_expression assign_op conditional_expression ... // bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node) { … } // Accept a conditional expression, which associates right-to-left, // accomplished by the "true" expression calling down to lower // precedence levels than this level. // // conditional_expression // : binary_expression // | binary_expression QUESTION expression COLON assignment_expression // bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node) { … } // Accept a binary expression, for binary operations that // associate left-to-right. This is, it is implicit, for example // // ((a op b) op c) op d // // binary_expression // : expression op expression op expression ... // // where 'expression' is the next higher level in precedence. // bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel) { … } // unary_expression // : (type) unary_expression // | + unary_expression // | - unary_expression // | ! unary_expression // | ~ unary_expression // | ++ unary_expression // | -- unary_expression // | postfix_expression // bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node) { … } // postfix_expression // : LEFT_PAREN expression RIGHT_PAREN // | literal // | constructor // | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ] // | function_call // | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET // | postfix_expression DOT IDENTIFIER // | postfix_expression DOT IDENTIFIER arguments // | postfix_expression arguments // | postfix_expression INC_OP // | postfix_expression DEC_OP // bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) { … } // constructor // : type argument_list // bool HlslGrammar::acceptConstructor(TIntermTyped*& node) { … } // The function_call identifier was already recognized, and passed in as idToken. // // function_call // : [idToken] arguments // bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject) { … } // arguments // : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN // // The arguments are pushed onto the 'function' argument list and // onto the 'arguments' aggregate. // bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments) { … } bool HlslGrammar::acceptLiteral(TIntermTyped*& node) { … } // simple_statement // : SEMICOLON // | declaration_statement // | expression SEMICOLON // bool HlslGrammar::acceptSimpleStatement(TIntermNode*& statement) { … } // compound_statement // : LEFT_CURLY statement statement ... RIGHT_CURLY // bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement) { … } bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement) { … } bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement) { … } // statement // : attributes attributed_statement // // attributed_statement // : compound_statement // | simple_statement // | selection_statement // | switch_statement // | case_label // | default_label // | iteration_statement // | jump_statement // bool HlslGrammar::acceptStatement(TIntermNode*& statement) { … } // attributes // : [zero or more:] bracketed-attribute // // bracketed-attribute: // : LEFT_BRACKET scoped-attribute RIGHT_BRACKET // : LEFT_BRACKET LEFT_BRACKET scoped-attribute RIGHT_BRACKET RIGHT_BRACKET // // scoped-attribute: // : attribute // | namespace COLON COLON attribute // // attribute: // : UNROLL // | UNROLL LEFT_PAREN literal RIGHT_PAREN // | FASTOPT // | ALLOW_UAV_CONDITION // | BRANCH // | FLATTEN // | FORCECASE // | CALL // | DOMAIN // | EARLYDEPTHSTENCIL // | INSTANCE // | MAXTESSFACTOR // | OUTPUTCONTROLPOINTS // | OUTPUTTOPOLOGY // | PARTITIONING // | PATCHCONSTANTFUNC // | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN // void HlslGrammar::acceptAttributes(TAttributes& attributes) { … } // selection_statement // : IF LEFT_PAREN expression RIGHT_PAREN statement // : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement // bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributes& attributes) { … } // switch_statement // : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement // bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributes& attributes) { … } // iteration_statement // : WHILE LEFT_PAREN condition RIGHT_PAREN statement // | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON // | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement // // Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen. bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributes& attributes) { … } // jump_statement // : CONTINUE SEMICOLON // | BREAK SEMICOLON // | DISCARD SEMICOLON // | RETURN SEMICOLON // | RETURN expression SEMICOLON // bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement) { … } // case_label // : CASE expression COLON // bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement) { … } // default_label // : DEFAULT COLON // bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement) { … } // array_specifier // : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional // : LEFT_BRACKET RGHT_BRACKET // optional // void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes) { … } // post_decls // : COLON semantic // optional // COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional // COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional // COLON LAYOUT layout_qualifier_list // annotations // optional // // Return true if any tokens were accepted. That is, // false can be returned on successfully recognizing nothing, // not necessarily meaning bad syntax. // bool HlslGrammar::acceptPostDecls(TQualifier& qualifier) { … } // // Get the stream of tokens from the scanner, but skip all syntactic/semantic // processing. // bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens) { … } // Return a string for just the types that can also be declared as an identifier. const char* HlslGrammar::getTypeString(EHlslTokenClass tokenClass) const { … } } // end namespace glslang