HLSL: Flesh out the loop grammar and productions.
authorJohn Kessenich <cepheus@frii.com>
Sun, 5 Jun 2016 21:44:07 +0000 (15:44 -0600)
committerJohn Kessenich <cepheus@frii.com>
Sun, 5 Jun 2016 21:44:07 +0000 (15:44 -0600)
Test/baseResults/hlsl.doLoop.frag.out [new file with mode: 0755]
Test/baseResults/hlsl.forLoop.frag.out [new file with mode: 0755]
Test/baseResults/hlsl.whileLoop.frag.out [new file with mode: 0755]
Test/hlsl.doLoop.frag [new file with mode: 0644]
Test/hlsl.forLoop.frag [new file with mode: 0644]
Test/hlsl.whileLoop.frag [new file with mode: 0644]
glslang/MachineIndependent/Intermediate.cpp
glslang/MachineIndependent/localintermediate.h
gtests/Hlsl.FromFile.cpp
hlsl/hlslGrammar.cpp
hlsl/hlslParseHelper.h

diff --git a/Test/baseResults/hlsl.doLoop.frag.out b/Test/baseResults/hlsl.doLoop.frag.out
new file mode 100755 (executable)
index 0000000..eed2d91
--- /dev/null
@@ -0,0 +1,116 @@
+hlsl.doLoop.frag
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:7  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
+0:2    Function Parameters: 
+0:2      'input' (temp 4-component vector of float)
+0:?     Sequence
+0:3      Loop with condition not tested first
+0:3        Loop Condition
+0:3        Constant:
+0:3          false (const bool)
+0:3        No loop body
+0:4      Loop with condition not tested first
+0:4        Loop Condition
+0:4        Constant:
+0:4          false (const bool)
+0:4        No loop body
+0:5      Loop with condition not tested first
+0:5        Loop Condition
+0:5        Compare Equal (temp bool)
+0:5          'input' (temp 4-component vector of float)
+0:5          'input' (temp 4-component vector of float)
+0:5        Loop Body
+0:5        Branch: Return with expression
+0:5          'input' (temp 4-component vector of float)
+0:?   Linker Objects
+
+
+Linked fragment stage:
+
+
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:7  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
+0:2    Function Parameters: 
+0:2      'input' (temp 4-component vector of float)
+0:?     Sequence
+0:3      Loop with condition not tested first
+0:3        Loop Condition
+0:3        Constant:
+0:3          false (const bool)
+0:3        No loop body
+0:4      Loop with condition not tested first
+0:4        Loop Condition
+0:4        Constant:
+0:4          false (const bool)
+0:4        No loop body
+0:5      Loop with condition not tested first
+0:5        Loop Condition
+0:5        Compare Equal (temp bool)
+0:5          'input' (temp 4-component vector of float)
+0:5          'input' (temp 4-component vector of float)
+0:5        Loop Body
+0:5        Branch: Return with expression
+0:5          'input' (temp 4-component vector of float)
+0:?   Linker Objects
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 31
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "PixelShaderFunction"
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 450
+                              Name 4  "PixelShaderFunction"
+                              Name 23  "input"
+               2:             TypeVoid
+               3:             TypeFunction 2
+              10:             TypeBool
+              11:    10(bool) ConstantFalse
+              20:             TypeFloat 32
+              21:             TypeVector 20(float) 4
+              22:             TypePointer Function 21(fvec4)
+              28:             TypeVector 10(bool) 4
+4(PixelShaderFunction):           2 Function None 3
+               5:             Label
+       23(input):     22(ptr) Variable Function
+                              Branch 6
+               6:             Label
+                              LoopMerge 8 9 None
+                              Branch 7
+               7:             Label
+                              Branch 9
+               9:             Label
+                              BranchConditional 11 6 8
+               8:             Label
+                              Branch 12
+              12:             Label
+                              LoopMerge 14 15 None
+                              Branch 13
+              13:             Label
+                              Branch 15
+              15:             Label
+                              BranchConditional 11 12 14
+              14:             Label
+                              Branch 16
+              16:             Label
+                              LoopMerge 18 19 None
+                              Branch 17
+              17:             Label
+              24:   21(fvec4) Load 23(input)
+                              ReturnValue 24
+              19:             Label
+              26:   21(fvec4) Load 23(input)
+              27:   21(fvec4) Load 23(input)
+              29:   28(bvec4) FOrdEqual 26 27
+              30:    10(bool) All 29
+                              BranchConditional 30 16 18
+              18:             Label
+                              Return
+                              FunctionEnd
diff --git a/Test/baseResults/hlsl.forLoop.frag.out b/Test/baseResults/hlsl.forLoop.frag.out
new file mode 100755 (executable)
index 0000000..2e654e1
--- /dev/null
@@ -0,0 +1,220 @@
+hlsl.forLoop.frag
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:9  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
+0:2    Function Parameters: 
+0:2      'input' (temp 4-component vector of float)
+0:?     Sequence
+0:?       Sequence
+0:3        Loop with condition tested first
+0:3          No loop condition
+0:3          No loop body
+0:4      Sequence
+0:4        Pre-Increment (temp 4-component vector of float)
+0:4          'input' (temp 4-component vector of float)
+0:4        Loop with condition tested first
+0:4          No loop condition
+0:4          No loop body
+0:?       Sequence
+0:5        Loop with condition tested first
+0:5          Loop Condition
+0:5          Compare Not Equal (temp bool)
+0:5            'input' (temp 4-component vector of float)
+0:5            'input' (temp 4-component vector of float)
+0:5          No loop body
+0:?       Sequence
+0:6        Loop with condition tested first
+0:6          Loop Condition
+0:6          Compare Not Equal (temp bool)
+0:6            'input' (temp 4-component vector of float)
+0:6            'input' (temp 4-component vector of float)
+0:6          Loop Body
+0:?           Sequence
+0:6            Branch: Return with expression
+0:6              Negate value (temp 4-component vector of float)
+0:6                'input' (temp 4-component vector of float)
+0:7      Sequence
+0:7        Pre-Decrement (temp 4-component vector of float)
+0:7          'input' (temp 4-component vector of float)
+0:7        Loop with condition tested first
+0:7          Loop Condition
+0:7          Compare Not Equal (temp bool)
+0:7            'input' (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7          Loop Body
+0:?           Sequence
+0:7            Branch: Return with expression
+0:7              Negate value (temp 4-component vector of float)
+0:7                'input' (temp 4-component vector of float)
+0:7          Loop Terminal Expression
+0:7          add second child into first child (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7            Constant:
+0:7              2.000000
+0:?   Linker Objects
+
+
+Linked fragment stage:
+
+
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:9  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
+0:2    Function Parameters: 
+0:2      'input' (temp 4-component vector of float)
+0:?     Sequence
+0:?       Sequence
+0:3        Loop with condition tested first
+0:3          No loop condition
+0:3          No loop body
+0:4      Sequence
+0:4        Pre-Increment (temp 4-component vector of float)
+0:4          'input' (temp 4-component vector of float)
+0:4        Loop with condition tested first
+0:4          No loop condition
+0:4          No loop body
+0:?       Sequence
+0:5        Loop with condition tested first
+0:5          Loop Condition
+0:5          Compare Not Equal (temp bool)
+0:5            'input' (temp 4-component vector of float)
+0:5            'input' (temp 4-component vector of float)
+0:5          No loop body
+0:?       Sequence
+0:6        Loop with condition tested first
+0:6          Loop Condition
+0:6          Compare Not Equal (temp bool)
+0:6            'input' (temp 4-component vector of float)
+0:6            'input' (temp 4-component vector of float)
+0:6          Loop Body
+0:?           Sequence
+0:6            Branch: Return with expression
+0:6              Negate value (temp 4-component vector of float)
+0:6                'input' (temp 4-component vector of float)
+0:7      Sequence
+0:7        Pre-Decrement (temp 4-component vector of float)
+0:7          'input' (temp 4-component vector of float)
+0:7        Loop with condition tested first
+0:7          Loop Condition
+0:7          Compare Not Equal (temp bool)
+0:7            'input' (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7          Loop Body
+0:?           Sequence
+0:7            Branch: Return with expression
+0:7              Negate value (temp 4-component vector of float)
+0:7                'input' (temp 4-component vector of float)
+0:7          Loop Terminal Expression
+0:7          add second child into first child (temp 4-component vector of float)
+0:7            'input' (temp 4-component vector of float)
+0:7            Constant:
+0:7              2.000000
+0:?   Linker Objects
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 64
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "PixelShaderFunction"
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 450
+                              Name 4  "PixelShaderFunction"
+                              Name 13  "input"
+               2:             TypeVoid
+               3:             TypeFunction 2
+              10:             TypeFloat 32
+              11:             TypeVector 10(float) 4
+              12:             TypePointer Function 11(fvec4)
+              15:   10(float) Constant 1065353216
+              29:             TypeBool
+              30:             TypeVector 29(bool) 4
+              60:   10(float) Constant 1073741824
+4(PixelShaderFunction):           2 Function None 3
+               5:             Label
+       13(input):     12(ptr) Variable Function
+                              Branch 6
+               6:             Label
+                              LoopMerge 8 9 None
+                              Branch 7
+               7:             Label
+                              Branch 9
+               9:             Label
+                              Branch 6
+               8:             Label
+              14:   11(fvec4) Load 13(input)
+              16:   11(fvec4) CompositeConstruct 15 15 15 15
+              17:   11(fvec4) FAdd 14 16
+                              Store 13(input) 17
+                              Branch 18
+              18:             Label
+                              LoopMerge 20 21 None
+                              Branch 19
+              19:             Label
+                              Branch 21
+              21:             Label
+                              Branch 18
+              20:             Label
+                              Branch 22
+              22:             Label
+                              LoopMerge 24 25 None
+                              Branch 26
+              26:             Label
+              27:   11(fvec4) Load 13(input)
+              28:   11(fvec4) Load 13(input)
+              31:   30(bvec4) FOrdNotEqual 27 28
+              32:    29(bool) Any 31
+                              BranchConditional 32 23 24
+              23:               Label
+                                Branch 25
+              25:               Label
+                                Branch 22
+              24:             Label
+                              Branch 33
+              33:             Label
+                              LoopMerge 35 36 None
+                              Branch 37
+              37:             Label
+              38:   11(fvec4) Load 13(input)
+              39:   11(fvec4) Load 13(input)
+              40:   30(bvec4) FOrdNotEqual 38 39
+              41:    29(bool) Any 40
+                              BranchConditional 41 34 35
+              34:               Label
+              42:   11(fvec4)   Load 13(input)
+              43:   11(fvec4)   FNegate 42
+                                ReturnValue 43
+              36:               Label
+                                Branch 33
+              35:             Label
+              45:   11(fvec4) Load 13(input)
+              46:   11(fvec4) CompositeConstruct 15 15 15 15
+              47:   11(fvec4) FSub 45 46
+                              Store 13(input) 47
+                              Branch 48
+              48:             Label
+                              LoopMerge 50 51 None
+                              Branch 52
+              52:             Label
+              53:   11(fvec4) Load 13(input)
+              54:   11(fvec4) Load 13(input)
+              55:   30(bvec4) FOrdNotEqual 53 54
+              56:    29(bool) Any 55
+                              BranchConditional 56 49 50
+              49:               Label
+              57:   11(fvec4)   Load 13(input)
+              58:   11(fvec4)   FNegate 57
+                                ReturnValue 58
+              51:               Label
+              61:   11(fvec4)   Load 13(input)
+              62:   11(fvec4)   CompositeConstruct 60 60 60 60
+              63:   11(fvec4)   FAdd 61 62
+                                Store 13(input) 63
+                                Branch 48
+              50:             Label
+                              Return
+                              FunctionEnd
diff --git a/Test/baseResults/hlsl.whileLoop.frag.out b/Test/baseResults/hlsl.whileLoop.frag.out
new file mode 100755 (executable)
index 0000000..686407b
--- /dev/null
@@ -0,0 +1,145 @@
+hlsl.whileLoop.frag
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:8  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
+0:2    Function Parameters: 
+0:2      'input' (temp 4-component vector of float)
+0:?     Sequence
+0:3      Loop with condition tested first
+0:3        Loop Condition
+0:3        Compare Not Equal (temp bool)
+0:3          'input' (temp 4-component vector of float)
+0:3          'input' (temp 4-component vector of float)
+0:3        Loop Body
+0:?         Sequence
+0:3          Branch: Return with expression
+0:3            'input' (temp 4-component vector of float)
+0:4      Loop with condition tested first
+0:4        Loop Condition
+0:4        Constant:
+0:4          false (const bool)
+0:4        No loop body
+0:5      Loop with condition tested first
+0:5        Loop Condition
+0:5        Constant:
+0:5          false (const bool)
+0:5        No loop body
+0:6      Loop with condition tested first
+0:6        Loop Condition
+0:6        Constant:
+0:6          false (const bool)
+0:6        No loop body
+0:?   Linker Objects
+
+
+Linked fragment stage:
+
+
+Shader version: 450
+gl_FragCoord origin is upper left
+0:? Sequence
+0:8  Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float)
+0:2    Function Parameters: 
+0:2      'input' (temp 4-component vector of float)
+0:?     Sequence
+0:3      Loop with condition tested first
+0:3        Loop Condition
+0:3        Compare Not Equal (temp bool)
+0:3          'input' (temp 4-component vector of float)
+0:3          'input' (temp 4-component vector of float)
+0:3        Loop Body
+0:?         Sequence
+0:3          Branch: Return with expression
+0:3            'input' (temp 4-component vector of float)
+0:4      Loop with condition tested first
+0:4        Loop Condition
+0:4        Constant:
+0:4          false (const bool)
+0:4        No loop body
+0:5      Loop with condition tested first
+0:5        Loop Condition
+0:5        Constant:
+0:5          false (const bool)
+0:5        No loop body
+0:6      Loop with condition tested first
+0:6        Loop Condition
+0:6        Constant:
+0:6          false (const bool)
+0:6        No loop body
+0:?   Linker Objects
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 39
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "PixelShaderFunction"
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 450
+                              Name 4  "PixelShaderFunction"
+                              Name 14  "input"
+               2:             TypeVoid
+               3:             TypeFunction 2
+              11:             TypeFloat 32
+              12:             TypeVector 11(float) 4
+              13:             TypePointer Function 12(fvec4)
+              17:             TypeBool
+              18:             TypeVector 17(bool) 4
+              28:    17(bool) ConstantFalse
+4(PixelShaderFunction):           2 Function None 3
+               5:             Label
+       14(input):     13(ptr) Variable Function
+                              Branch 6
+               6:             Label
+                              LoopMerge 8 9 None
+                              Branch 10
+              10:             Label
+              15:   12(fvec4) Load 14(input)
+              16:   12(fvec4) Load 14(input)
+              19:   18(bvec4) FOrdNotEqual 15 16
+              20:    17(bool) Any 19
+                              BranchConditional 20 7 8
+               7:               Label
+              21:   12(fvec4)   Load 14(input)
+                                ReturnValue 21
+               9:               Label
+                                Branch 6
+               8:             Label
+                              Branch 23
+              23:             Label
+                              LoopMerge 25 26 None
+                              Branch 27
+              27:             Label
+                              BranchConditional 28 24 25
+              24:               Label
+                                Branch 26
+              26:               Label
+                                Branch 23
+              25:             Label
+                              Branch 29
+              29:             Label
+                              LoopMerge 31 32 None
+                              Branch 33
+              33:             Label
+                              BranchConditional 28 30 31
+              30:               Label
+                                Branch 32
+              32:               Label
+                                Branch 29
+              31:             Label
+                              Branch 34
+              34:             Label
+                              LoopMerge 36 37 None
+                              Branch 38
+              38:             Label
+                              BranchConditional 28 35 36
+              35:               Label
+                                Branch 37
+              37:               Label
+                                Branch 34
+              36:             Label
+                              Return
+                              FunctionEnd
diff --git a/Test/hlsl.doLoop.frag b/Test/hlsl.doLoop.frag
new file mode 100644 (file)
index 0000000..546b2c2
--- /dev/null
@@ -0,0 +1,6 @@
+float4 PixelShaderFunction(float4 input) : COLOR0
+{
+    [unroll] do {} while (false);
+    [unroll] do {;} while (false);
+    do { return input; } while (input == input);
+}
diff --git a/Test/hlsl.forLoop.frag b/Test/hlsl.forLoop.frag
new file mode 100644 (file)
index 0000000..9109de7
--- /dev/null
@@ -0,0 +1,8 @@
+float4 PixelShaderFunction(float4 input) : COLOR0
+{
+    for (;;) ;
+    for (++input; ; ) ;
+    [unroll] for (; input != input; ) {}
+    for (; input != input; ) { return -input; }
+    for (--input; input != input; input += 2) { return -input; }
+}
diff --git a/Test/hlsl.whileLoop.frag b/Test/hlsl.whileLoop.frag
new file mode 100644 (file)
index 0000000..f282375
--- /dev/null
@@ -0,0 +1,7 @@
+float4 PixelShaderFunction(float4 input) : COLOR0
+{
+    while (input != input) { return input; }
+    while (false) ;
+    [unroll] while (false) { }
+    while ((false)) { }
+}
index 416dc34..02681ac 100644 (file)
@@ -1028,7 +1028,7 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool
 }
 
 //
-// Create loop nodes.
+// Create while and do-while loop nodes.
 //
 TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc)
 {
@@ -1039,6 +1039,22 @@ TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TInte
 }
 
 //
