HLSL: Add (almost) full expression grammar: Binary, unary (pre/post-fix), assign...
authorJohn Kessenich <cepheus@frii.com>
Wed, 4 May 2016 05:17:20 +0000 (23:17 -0600)
committerJohn Kessenich <cepheus@frii.com>
Wed, 4 May 2016 05:33:00 +0000 (23:33 -0600)
Test/baseResults/hlsl.frag.out
Test/hlsl.frag
hlsl/CMakeLists.txt
hlsl/hlslGrammar.cpp
hlsl/hlslGrammar.h
hlsl/hlslOpMap.cpp [new file with mode: 0755]
hlsl/hlslOpMap.h [new file with mode: 0755]
hlsl/hlslScanContext.cpp
hlsl/hlslTokenStream.h
hlsl/hlslTokens.h

index 0fae4ae..9afecf1 100644 (file)
@@ -2,23 +2,41 @@ hlsl.frag
 Shader version: 100
 gl_FragCoord origin is upper left
 0:? Sequence
-0:1  move second child to first child (temp 4-component vector of float)
-0:1    'AmbientColor' (temp 4-component vector of float)
-0:?     Constant:
-0:?       1.000000
-0:?       0.500000
-0:?       0.000000
-0:?       1.000000
-0:8  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
+0:12  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
 0:5    Function Parameters: 
 0:5      'input' (temp 4-component vector of float)
 0:?     Sequence
