HLSL: Add basic declaration syntax and AST generation.
diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp
index 9673658..bbf3c99 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -83,11 +83,308 @@
 }
 
 // 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()
 {
-    advanceToken();
+    // 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