+// Create a for-loop sequence.
+//
+TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc)
+{
+    TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
+    node->setLoc(loc);
+
+    // make a sequence of the initializer and statement
+    TIntermAggregate* loopSequence = makeAggregate(initializer, loc);
+    loopSequence = growAggregate(loopSequence, node);
+    loopSequence->setOperator(EOpSequence);
+
+    return loopSequence;
+}
+
+//
 // Add branches.
 //
 TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& loc)
index d60c59e..7445dee 100644 (file)
@@ -198,6 +198,7 @@ public:
     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
     TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
+    TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
     TIntermBranch* addBranch(TOperator, const TSourceLoc&);
     TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
     TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&);
index 123dd60..3b61dc0 100644 (file)
@@ -75,8 +75,10 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.assoc.frag", "PixelShaderFunction"},
         {"hlsl.attribute.frag", "PixelShaderFunction"},
         {"hlsl.cast.frag", "PixelShaderFunction"},
+        {"hlsl.doLoop.frag", "PixelShaderFunction"},
         {"hlsl.float1.frag", "PixelShaderFunction"},
         {"hlsl.float4.frag", "PixelShaderFunction"},
+        {"hlsl.forLoop.frag", "PixelShaderFunction"},
         {"hlsl.if.frag", "PixelShaderFunction"},
         {"hlsl.intrinsics.frag", "PixelShaderFunction"},
         {"hlsl.intrinsics.negative.frag", "PixelShaderFunction"},