-0:6      Branch: Return with expression
-0:6        add (temp 4-component vector of float)
-0:6          'input' (temp 4-component vector of float)
-0:6          'AmbientColor' (temp 4-component vector of float)
+0:7      Branch: Return with expression
+0:7        add (temp 4-component vector of float)
+0:7          component-wise multiply (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7          component-wise multiply (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:8      Branch: Return with expression
+0:8        add (temp 4-component vector of float)
+0:8          add (temp 4-component vector of float)
+0:8            'input' (temp 4-component vector of float)
+0:8            component-wise multiply (temp 4-component vector of float)
+0:8              'input' (temp 4-component vector of float)
+0:8              'input' (temp 4-component vector of float)
+0:8          'input' (temp 4-component vector of float)
+0:9      Branch: Return with expression
+0:9        component-wise multiply (temp 4-component vector of float)
+0:9          Pre-Increment (temp 4-component vector of float)
+0:9            'input' (temp 4-component vector of float)
+0:9          Negate value (temp 4-component vector of float)
+0:9            Negate value (temp 4-component vector of float)
+0:9              Pre-Decrement (temp 4-component vector of float)
+0:9                'input' (temp 4-component vector of float)
+0:10      Branch: Return with expression
+0:10        add (temp 4-component vector of float)
+0:10          Post-Increment (temp 4-component vector of float)
+0:10            'input' (temp 4-component vector of float)
+0:10          Pre-Increment (temp 4-component vector of float)
+0:10            'input' (temp 4-component vector of float)
 0:?   Linker Objects
-0:?     'AmbientColor' (temp 4-component vector of float)
 
 
 Linked fragment stage:
@@ -27,27 +45,45 @@ Linked fragment stage:
 Shader version: 100
 gl_FragCoord origin is upper left
 0:? Sequence
-0:1  move second child to first child (temp 4-component vector of float)
-0:1    'AmbientColor' (temp 4-component vector of float)
-0:?     Constant:
-0:?       1.000000
-0:?       0.500000
-0:?       0.000000
-0:?       1.000000
-0:8  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
+0:12  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
 0:5    Function Parameters: 
 0:5      'input' (temp 4-component vector of float)
 0:?     Sequence
-0:6      Branch: Return with expression
-0:6        add (temp 4-component vector of float)
-0:6          'input' (temp 4-component vector of float)
-0:6          'AmbientColor' (temp 4-component vector of float)
+0:7      Branch: Return with expression
+0:7        add (temp 4-component vector of float)
+0:7          component-wise multiply (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7          component-wise multiply (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:8      Branch: Return with expression
+0:8        add (temp 4-component vector of float)
+0:8          add (temp 4-component vector of float)
+0:8            'input' (temp 4-component vector of float)
+0:8            component-wise multiply (temp 4-component vector of float)
+0:8              'input' (temp 4-component vector of float)
+0:8              'input' (temp 4-component vector of float)
+0:8          'input' (temp 4-component vector of float)
+0:9      Branch: Return with expression
+0:9        component-wise multiply (temp 4-component vector of float)
+0:9          Pre-Increment (temp 4-component vector of float)
+0:9            'input' (temp 4-component vector of float)
+0:9          Negate value (temp 4-component vector of float)
+0:9            Negate value (temp 4-component vector of float)
+0:9              Pre-Decrement (temp 4-component vector of float)
+0:9                'input' (temp 4-component vector of float)
+0:10      Branch: Return with expression
+0:10        add (temp 4-component vector of float)
+0:10          Post-Increment (temp 4-component vector of float)
+0:10            'input' (temp 4-component vector of float)
+0:10          Pre-Increment (temp 4-component vector of float)
+0:10            'input' (temp 4-component vector of float)
 0:?   Linker Objects
-0:?     'AmbientColor' (temp 4-component vector of float)
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 15
+// Id's are bound by 45
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
@@ -57,18 +93,21 @@ gl_FragCoord origin is upper left
                               Source HLSL 100
                               Name 4  "PixelShaderFunction"
                               Name 9  "input"
-                              Name 11  "AmbientColor"
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeFloat 32
                7:             TypeVector 6(float) 4
                8:             TypePointer Function 7(fvec4)
+              27:    6(float) Constant 1065353216
 4(PixelShaderFunction):           2 Function None 3
                5:             Label
         9(input):      8(ptr) Variable Function
-11(AmbientColor):      8(ptr) Variable Function
               10:    7(fvec4) Load 9(input)
-              12:    7(fvec4) Load 11(AmbientColor)
-              13:    7(fvec4) FAdd 10 12
-                              ReturnValue 13
+              11:    7(fvec4) Load 9(input)
+              12:    7(fvec4) FMul 10 11
+              13:    7(fvec4) Load 9(input)
+              14:    7(fvec4) Load 9(input)
+              15:    7(fvec4) FMul 13 14
+              16:    7(fvec4) FAdd 12 15
+                              ReturnValue 16
                               FunctionEnd
index 7ee5849..ac6aa23 100644 (file)
@@ -1,7 +1,11 @@
-float4 AmbientColor = float4(1, 0.5, 0, 1);
+//float4 AmbientColor = float4(1, 0.5, 0, 1);
 //float AmbientIntensity = 0.1;
 
 float4 PixelShaderFunction(float4 input) : COLOR0
 {
-    return input /* * AmbientIntensity */ + AmbientColor;
+//    return input * AmbientIntensity + AmbientColor;
+    return input * input + input * input;
+    return input + input * input + input;
+    return ++input * -+-+--input;
+    return input++ + ++input;
 }
index 96028f6..6dd84fa 100755 (executable)
@@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8)
 set(SOURCES
     hlslParseHelper.cpp
     hlslScanContext.cpp
+    hlslOpMap.cpp
     hlslTokenStream.cpp
     hlslGrammar.cpp)
 
@@ -10,6 +11,7 @@ set(HEADERS
     hlslParseHelper.h
     hlslTokens.h
     hlslScanContext.h
+    hlslOpMap.h
     hlslTokenStream.h
     hlslGrammar.h)
 
index 40c35ca..2339c2d 100755 (executable)
@@ -129,7 +129,7 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
     if (acceptIdentifier(idToken)) {
         // = expression
         TIntermTyped* expressionNode = nullptr;
-        if (acceptTokenClass(EHTokEqual)) {
+        if (acceptTokenClass(EHTokAssign)) {
             if (! acceptExpression(expressionNode)) {
                 expected("initializer");
                 return false;
@@ -362,36 +362,171 @@ bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& no
     return false;
 }
 
+// The top-level full expression recognizer.
+//
 // expression
-//      : identifier
-//      | identifier operator identifier       // todo: generalize to all expressions
-//      | LEFT_PAREN expression RIGHT_PAREN
-//      | constructor
-//      | literal
+//      : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
 //
 bool HlslGrammar::acceptExpression(TIntermTyped*& node)
 {
-    // identifier
-    HlslToken idToken;
-    if (acceptIdentifier(idToken)) {
-        TIntermTyped* left = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
+    // assignment_expression
+    if (! acceptAssignmentExpression(node))
+        return false;
 
-        // operator?
-        TOperator op;
-        if (! acceptOperator(op))
-            return true;
+    if (! peekTokenClass(EHTokComma))
+        return true;
+
+    do {
+        // ... COMMA
         TSourceLoc loc = token.loc;
+        advanceToken();
 
-        // identifier
-        if (acceptIdentifier(idToken)) {
-            TIntermTyped* right = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
-            node = intermediate.addBinaryMath(op, left, right, loc);
-            return true;
+        // ... assignment_expression
+        TIntermTyped* rightNode = nullptr;
+        if (! acceptAssignmentExpression(rightNode)) {
+            expected("assignment expression");
+            return false;
         }
 
+        node = intermediate.addComma(node, rightNode, loc);
+
+        if (! peekTokenClass(EHTokComma))
+            return true;
+    } while (true);
+}
+
+// Accept an assignment expression, where assignment operations
+// associate right-to-left.  This is, it is implicit, for example
+//
+//    a op (b op (c op d))
+//
+// assigment_expression
+//      : binary_expression op binary_expression op binary_expression ...
+//
+bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
+{
+    if (! acceptBinaryExpression(node, PlLogicalOr))
+        return false;
+
+    TOperator assignOp = HlslOpMap::assignment(peek());
+    if (assignOp == EOpNull)
+        return true;
+
+    // ... op
+    TSourceLoc loc = token.loc;
+    advanceToken();
+
+    // ... binary_expression
+    // But, done by recursing this function, which automatically
+    // gets the right-to-left associativity.
+    TIntermTyped* rightNode = nullptr;
+    if (! acceptAssignmentExpression(rightNode)) {
+        expected("assignment expression");
         return false;
     }
 
+    node = intermediate.addAssign(assignOp, node, rightNode, loc);
+
+    if (! peekTokenClass(EHTokComma))
+        return true;
+
+    return true;
+}
+
+// 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)
+{
+    if (precedenceLevel > PlMul)
+        return acceptUnaryExpression(node);
+
+    // assignment_expression
+    if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
+        return false;
+
+    TOperator op = HlslOpMap::binary(peek());
+    PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
+    if (tokenLevel < precedenceLevel)
+        return true;
+
+    do {
+        // ... op
+        TSourceLoc loc = token.loc;
+        advanceToken();
+
+        // ... expression
+        TIntermTyped* rightNode = nullptr;
+        if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
+            expected("expression");
+            return false;
+        }
+
+        node = intermediate.addBinaryMath(op, node, rightNode, loc);
+
+        if (! peekTokenClass(EHTokComma))
+            return true;
+    } while (true);
+}
+
+// unary_expression
+//      : + unary_expression
+//      | - unary_expression
+//      | ! unary_expression
+//      | ~ unary_expression
+//      | ++ unary_expression
+//      | -- unary_expression
+//      | postfix_expression
+//
+bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
+{
+    TOperator unaryOp = HlslOpMap::preUnary(peek());
+    
+    // postfix_expression
+    if (unaryOp == EOpNull)
+        return acceptPostfixExpression(node);
+
+    // op unary_expression
+    TSourceLoc loc = token.loc;
+    advanceToken();
+    if (! acceptUnaryExpression(node))
+        return false;
+
+    // + is a no-op
+    if (unaryOp == EOpAdd)
+        return true;
+
+    node = intermediate.addUnaryMath(unaryOp, node, loc);
+
+    return node != nullptr;
+}
+
+// postfix_expression
+//      : LEFT_PAREN expression RIGHT_PAREN
+//      | literal
+//      | constructor
+//      | identifier
+//      | function_call
+//      | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
+//      | postfix_expression DOT IDENTIFIER
+//      | postfix_expression INC_OP
+//      | postfix_expression DEC_OP
+//
+bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
+{
+    // Not implemented as self-recursive:
+    // The logical "right recursion" is done with an loop at the end
+
+    // idToken will pick up either a variable or a function name in a function call
+    HlslToken idToken;
+
     // LEFT_PAREN expression RIGHT_PAREN
     if (acceptTokenClass(EHTokLeftParen)) {
         if (! acceptExpression(node)) {
@@ -402,19 +537,62 @@ bool HlslGrammar::acceptExpression(TIntermTyped*& node)
             expected("right parenthesis");
             return false;
         }
-
-        return true;
+    } else if (acceptLiteral(node)) {
+        // literal (nothing else to do yet), go on to the 
+    } else if (acceptConstructor(node)) {
+        // constructor (nothing else to do yet)
+    } else if (acceptIdentifier(idToken)) {
+        // identifier or function_call name
+        if (! peekTokenClass(EHTokLeftParen)) {
+            node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
+        } else if (acceptFunctionCall(idToken, node)) {
+            // function_call (nothing else to do yet)
+        } else {
+            expected("function call arguments");
+            return false;
+        }
     }
 
-    // literal
-    if (acceptLiteral(node))
-        return true;
-
-    // constructor
-    if (acceptConstructor(node))
-        return true;
+    do {
+        TSourceLoc loc = token.loc;
+        TOperator postOp = HlslOpMap::postUnary(peek());
+
+        // Consume only a valid post-unary operator, otherwise we are done.
+        switch (postOp) {
+        case EOpIndexDirectStruct:
+        case EOpIndexIndirect:
+        case EOpPostIncrement:
+        case EOpPostDecrement:
+            advanceToken();
+            break;
+        default:
+            return true;
+        }
 
-    return false;
+        // We have a valid post-unary operator, process it.
+        switch (postOp) {
+        case EOpIndexDirectStruct:
+            // todo
+            break;
+        case EOpIndexIndirect:
+        {
+            TIntermTyped* indexNode = nullptr;
+            if (! acceptExpression(indexNode) ||
+                ! peekTokenClass(EHTokRightBracket)) {
+                expected("expression followed by ']'");
+                return false;
+            }
+            // todo:      node = intermediate.addBinaryMath(
+        }
+        case EOpPostIncrement:
+        case EOpPostDecrement:
+            node = intermediate.addUnaryMath(postOp, node, loc);
+            break;
+        default:
+            assert(0);
+            break;
+        }
+    } while (true);
 }
 
 // constructor
@@ -445,6 +623,17 @@ bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
     return false;
 }
 
+// The function_call identifier was already recognized, and passed in as idToken.
+//
+// function_call
+//      : [idToken] arguments
+//
+bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*&)
+{
+    // todo
+    return false;
+}
+
 // arguments
 //      : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
 //
@@ -505,41 +694,12 @@ bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
     return true;
 }
 
-// operator
-//      : PLUS | DASH | STAR | SLASH | ...
-bool HlslGrammar::acceptOperator(TOperator& op)
-{
-    switch (token.tokenClass) {
-    case EHTokEqual:
-        op = EOpAssign;
-        break;
-    case EHTokPlus:
-        op = EOpAdd;
-        break;
-    case EHTokDash:
-        op = EOpSub;
-        break;
-    case EHTokStar:
-        op = EOpMul;
-        break;
-    case EHTokSlash:
-        op = EOpDiv;
-        break;
-    default:
-        return false;
-    }
-
-    advanceToken();
-
-    return true;
-}
-
 // compound_statement
-//      : { statement statement ... }
+//      : LEFT_CURLY statement statement ... RIGHT_CURLY
 //
 bool HlslGrammar::acceptCompoundStatement(TIntermAggregate*& compoundStatement)
 {
-    // {
+    // LEFT_CURLY
     if (! acceptTokenClass(EHTokLeftBrace))
         return false;
 
@@ -549,9 +709,10 @@ bool HlslGrammar::acceptCompoundStatement(TIntermAggregate*& compoundStatement)
         // hook it up
         compoundStatement = intermediate.growAggregate(compoundStatement, statement);
     }
-    compoundStatement->setOperator(EOpSequence);
+    if (compoundStatement)
+        compoundStatement->setOperator(EOpSequence);
 
-    // }
+    // RIGHT_CURLY
     return acceptTokenClass(EHTokRightBrace);
 }
 
index 8b9b289..61d30af 100755 (executable)
@@ -37,6 +37,7 @@
 #define HLSLGRAMMAR_H_
 
 #include "hlslParseHelper.h"
+#include "hlslOpMap.h"
 #include "hlslTokenStream.h"
 
 namespace glslang {
@@ -64,10 +65,14 @@ namespace glslang {
         bool acceptParameterDeclaration(TFunction&);
         bool acceptFunctionDefinition(TFunction&, TIntermNode*&);
         bool acceptExpression(TIntermTyped*&);
+        bool acceptAssignmentExpression(TIntermTyped*&);
+        bool acceptBinaryExpression(TIntermTyped*&, PrecedenceLevel);
+        bool acceptUnaryExpression(TIntermTyped*&);
+        bool acceptPostfixExpression(TIntermTyped*&);
         bool acceptConstructor(TIntermTyped*&);
+        bool acceptFunctionCall(HlslToken, TIntermTyped*&);
         bool acceptArguments(TFunction*, TIntermAggregate*&);
         bool acceptLiteral(TIntermTyped*&);
-        bool acceptOperator(TOperator& op);
         bool acceptCompoundStatement(TIntermAggregate*&);
         bool acceptStatement(TIntermNode*&);
         bool acceptSemantic();
diff --git a/hlsl/hlslOpMap.cpp b/hlsl/hlslOpMap.cpp
new file mode 100755 (executable)
index 0000000..c31dd7c
--- /dev/null
@@ -0,0 +1,171 @@
+//
+//Copyright (C) 2016 Google, Inc.
+//
+//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.
+//
+
+// Map from physical token form (e.g. '-') to logical operator
+// form (e.g., binary subtract or unary negate).
+
+#include "hlslOpMap.h"
+
+namespace glslang {
+
+// Map parsing tokens that could be assignments into assignment operators.
+TOperator HlslOpMap::assignment(EHlslTokenClass op)
+{
+    switch (op) {
+    case EHTokAssign:      return EOpAssign;
+    case EHTokMulAssign:   return EOpMulAssign;
+    case EHTokDivAssign:   return EOpDivAssign;
+    case EHTokAddAssign:   return EOpAddAssign;
+    case EHTokModAssign:   return EOpModAssign;
+    case EHTokLeftAssign:  return EOpLeftShiftAssign;
+    case EHTokRightAssign: return EOpRightShiftAssign;
+    case EHTokAndAssign:   return EOpAndAssign;
+    case EHTokXorAssign:   return EOpExclusiveOrAssign;
+    case EHTokOrAssign:    return EOpInclusiveOrAssign;
+    case EHTokSubAssign:   return EOpSubAssign;
+
+    default:
+        return EOpNull;
+    }
+}
+
+// Map parsing tokens that could be binary operations into binary operators.
+TOperator HlslOpMap::binary(EHlslTokenClass op)
+{
+    switch (op) {
+    case EHTokPlus:        return EOpAdd;
+    case EHTokDash:        return EOpSub;
+    case EHTokStar:        return EOpMul;
+    case EHTokSlash:       return EOpDiv;
+    case EHTokPercent:     return EOpMod;
+    case EHTokRightOp:     return EOpRightShift;
+    case EHTokLeftOp:      return EOpLeftShift;
+    case EHTokAmpersand:   return EOpAnd;
+    case EHTokVerticalBar: return EOpInclusiveOr;
+    case EHTokCaret:       return EOpExclusiveOr;
+    case EHTokEqOp:        return EOpEqual;
+    case EHTokNeOp:        return EOpNotEqual;
+    case EHTokLeftAngle:   return EOpLessThan;
+    case EHTokRightAngle:  return EOpGreaterThan;
+    case EHTokLeOp:        return EOpLessThanEqual;
+    case EHTokGeOp:        return EOpGreaterThanEqual;
+    case EHTokOrOp:        return EOpLogicalOr;
+    case EHTokXorOp:       return EOpLogicalXor;
+    case EHTokAndOp:       return EOpLogicalAnd;
+
+    default:
+        return EOpNull;
+    }
+}
+
+// Map parsing tokens that could be unary operations into unary operators.
+// These are just the ones that can appear in front of its operand.
+TOperator HlslOpMap::preUnary(EHlslTokenClass op)
+{
+    switch (op) {
+    case EHTokPlus:       return EOpAdd;        // means no-op, but still a unary op was present
+    case EHTokDash:       return EOpNegative;
+    case EHTokBang:       return EOpLogicalNot;
+    case EHTokTilde:      return EOpBitwiseNot;
+    
+    case EHTokIncOp:      return EOpPreIncrement;
+    case EHTokDecOp:      return EOpPreDecrement;
+
+    default:              return EOpNull;       // means not a pre-unary op
+    }
+}
+
+// Map parsing tokens that could be unary operations into unary operators.
+// These are just the ones that can appear behind its operand.
+TOperator HlslOpMap::postUnary(EHlslTokenClass op)
+{
+    switch (op) {
+    case EHTokDot:         return EOpIndexDirectStruct;
+    case EHTokLeftBracket: return EOpIndexIndirect;   // may need to change later to EOpIndexDirect
+    
+    case EHTokIncOp:       return EOpPostIncrement;
+    case EHTokDecOp:       return EOpPostDecrement;
+
+    default:               return EOpNull;             // means not a post-unary op
+    }
+}
+
+// Map operators into their level of precedence.
+PrecedenceLevel HlslOpMap::precedenceLevel(TOperator op)
+{
+    switch (op) {
+    case EOpLogicalOr:
+        return PlLogicalOr;
+    case EOpLogicalXor:
+        return PlLogicalXor;
+    case EOpLogicalAnd:
+        return PlLogicalAnd;
+
+    case EOpInclusiveOr:
+        return PlBitwiseOr;
+    case EOpExclusiveOr:
+        return PlBitwiseXor;
+    case EOpAnd:
+        return PlBitwiseAnd;
+
+    case EOpEqual:
+    case EOpNotEqual:
+        return PlEquality;
+
+    case EOpLessThan:
+    case EOpGreaterThan:
+    case EOpLessThanEqual:
+    case EOpGreaterThanEqual:
+        return PlRelational;
+
+    case EOpRightShift:
+    case EOpLeftShift:
+        return PlShift;
+
+    case EOpAdd:
+    case EOpSub:
+        return PlAdd;
+
+    case EOpMul:
+    case EOpDiv:
+    case EOpMod:
+        return PlMul;
+
+    default:
+        return PlBad;
+    }
+}
+
+} // end namespace glslang
diff --git a/hlsl/hlslOpMap.h b/hlsl/hlslOpMap.h
new file mode 100755 (executable)
index 0000000..9246378
--- /dev/null
@@ -0,0 +1,69 @@
+//
+//Copyright (C) 2016 Google, Inc.
+//
+//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.
+//
+
+#ifndef HLSLOPMAP_H_
+#define HLSLOPMAP_H_
+
+#include "hlslScanContext.h"
+
+namespace glslang {
+
+    enum PrecedenceLevel {
+        PlBad,
+        PlLogicalOr,
+        PlLogicalXor,
+        PlLogicalAnd,
+        PlBitwiseOr,
+        PlBitwiseXor,
+        PlBitwiseAnd,
+        PlEquality,
+        PlRelational,
+        PlShift,
+        PlAdd,
+        PlMul
+    };
+
+    class HlslOpMap {
+    public:
+        static TOperator assignment(EHlslTokenClass op);
+        static TOperator binary(EHlslTokenClass op);
+        static TOperator preUnary(EHlslTokenClass op);
+        static TOperator postUnary(EHlslTokenClass op);
+        static PrecedenceLevel precedenceLevel(TOperator);
+    };
+
+} // end namespace glslang
+
+#endif // HLSLOPMAP_H_
index 50277cf..ab96bad 100755 (executable)
@@ -309,7 +309,7 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token)
         case ';':  afterType = false;   return EHTokSemicolon;
         case ',':  afterType = false;   return EHTokComma;
         case ':':                       return EHTokColon;
-        case '=':  afterType = false;   return EHTokEqual;
+        case '=':  afterType = false;   return EHTokAssign;
         case '(':  afterType = false;   return EHTokLeftParen;
         case ')':  afterType = false;   return EHTokRightParen;
         case '.':  field = true;        return EHTokDot;
index 4fad814..9139df0 100755 (executable)
@@ -42,7 +42,7 @@ namespace glslang {
 
     class HlslTokenStream {
     public:
-        HlslTokenStream(HlslScanContext& scanner)
+        explicit HlslTokenStream(HlslScanContext& scanner)
             : scanner(scanner) { }
         virtual ~HlslTokenStream() { }
 
index b118f2e..bc472fe 100755 (executable)
@@ -207,6 +207,7 @@ enum EHlslTokenClass {
     EHTokAndOp,
     EHTokOrOp,
     EHTokXorOp,
+    EHTokAssign,
     EHTokMulAssign,
     EHTokDivAssign,
     EHTokAddAssign,
@@ -226,7 +227,6 @@ enum EHlslTokenClass {
     EHTokDot,
     EHTokComma,
     EHTokColon,
-    EHTokEqual,
     EHTokSemicolon,
     EHTokBang,
     EHTokDash,