HLSL: Add string basic type and recognize string declaration grammar.

This includes the "< decl ; decl ; >" syntax which has its own namespace.
This functionality is not implemented, just silently accepted.
diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp
index cc7e901..0762514 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -721,6 +721,54 @@
     return true;
 }
 
+// string_template_type
+//      : STRING
+//      | STRING identifier LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
+//
+bool HlslGrammar::acceptStringTemplateType(TType& type)
+{
+    // STRING
+    if (! acceptTokenClass(EHTokString))
+        return false;
+
+    // no matter what happens next, we recognized a string type
+    new(&type) TType(EbtString);
+
+    // identifier LEFT_ANGLE, or not?
+    if (! acceptTokenClass(EHTokIdentifier)) {
+        expected("identifier following 'string'");
+        return false;
+    }
+
+    if (! peekTokenClass(EHTokLeftAngle)) {
+        // then it must be the non-template version, back up and let
+        // normal declaration code handle it
+
+        // recede the identifier
+        recedeToken();
+        return true;
+    }
+
+    // move past the LEFT_ANGLE
+    advanceToken();
+
+    // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
+    do {
+        // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
+        while (acceptTokenClass(EHTokSemicolon))
+            ;
+
+        if (acceptTokenClass(EHTokRightAngle))
+            return true;
+
+        // declaration
+        TIntermNode* node;
+        if (! acceptDeclaration(node)) {
+            expected("declaration in string list");
+            return false;
+        }
+    } while (true);
+}
 
 // sampler_type
 //      : SAMPLER
@@ -894,6 +942,10 @@
         return acceptMatrixTemplateType(type);
         break;
 
+    case EHTokString:
+        return acceptStringTemplateType(type);
+        break;
+
     case EHTokSampler:                // fall through
     case EHTokSampler1d:              // ...
     case EHTokSampler2d:              // ...
@@ -2062,6 +2114,9 @@
     case EHTokBoolConstant:
         node = intermediate.addConstantUnion(token.b, token.loc, true);
         break;
+    case EHTokStringConstant:
+        node = nullptr;
+        break;
 
     default:
         return false;