@@ -87,6 +89,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.precedence.frag", "PixelShaderFunction"},
         {"hlsl.precedence2.frag", "PixelShaderFunction"},
         {"hlsl.sin.frag", "PixelShaderFunction"},
+        {"hlsl.whileLoop.frag", "PixelShaderFunction"},
     }),
     FileNameAsCustomTestSuffix
 );
index a75fee6..c1600e4 100755 (executable)
@@ -1119,9 +1119,128 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
     return false;
 }
 
+// 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)
 {
-    return false;
+    TSourceLoc loc = token.loc;
+    TIntermTyped* condition = nullptr;
+
+    EHlslTokenClass loop = peek();
+    assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
+
+    //  WHILE or DO or FOR
+    advanceToken();
+
+    switch (loop) {
+    case EHTokWhile:
+        // so that something declared in the condition is scoped to the lifetime
+        // of the while sub-statement
+        parseContext.pushScope();
+        parseContext.nestLooping();
+
+        // LEFT_PAREN condition RIGHT_PAREN
+        if (! acceptParenExpression(condition))
+            return false;
+
+        // statement
+        if (! acceptScopedStatement(statement)) {
+            expected("while sub-statement");
+            return false;
+        }
+
+        parseContext.unnestLooping();
+        parseContext.popScope();
+
+        statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
+
+        return true;
+
+    case EHTokDo:
+        parseContext.nestLooping();
+
+        if (! acceptTokenClass(EHTokLeftBrace))
+            expected("{");
+
+        // statement
+        if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
+            expected("do sub-statement");
+            return false;
+        }
+
+        if (! acceptTokenClass(EHTokRightBrace))
+            expected("}");
+
+        // WHILE
+        if (! acceptTokenClass(EHTokWhile)) {
+            expected("while");
+            return false;
+        }
+
+        // LEFT_PAREN condition RIGHT_PAREN
+        TIntermTyped* condition;
+        if (! acceptParenExpression(condition))
+            return false;
+
+        if (! acceptTokenClass(EHTokSemicolon))
+            expected(";");
+
+        parseContext.unnestLooping();
+
+        statement = intermediate.addLoop(statement, condition, 0, false, loc);
+
+        return true;
+
+    case EHTokFor:
+    {
+        // LEFT_PAREN
+        if (! acceptTokenClass(EHTokLeftParen))
+            expected("(");
+
+        // so that something declared in the condition is scoped to the lifetime
+        // of the for sub-statement
+        parseContext.pushScope();
+
+        // initializer SEMI_COLON
+        TIntermTyped* initializer = nullptr; // TODO, "for (initializer" needs to support decl. statement
+        acceptExpression(initializer);
+        if (! acceptTokenClass(EHTokSemicolon))
+            expected(";");
+
+        parseContext.nestLooping();
+
+        // condition SEMI_COLON
+        acceptExpression(condition);
+        if (! acceptTokenClass(EHTokSemicolon))
+            expected(";");
+
+        // iterator SEMI_COLON
+        TIntermTyped* iterator = nullptr;
+        acceptExpression(iterator);
+        if (! acceptTokenClass(EHTokRightParen))
+            expected(")");
+
+        // statement
+        if (! acceptScopedStatement(statement)) {
+            expected("for sub-statement");
+            return false;
+        }
+
+        statement = intermediate.addForLoop(statement, initializer, condition, iterator, true, loc);
+
+        parseContext.popScope();
+        parseContext.unnestLooping();
+
+        return true;
+    }
+
+    default:
+        return false;
+    }
 }
 
 // jump_statement
index a6c59a3..6f920d8 100755 (executable)
@@ -141,6 +141,8 @@ public:
 
     void nestStatement()   { ++statementNestingLevel; }
     void unnestStatement() { --statementNestingLevel; }
+    void nestLooping()     { ++loopNestingLevel; }
+    void unnestLooping()   { --loopNestingLevel; }
     void pushScope()       { symbolTable.push(); }
     void popScope()        { symbolTable.pop(0); }