}
// declaration
-// : dummy stub
+// : SEMICOLON
+// : fully_specified_type ;
+// | fully_specified_type identifier ;
+// | fully_specified_type identifier = expression ;
+// | fully_specified_type identifier function_parameters ; // function prototype
+// | fully_specified_type function_parameters compound_statement // function definition
+//
bool HlslGrammar::acceptDeclaration()
{
+ // fully_specified_type
+ TType type;
+ if (! acceptFullySpecifiedType(type))
+ return false;
+
+ // identifier
+ if (token.tokenClass == EHTokIdentifier) {
+ TSourceLoc declLoc = token.loc;
+ TString* declName = token.string;
+ advanceToken();
+
+ // = expression
+ TIntermTyped* expressionNode = nullptr;
+ if (acceptTokenClass(EHTokEqual)) {
+ if (! acceptExpression(expressionNode)) {
+ expected("initializer");
+ return false;
+ }
+ }
+
+ // ;
+ if (acceptTokenClass(EHTokSemicolon)) {
+ parseContext.declareVariable(declLoc, *declName, type, 0, expressionNode);
+ return true;
+ }
+ }
+
+ // no identifier, just ;
+ if (acceptTokenClass(EHTokSemicolon))
+ return true;
+
+ return true;
+}
+
+// fully_specified_type
+// : type_specifier
+// | type_qualifier type_specifier
+//
+bool HlslGrammar::acceptFullySpecifiedType(TType& type)
+{
+ // type_qualifier
+ TQualifier qualifier;
+ qualifier.clear();
+ acceptQualifier(qualifier);
+
+ // type_specifier
+ if (! acceptType(type))
+ return false;
+ type.getQualifier() = qualifier;
+
+ return true;
+}
+
+// If token is a qualifier, return its token class and advance to the next
+// qualifier. Otherwise, return false, and don't advance.
+void HlslGrammar::acceptQualifier(TQualifier& qualifier)
+{
+ switch (token.tokenClass) {
+ case EHTokUniform:
+ qualifier.storage = EvqUniform;
+ break;
+ case EHTokConst:
+ qualifier.storage = EvqConst;
+ break;
+ default:
+ return;
+ }
+
+ advanceToken();
+}
+
+// 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)
+{
+ if (! token.isType)
+ return false;
+
+ switch (token.tokenClass) {
+ case EHTokInt:
+ case EHTokInt1:
+ case EHTokDword:
+ new(&type) TType(EbtInt);
+ break;
+ case EHTokFloat:
+ case EHTokFloat1:
+ new(&type) TType(EbtFloat);
+ break;
+
+ case EHTokFloat2:
+ new(&type) TType(EbtFloat, EvqTemporary, 2);
+ break;
+ case EHTokFloat3:
+ new(&type) TType(EbtFloat, EvqTemporary, 3);
+ break;
+ case EHTokFloat4:
+ new(&type) TType(EbtFloat, EvqTemporary, 4);
+ break;
+
+ case EHTokInt2:
+ new(&type) TType(EbtInt, EvqTemporary, 2);
+ break;
+ case EHTokInt3:
+ new(&type) TType(EbtInt, EvqTemporary, 3);
+ break;
+ case EHTokInt4:
+ new(&type) TType(EbtInt, EvqTemporary, 4);
+ break;
+
+ case EHTokBool2:
+ new(&type) TType(EbtBool, EvqTemporary, 2);
+ break;
+ case EHTokBool3:
+ new(&type) TType(EbtBool, EvqTemporary, 3);
+ break;
+ case EHTokBool4:
+ new(&type) TType(EbtBool, EvqTemporary, 4);
+ break;
+
+ case EHTokFloat2x2:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
+ break;
+ case EHTokFloat2x3:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
+ break;
+ case EHTokFloat2x4:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
+ break;
+ case EHTokFloat3x2:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
+ break;
+ case EHTokFloat3x3:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
+ break;
+ case EHTokFloat3x4:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
+ break;
+ case EHTokFloat4x2:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
+ break;
+ case EHTokFloat4x3:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
+ break;
+ case EHTokFloat4x4:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
+ break;
+
+ default:
+ return false;
+ }
+
+ advanceToken();
+
+ return true;
+}
+
+// expression
+// : identifier
+// | ( expression )
+// | type(...) // constructor
+// | literal
+// | identifier + identifier
+//
+bool HlslGrammar::acceptExpression(TIntermTyped*& node)
+{
+ // identifier
+ if (token.tokenClass == EHTokIdentifier) {
+ node = parseContext.handleVariable(token.loc, token.symbol, token.string);
+ return true;
+ }
+
+ // ( expression )
+ if (acceptTokenClass(EHTokLeftParen)) {
+ if (! acceptExpression(node)) {
+ expected("expression");
+ return false;
+ }
+ if (! acceptTokenClass(EHTokRightParen)) {
+ expected("right parenthesis");
+ return false;
+ }
+
+ return true;
+ }
+
+ // literal
+ if (acceptLiteral(node))
+ return true;
+
+ // type(...) // constructor
+ TType type;
+ if (acceptType(type)) {
+ TIntermSequence* arguments;
+ if (! acceptArguments(arguments)) {
+ expected("constructor arguments");
+ return false;
+ }
+
+ return true;
+ }
+
+ // identifier + identifier
+ if (token.tokenClass == EHTokIdentifier) {
+ TIntermTyped* left = parseContext.handleVariable(token.loc, token.symbol, token.string);
+ advanceToken();
+
+ // operator
+ TOperator op;
+ if (! acceptOperator(op))
+ return false;
+ TSourceLoc loc = token.loc;
+
+ // right
+ if (token.tokenClass == EHTokIdentifier) {
+ TIntermTyped* right = parseContext.handleVariable(token.loc, token.symbol, token.string);
+ advanceToken();
+ node = parseContext.intermediate.addBinaryMath(op, left, right, loc);
+ } else
+ return false;
+ } else
+ return false;
+
+ return true;
+}
+
+// arguments
+// : ( expression , expression, ... )
+//
+bool HlslGrammar::acceptArguments(TIntermSequence*& arguments)
+{
+ if (! acceptTokenClass(EHTokLeftParen))
+ return false;
+
+ do {
+ TIntermTyped* arg;
+ if (! acceptExpression(arg))
+ break;
+ if (! acceptTokenClass(EHTokComma))
+ break;
+ } while (true);
+
+ if (! acceptTokenClass(EHTokRightParen)) {
+ expected("right parenthesis");
+ return false;
+ }
+
+ return true;
+}
+
+bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
+{
+ switch (token.tokenClass) {
+ case EHTokIntConstant:
+ node = parseContext.intermediate.addConstantUnion(token.i, token.loc, true);
+ break;
+ case EHTokFloatConstant:
+ node = parseContext.intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
+ break;
+ case EHTokDoubleConstant:
+ node = parseContext.intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
+ break;
+ case EHTokBoolConstant:
+ node = parseContext.intermediate.addConstantUnion(token.b, token.loc, true);
+ break;
+
+ default:
+ return false;
+ }
+
advanceToken();
+
return true;
}
+bool HlslGrammar::acceptOperator(TOperator& op)
+{
+ switch (token.tokenClass) {
+ case EHTokPlus:
+ op = EOpAdd;
+ break;
+ default:
+ return false;
+ }
+
+ advanceToken();
+
+ return true;
+}
+
+bool HlslGrammar::acceptCompoundStatement()
+{
+ return false;
+}
+
} // end namespace glslang