Add switch/case/default statements, using a switch node that contains a sequence of case/default nodes and top-level nodes of the code chunks in between them.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@21131 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
8e5425745f
commit
0576126005
64
Test/switch.frag
Normal file
64
Test/switch.frag
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
uniform int c, d;
|
||||||
|
in float x;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float f;
|
||||||
|
int a[2];
|
||||||
|
|
||||||
|
switch(f) { // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(a) { // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case 2: // ERROR, not enough stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
f = sin(x); // ERRROR
|
||||||
|
case 2: // ERROR, not enough stuff
|
||||||
|
f = cos(x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 1:
|
||||||
|
f = sin(x);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
f = cos(x);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
f = tan(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 1:
|
||||||
|
f = sin(x);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
switch (d) {
|
||||||
|
case 1:
|
||||||
|
f = x * x * x;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
f = x * x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
f = tan(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
break; // ERROR
|
||||||
|
}
|
@ -33,3 +33,4 @@ constFold.frag
|
|||||||
errors.frag
|
errors.frag
|
||||||
forwardRef.frag
|
forwardRef.frag
|
||||||
uint.frag
|
uint.frag
|
||||||
|
switch.frag
|
||||||
|
@ -217,6 +217,8 @@ enum TOperator {
|
|||||||
EOpReturn,
|
EOpReturn,
|
||||||
EOpBreak,
|
EOpBreak,
|
||||||
EOpContinue,
|
EOpContinue,
|
||||||
|
EOpCase,
|
||||||
|
EOpDefault,
|
||||||
|
|
||||||
//
|
//
|
||||||
// Constructors
|
// Constructors
|
||||||
@ -297,6 +299,8 @@ class TIntermUnary;
|
|||||||
class TIntermBinary;
|
class TIntermBinary;
|
||||||
class TIntermConstantUnion;
|
class TIntermConstantUnion;
|
||||||
class TIntermSelection;
|
class TIntermSelection;
|
||||||
|
class TIntermSwitch;
|
||||||
|
class TIntermBranch;
|
||||||
class TIntermTyped;
|
class TIntermTyped;
|
||||||
class TIntermMethod;
|
class TIntermMethod;
|
||||||
class TIntermSymbol;
|
class TIntermSymbol;
|
||||||
@ -319,8 +323,10 @@ public:
|
|||||||
virtual TIntermUnary* getAsUnaryNode() { return 0; }
|
virtual TIntermUnary* getAsUnaryNode() { return 0; }
|
||||||
virtual TIntermBinary* getAsBinaryNode() { return 0; }
|
virtual TIntermBinary* getAsBinaryNode() { return 0; }
|
||||||
virtual TIntermSelection* getAsSelectionNode() { return 0; }
|
virtual TIntermSelection* getAsSelectionNode() { return 0; }
|
||||||
|
virtual TIntermSwitch* getAsSwitchNode() { return 0; }
|
||||||
virtual TIntermMethod* getAsMethodNode() { return 0; }
|
virtual TIntermMethod* getAsMethodNode() { return 0; }
|
||||||
virtual TIntermSymbol* getAsSymbolNode() { return 0; }
|
virtual TIntermSymbol* getAsSymbolNode() { return 0; }
|
||||||
|
virtual TIntermBranch* getAsBranchNode() { return 0; }
|
||||||
virtual ~TIntermNode() { }
|
virtual ~TIntermNode() { }
|
||||||
protected:
|
protected:
|
||||||
TSourceLoc line;
|
TSourceLoc line;
|
||||||
@ -383,19 +389,20 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Handle break, continue, return, and kill.
|
// Handle case, break, continue, return, and kill.
|
||||||
//
|
//
|
||||||
class TIntermBranch : public TIntermNode {
|
class TIntermBranch : public TIntermNode {
|
||||||
public:
|
public:
|
||||||
TIntermBranch(TOperator op, TIntermTyped* e) :
|
TIntermBranch(TOperator op, TIntermTyped* e) :
|
||||||
flowOp(op),
|
flowOp(op),
|
||||||
expression(e) { }
|
expression(e) { }
|
||||||
|
virtual TIntermBranch* getAsBranchNode() { return this; }
|
||||||
virtual void traverse(TIntermTraverser*);
|
virtual void traverse(TIntermTraverser*);
|
||||||
TOperator getFlowOp() { return flowOp; }
|
TOperator getFlowOp() { return flowOp; }
|
||||||
TIntermTyped* getExpression() { return expression; }
|
TIntermTyped* getExpression() { return expression; }
|
||||||
protected:
|
protected:
|
||||||
TOperator flowOp;
|
TOperator flowOp;
|
||||||
TIntermTyped* expression; // non-zero except for "return exp;" statements
|
TIntermTyped* expression;
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -534,7 +541,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// For if tests. Simplified since there is no switch statement.
|
// For if tests.
|
||||||
//
|
//
|
||||||
class TIntermSelection : public TIntermTyped {
|
class TIntermSelection : public TIntermTyped {
|
||||||
public:
|
public:
|
||||||
@ -553,6 +560,24 @@ protected:
|
|||||||
TIntermNode* falseBlock;
|
TIntermNode* falseBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// For switch statements. Designed use is that a switch will have sequence of nodes
|
||||||
|
// that are either case/default nodes or a *single* node that represents all the code
|
||||||
|
// in between (if any) consecutive case/defaults. So, a traversal need only deal with
|
||||||
|
// 0 or 1 nodes per case/default statement.
|
||||||
|
//
|
||||||
|
class TIntermSwitch : public TIntermAggregate {
|
||||||
|
public:
|
||||||
|
TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b) { }
|
||||||
|
virtual void traverse(TIntermTraverser*);
|
||||||
|
virtual TIntermNode* getCondition() const { return condition; }
|
||||||
|
virtual TIntermAggregate* getBody() const { return body; }
|
||||||
|
virtual TIntermSwitch* getAsSwitchNode() { return this; }
|
||||||
|
protected:
|
||||||
|
TIntermTyped* condition;
|
||||||
|
TIntermAggregate* body;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// For traversing the tree. User should derive from this,
|
// For traversing the tree. User should derive from this,
|
||||||
// put their traversal specific data in it, and then pass
|
// put their traversal specific data in it, and then pass
|
||||||
@ -587,6 +612,7 @@ public:
|
|||||||
bool (*visitAggregate)(bool preVisit, TIntermAggregate*, TIntermTraverser*);
|
bool (*visitAggregate)(bool preVisit, TIntermAggregate*, TIntermTraverser*);
|
||||||
bool (*visitLoop)(bool preVisit, TIntermLoop*, TIntermTraverser*);
|
bool (*visitLoop)(bool preVisit, TIntermLoop*, TIntermTraverser*);
|
||||||
bool (*visitBranch)(bool preVisit, TIntermBranch*, TIntermTraverser*);
|
bool (*visitBranch)(bool preVisit, TIntermBranch*, TIntermTraverser*);
|
||||||
|
bool (*visitSwitch)(bool preVisit, TIntermSwitch*, TIntermTraverser*);
|
||||||
|
|
||||||
int depth;
|
int depth;
|
||||||
bool preVisit;
|
bool preVisit;
|
||||||
|
@ -176,13 +176,13 @@ void TIntermSelection::traverse(TIntermTraverser* it)
|
|||||||
if (it->rightToLeft) {
|
if (it->rightToLeft) {
|
||||||
if (falseBlock)
|
if (falseBlock)
|
||||||
falseBlock->traverse(it);
|
falseBlock->traverse(it);
|
||||||
if (trueBlock)
|
if (trueBlock)
|
||||||
trueBlock->traverse(it);
|
trueBlock->traverse(it);
|
||||||
condition->traverse(it);
|
condition->traverse(it);
|
||||||
} else {
|
} else {
|
||||||
condition->traverse(it);
|
condition->traverse(it);
|
||||||
if (trueBlock)
|
if (trueBlock)
|
||||||
trueBlock->traverse(it);
|
trueBlock->traverse(it);
|
||||||
if (falseBlock)
|
if (falseBlock)
|
||||||
falseBlock->traverse(it);
|
falseBlock->traverse(it);
|
||||||
}
|
}
|
||||||
@ -210,11 +210,11 @@ void TIntermLoop::traverse(TIntermTraverser* it)
|
|||||||
terminal->traverse(it);
|
terminal->traverse(it);
|
||||||
if (body)
|
if (body)
|
||||||
body->traverse(it);
|
body->traverse(it);
|
||||||
if (test)
|
if (test)
|
||||||
test->traverse(it);
|
test->traverse(it);
|
||||||
} else {
|
} else {
|
||||||
if (test)
|
if (test)
|
||||||
test->traverse(it);
|
test->traverse(it);
|
||||||
if (body)
|
if (body)
|
||||||
body->traverse(it);
|
body->traverse(it);
|
||||||
if (terminal)
|
if (terminal)
|
||||||
@ -247,3 +247,28 @@ void TIntermBranch::traverse(TIntermTraverser* it)
|
|||||||
it->visitBranch(false, this, it);
|
it->visitBranch(false, this, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Traverse a switch node.
|
||||||
|
//
|
||||||
|
void TIntermSwitch::traverse(TIntermTraverser* it)
|
||||||
|
{
|
||||||
|
bool visit = true;
|
||||||
|
|
||||||
|
if (it->preVisit && it->visitSwitch)
|
||||||
|
visit = it->visitSwitch(true, this, it);
|
||||||
|
|
||||||
|
if (visit) {
|
||||||
|
++it->depth;
|
||||||
|
if (it->rightToLeft) {
|
||||||
|
body->traverse(it);
|
||||||
|
condition->traverse(it);
|
||||||
|
} else {
|
||||||
|
condition->traverse(it);
|
||||||
|
body->traverse(it);
|
||||||
|
}
|
||||||
|
--it->depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visit && it->postVisit && it->visitSwitch)
|
||||||
|
it->visitSwitch(false, this, it);
|
||||||
|
}
|
||||||
|
@ -44,7 +44,7 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, E
|
|||||||
bool fc, EShMessages m) :
|
bool fc, EShMessages m) :
|
||||||
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
|
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
|
||||||
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
|
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
|
||||||
switchNestingLevel(0), inTypeParen(false),
|
inTypeParen(false),
|
||||||
version(v), profile(p), forwardCompatible(fc), messages(m),
|
version(v), profile(p), forwardCompatible(fc), messages(m),
|
||||||
contextPragma(true, false)
|
contextPragma(true, false)
|
||||||
{
|
{
|
||||||
@ -1574,6 +1574,58 @@ void TParseContext::addBlock(int line, TPublicType& publicType, const TString& b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode)
|
||||||
|
{
|
||||||
|
auto switchSequence = switchSequenceStack.back();
|
||||||
|
|
||||||
|
if (statements) {
|
||||||
|
if (switchSequence->size() == 0) {
|
||||||
|
error(statements->getLine(), "cannot have statements before first case/default label", "switch", "");
|
||||||
|
recover();
|
||||||
|
}
|
||||||
|
statements->setOperator(EOpSequence);
|
||||||
|
switchSequence->push_back(statements);
|
||||||
|
}
|
||||||
|
if (branchNode)
|
||||||
|
switchSequence->push_back(branchNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
TIntermNode* TParseContext::addSwitch(int line, TIntermTyped* expression, TIntermAggregate* lastStatements)
|
||||||
|
{
|
||||||
|
profileRequires(line, EEsProfile, 300, 0, "switch statements");
|
||||||
|
profileRequires(line, ENoProfile, 130, 0, "switch statements");
|
||||||
|
|
||||||
|
wrapupSwitchSubsequence(lastStatements, 0);
|
||||||
|
|
||||||
|
if (expression == 0 ||
|
||||||
|
expression->getBasicType() != EbtInt && expression->getBasicType() != EbtUint ||
|
||||||
|
expression->getType().isArray() || expression->getType().isMatrix() || expression->getType().isVector()) {
|
||||||
|
error(line, "condition must be a scalar integer expression", "switch", "");
|
||||||
|
recover();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is nothing to do, drop the switch but still execute the expression
|
||||||
|
auto switchSequence = switchSequenceStack.back();
|
||||||
|
if (switchSequence->size() == 0)
|
||||||
|
return expression;
|
||||||
|
|
||||||
|
if (lastStatements == 0) {
|
||||||
|
error(line, "last case/default label must be followed by statements", "switch", "");
|
||||||
|
recover();
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIntermAggregate* body = new TIntermAggregate(EOpSequence);
|
||||||
|
body->getSequence() = *switchSequenceStack.back();
|
||||||
|
body->setLine(line);
|
||||||
|
|
||||||
|
TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
|
||||||
|
switchNode->setLine(line);
|
||||||
|
|
||||||
|
return switchNode;
|
||||||
|
}
|
||||||
|
|
||||||
void TParseContext::updateDefaults(int line, const TPublicType& publicType, const TString* id)
|
void TParseContext::updateDefaults(int line, const TPublicType& publicType, const TString* id)
|
||||||
{
|
{
|
||||||
bool cantHaveId = false;
|
bool cantHaveId = false;
|
||||||
|
@ -78,7 +78,7 @@ struct TParseContext {
|
|||||||
int numErrors;
|
int numErrors;
|
||||||
bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier
|
bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier
|
||||||
int loopNestingLevel; // 0 if outside all loops
|
int loopNestingLevel; // 0 if outside all loops
|
||||||
int switchNestingLevel; // 0 if outside all switch statements
|
TList<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting
|
||||||
bool inTypeParen; // true if in parentheses, looking only for an identifier
|
bool inTypeParen; // true if in parentheses, looking only for an identifier
|
||||||
const TType* currentFunctionType; // the return type of the function that's currently being parsed
|
const TType* currentFunctionType; // the return type of the function that's currently being parsed
|
||||||
bool functionReturnsValue; // true if a non-void function has a return
|
bool functionReturnsValue; // true if a non-void function has a return
|
||||||
@ -143,6 +143,8 @@ struct TParseContext {
|
|||||||
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
|
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
|
||||||
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset);
|
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset);
|
||||||
void addBlock(int line, TPublicType& qualifier, const TString& blockName, TTypeList& typeList, const TString* instanceName = 0, TArraySizes arraySizes = 0);
|
void addBlock(int line, TPublicType& qualifier, const TString& blockName, TTypeList& typeList, const TString* instanceName = 0, TArraySizes arraySizes = 0);
|
||||||
|
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
|
||||||
|
TIntermNode* addSwitch(int line, TIntermTyped* expression, TIntermAggregate* body);
|
||||||
void updateDefaults(int line, const TPublicType&, const TString* id);
|
void updateDefaults(int line, const TPublicType&, const TString* id);
|
||||||
TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc);
|
TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc);
|
||||||
TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc);
|
TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc);
|
||||||
|
@ -71,6 +71,13 @@ bool RemoveSelection(bool /*preVisit*/ , TIntermSelection* node, TIntermTravers
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RemoveSwitch(bool /*preVisit*/ , TIntermSwitch* node, TIntermTraverser*)
|
||||||
|
{
|
||||||
|
delete node;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void RemoveConstantUnion(TIntermConstantUnion* node, TIntermTraverser*)
|
void RemoveConstantUnion(TIntermConstantUnion* node, TIntermTraverser*)
|
||||||
{
|
{
|
||||||
delete node;
|
delete node;
|
||||||
@ -89,6 +96,7 @@ void RemoveAllTreeNodes(TIntermNode* root)
|
|||||||
it.visitSelection = RemoveSelection;
|
it.visitSelection = RemoveSelection;
|
||||||
it.visitSymbol = RemoveSymbol;
|
it.visitSymbol = RemoveSymbol;
|
||||||
it.visitUnary = RemoveUnary;
|
it.visitUnary = RemoveUnary;
|
||||||
|
it.visitSwitch = RemoveSwitch;
|
||||||
|
|
||||||
it.preVisit = false;
|
it.preVisit = false;
|
||||||
it.postVisit = true;
|
it.postVisit = true;
|
||||||
|
@ -131,9 +131,9 @@ bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, int version, EProfil
|
|||||||
|
|
||||||
builtInShaders[0] = (*i).c_str();
|
builtInShaders[0] = (*i).c_str();
|
||||||
builtInLengths[0] = (int) (*i).size();
|
builtInLengths[0] = (int) (*i).size();
|
||||||
|
|
||||||
if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext, 0) != 0) {
|
if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext, 0) != 0) {
|
||||||
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
|
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
|
||||||
|
printf("Unable to parse built-ins\n");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -188,9 +188,9 @@ extern void yyerror(const char*);
|
|||||||
|
|
||||||
%type <interm.intermNode> translation_unit function_definition
|
%type <interm.intermNode> translation_unit function_definition
|
||||||
%type <interm.intermNode> statement simple_statement
|
%type <interm.intermNode> statement simple_statement
|
||||||
%type <interm.intermAggregate> statement_list compound_statement
|
%type <interm.intermAggregate> statement_list switch_statement_list compound_statement
|
||||||
%type <interm.intermNode> declaration_statement selection_statement expression_statement
|
%type <interm.intermNode> declaration_statement selection_statement expression_statement
|
||||||
%type <interm.intermNode> switch_statement case_label switch_statement_list
|
%type <interm.intermNode> switch_statement case_label
|
||||||
%type <interm.intermNode> declaration external_declaration
|
%type <interm.intermNode> declaration external_declaration
|
||||||
%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
|
%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
|
||||||
%type <interm.nodePair> selection_rest_statement for_rest_statement
|
%type <interm.nodePair> selection_rest_statement for_rest_statement
|
||||||
@ -2735,9 +2735,19 @@ compound_statement_no_new_scope
|
|||||||
statement_list
|
statement_list
|
||||||
: statement {
|
: statement {
|
||||||
$$ = parseContext.intermediate.makeAggregate($1, 0);
|
$$ = parseContext.intermediate.makeAggregate($1, 0);
|
||||||
|
if ($1 && $1->getAsBranchNode() && ($1->getAsBranchNode()->getFlowOp() == EOpCase ||
|
||||||
|
$1->getAsBranchNode()->getFlowOp() == EOpDefault)) {
|
||||||
|
parseContext.wrapupSwitchSubsequence(0, $1);
|
||||||
|
$$ = 0; // start a fresh subsequence for what's after this case
|
||||||
|
}
|
||||||
}
|
}
|
||||||
| statement_list statement {
|
| statement_list statement {
|
||||||
$$ = parseContext.intermediate.growAggregate($1, $2, 0);
|
if ($2 && $2->getAsBranchNode() && ($2->getAsBranchNode()->getFlowOp() == EOpCase ||
|
||||||
|
$2->getAsBranchNode()->getFlowOp() == EOpDefault)) {
|
||||||
|
parseContext.wrapupSwitchSubsequence($1, $2);
|
||||||
|
$$ = 0; // start a fresh subsequence for what's after this case
|
||||||
|
} else
|
||||||
|
$$ = parseContext.intermediate.growAggregate($1, $2, 0);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -2787,14 +2797,20 @@ condition
|
|||||||
;
|
;
|
||||||
|
|
||||||
switch_statement
|
switch_statement
|
||||||
: SWITCH LEFT_PAREN expression RIGHT_PAREN { ++parseContext.switchNestingLevel; } LEFT_BRACE switch_statement_list RIGHT_BRACE {
|
: SWITCH LEFT_PAREN expression RIGHT_PAREN {
|
||||||
$$ = 0;
|
// start new switch sequence on the switch stack
|
||||||
--parseContext.switchNestingLevel;
|
parseContext.switchSequenceStack.push_back(new TIntermSequence);
|
||||||
|
}
|
||||||
|
LEFT_BRACE switch_statement_list RIGHT_BRACE {
|
||||||
|
$$ = parseContext.addSwitch($1.line, $3, $7);
|
||||||
|
delete parseContext.switchSequenceStack.back();
|
||||||
|
parseContext.switchSequenceStack.pop_back();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
switch_statement_list
|
switch_statement_list
|
||||||
: /* nothing */ {
|
: /* nothing */ {
|
||||||
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| statement_list {
|
| statement_list {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
@ -2803,10 +2819,10 @@ switch_statement_list
|
|||||||
|
|
||||||
case_label
|
case_label
|
||||||
: CASE expression COLON {
|
: CASE expression COLON {
|
||||||
$$ = 0;
|
$$ = parseContext.intermediate.addBranch(EOpCase, $2, $1.line);
|
||||||
}
|
}
|
||||||
| DEFAULT COLON {
|
| DEFAULT COLON {
|
||||||
$$ = 0;
|
$$ = parseContext.intermediate.addBranch(EOpDefault, $1.line);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -2881,7 +2897,7 @@ jump_statement
|
|||||||
$$ = parseContext.intermediate.addBranch(EOpContinue, $1.line);
|
$$ = parseContext.intermediate.addBranch(EOpContinue, $1.line);
|
||||||
}
|
}
|
||||||
| BREAK SEMICOLON {
|
| BREAK SEMICOLON {
|
||||||
if (parseContext.loopNestingLevel + parseContext.switchNestingLevel <= 0) {
|
if (parseContext.loopNestingLevel + parseContext.switchSequenceStack.size() <= 0) {
|
||||||
parseContext.error($1.line, "break statement only allowed in switch and loops", "", "");
|
parseContext.error($1.line, "break statement only allowed in switch and loops", "", "");
|
||||||
parseContext.recover();
|
parseContext.recover();
|
||||||
}
|
}
|
||||||
|
@ -503,6 +503,8 @@ bool OutputBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it)
|
|||||||
case EOpBreak: out.debug << "Branch: Break"; break;
|
case EOpBreak: out.debug << "Branch: Break"; break;
|
||||||
case EOpContinue: out.debug << "Branch: Continue"; break;
|
case EOpContinue: out.debug << "Branch: Continue"; break;
|
||||||
case EOpReturn: out.debug << "Branch: Return"; break;
|
case EOpReturn: out.debug << "Branch: Return"; break;
|
||||||
|
case EOpCase: out.debug << "case: "; break;
|
||||||
|
case EOpDefault: out.debug << "default: "; break;
|
||||||
default: out.debug << "Branch: Unknown Branch"; break;
|
default: out.debug << "Branch: Unknown Branch"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,6 +519,30 @@ bool OutputBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OutputSwitch(bool /* preVisit */, TIntermSwitch* node, TIntermTraverser* it)
|
||||||
|
{
|
||||||
|
TOutputTraverser* oit = static_cast<TOutputTraverser*>(it);
|
||||||
|
TInfoSink& out = oit->infoSink;
|
||||||
|
|
||||||
|
OutputTreeText(out, node, oit->depth);
|
||||||
|
out.debug << "switch\n";
|
||||||
|
|
||||||
|
OutputTreeText(out, node, oit->depth);
|
||||||
|
out.debug << "condition\n";
|
||||||
|
++oit->depth;
|
||||||
|
node->getCondition()->traverse(it);
|
||||||
|
|
||||||
|
--oit->depth;
|
||||||
|
OutputTreeText(out, node, oit->depth);
|
||||||
|
out.debug << "body\n";
|
||||||
|
++oit->depth;
|
||||||
|
node->getBody()->traverse(it);
|
||||||
|
|
||||||
|
--oit->depth;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This function is the one to call externally to start the traversal.
|
// This function is the one to call externally to start the traversal.
|
||||||
// Individual functions can be initialized to 0 to skip processing of that
|
// Individual functions can be initialized to 0 to skip processing of that
|
||||||
@ -537,6 +563,7 @@ void TIntermediate::outputTree(TIntermNode* root)
|
|||||||
it.visitUnary = OutputUnary;
|
it.visitUnary = OutputUnary;
|
||||||
it.visitLoop = OutputLoop;
|
it.visitLoop = OutputLoop;
|
||||||
it.visitBranch = OutputBranch;
|
it.visitBranch = OutputBranch;
|
||||||
|
it.visitSwitch = OutputSwitch;
|
||||||
|
|
||||||
root->traverse(&it);
|
root->traverse(&it);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user