Commit 76a343af by Alexis Hetu Committed by Alexis Hétu

Adding switch case default keywords

This adds switch/case keywords to glsl. This makes the shaders that include these keywords compile, but they don't run properly yet, partly because the "break" statement only handles loops currently. Change-Id: I1f52b445e1124ed3931843c46e27ecc1d9ce3d11 Reviewed-on: https://swiftshader-review.googlesource.com/3400Reviewed-by: 's avatarNicolas Capens <capn@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com>
parent a35d8232
...@@ -40,6 +40,7 @@ LOCAL_SRC_FILES += \ ...@@ -40,6 +40,7 @@ LOCAL_SRC_FILES += \
TranslatorASM.cpp \ TranslatorASM.cpp \
util.cpp \ util.cpp \
ValidateLimitations.cpp \ ValidateLimitations.cpp \
ValidateSwitch.cpp \
LOCAL_CFLAGS += -DLOG_TAG=\"swiftshader_compiler\" -Wno-unused-parameter LOCAL_CFLAGS += -DLOG_TAG=\"swiftshader_compiler\" -Wno-unused-parameter
......
...@@ -216,6 +216,7 @@ ...@@ -216,6 +216,7 @@
<ClCompile Include="ValidateLimitations.cpp" /> <ClCompile Include="ValidateLimitations.cpp" />
<ClCompile Include="glslang_lex.cpp" /> <ClCompile Include="glslang_lex.cpp" />
<ClCompile Include="glslang_tab.cpp" /> <ClCompile Include="glslang_tab.cpp" />
<ClCompile Include="ValidateSwitch.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="glslang.l"> <CustomBuild Include="glslang.l">
...@@ -318,6 +319,7 @@ ...@@ -318,6 +319,7 @@
<ClInclude Include="util.h" /> <ClInclude Include="util.h" />
<ClInclude Include="ValidateLimitations.h" /> <ClInclude Include="ValidateLimitations.h" />
<ClInclude Include="glslang_tab.h" /> <ClInclude Include="glslang_tab.h" />
<ClInclude Include="ValidateSwitch.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="preprocessor\preprocessor.vcxproj"> <ProjectReference Include="preprocessor\preprocessor.vcxproj">
......
...@@ -83,6 +83,9 @@ ...@@ -83,6 +83,9 @@
<ClCompile Include="AnalyzeCallDepth.cpp"> <ClCompile Include="AnalyzeCallDepth.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="ValidateSwitch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="BaseTypes.h"> <ClInclude Include="BaseTypes.h">
...@@ -169,6 +172,9 @@ ...@@ -169,6 +172,9 @@
<ClInclude Include="glslang.h"> <ClInclude Include="glslang.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ValidateSwitch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="glslang.l"> <CustomBuild Include="glslang.l">
......
...@@ -53,7 +53,7 @@ void TIntermBinary::traverse(TIntermTraverser* it) ...@@ -53,7 +53,7 @@ void TIntermBinary::traverse(TIntermTraverser* it)
// //
if(visit) if(visit)
{ {
it->incrementDepth(); it->incrementDepth(this);
if(it->rightToLeft) if(it->rightToLeft)
{ {
...@@ -114,7 +114,7 @@ void TIntermUnary::traverse(TIntermTraverser* it) ...@@ -114,7 +114,7 @@ void TIntermUnary::traverse(TIntermTraverser* it)
visit = it->visitUnary(PreVisit, this); visit = it->visitUnary(PreVisit, this);
if (visit) { if (visit) {
it->incrementDepth(); it->incrementDepth(this);
operand->traverse(it); operand->traverse(it);
it->decrementDepth(); it->decrementDepth();
} }
...@@ -137,7 +137,7 @@ void TIntermAggregate::traverse(TIntermTraverser* it) ...@@ -137,7 +137,7 @@ void TIntermAggregate::traverse(TIntermTraverser* it)
if(visit) if(visit)
{ {
it->incrementDepth(); it->incrementDepth(this);
if(it->rightToLeft) if(it->rightToLeft)
{ {
...@@ -190,7 +190,7 @@ void TIntermSelection::traverse(TIntermTraverser* it) ...@@ -190,7 +190,7 @@ void TIntermSelection::traverse(TIntermTraverser* it)
visit = it->visitSelection(PreVisit, this); visit = it->visitSelection(PreVisit, this);
if (visit) { if (visit) {
it->incrementDepth(); it->incrementDepth(this);
if (it->rightToLeft) { if (it->rightToLeft) {
if (falseBlock) if (falseBlock)
falseBlock->traverse(it); falseBlock->traverse(it);
...@@ -212,6 +212,60 @@ void TIntermSelection::traverse(TIntermTraverser* it) ...@@ -212,6 +212,60 @@ void TIntermSelection::traverse(TIntermTraverser* it)
} }
// //
// Traverse a switch node. Same comments in binary node apply here.
//
void TIntermSwitch::traverse(TIntermTraverser *it)
{
bool visit = true;
if(it->preVisit)
visit = it->visitSwitch(PreVisit, this);
if(visit)
{
it->incrementDepth(this);
if(it->rightToLeft)
{
if(mStatementList)
mStatementList->traverse(it);
if(it->inVisit)
visit = it->visitSwitch(InVisit, this);
if(visit)
mInit->traverse(it);
}
else
{
mInit->traverse(it);
if(it->inVisit)
visit = it->visitSwitch(InVisit, this);
if(visit && mStatementList)
mStatementList->traverse(it);
}
it->decrementDepth();
}
if(visit && it->postVisit)
it->visitSwitch(PostVisit, this);
}
//
// Traverse a switch node. Same comments in binary node apply here.
//
void TIntermCase::traverse(TIntermTraverser *it)
{
bool visit = true;
if(it->preVisit)
visit = it->visitCase(PreVisit, this);
if(visit && mCondition)
mCondition->traverse(it);
if(visit && it->postVisit)
it->visitCase(PostVisit, this);
}
//
// Traverse a loop node. Same comments in binary node apply here. // Traverse a loop node. Same comments in binary node apply here.
// //
void TIntermLoop::traverse(TIntermTraverser* it) void TIntermLoop::traverse(TIntermTraverser* it)
...@@ -225,7 +279,7 @@ void TIntermLoop::traverse(TIntermTraverser* it) ...@@ -225,7 +279,7 @@ void TIntermLoop::traverse(TIntermTraverser* it)
if(visit) if(visit)
{ {
it->incrementDepth(); it->incrementDepth(this);
if(it->rightToLeft) if(it->rightToLeft)
{ {
...@@ -282,7 +336,7 @@ void TIntermBranch::traverse(TIntermTraverser* it) ...@@ -282,7 +336,7 @@ void TIntermBranch::traverse(TIntermTraverser* it)
visit = it->visitBranch(PreVisit, this); visit = it->visitBranch(PreVisit, this);
if (visit && expression) { if (visit && expression) {
it->incrementDepth(); it->incrementDepth(this);
expression->traverse(it); expression->traverse(it);
it->decrementDepth(); it->decrementDepth();
} }
......
...@@ -552,6 +552,22 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true ...@@ -552,6 +552,22 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
return node; return node;
} }
TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line)
{
TIntermSwitch *node = new TIntermSwitch(init, statementList);
node->setLine(line);
return node;
}
TIntermCase *TIntermediate::addCase(TIntermTyped *condition, const TSourceLoc &line)
{
TIntermCase *node = new TIntermCase(condition);
node->setLine(line);
return node;
}
// //
// Constant terminal nodes. Has a union that contains bool, float or int constants // Constant terminal nodes. Has a union that contains bool, float or int constants
// //
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "glslang.h" #include "glslang.h"
#include "preprocessor/SourceLocation.h" #include "preprocessor/SourceLocation.h"
#include "ValidateSwitch.h"
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //
...@@ -2966,6 +2967,143 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TInter ...@@ -2966,6 +2967,143 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TInter
return true; return true;
} }
TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc)
{
TBasicType switchType = init->getBasicType();
if((switchType != EbtInt && switchType != EbtUInt) ||
init->isMatrix() ||
init->isArray() ||
init->isVector())
{
error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch");
recover();
return nullptr;
}
if(statementList)
{
if(!ValidateSwitch::validate(switchType, this, statementList, loc))
{
recover();
return nullptr;
}
}
TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
if(node == nullptr)
{
error(loc, "erroneous switch statement", "switch");
recover();
return nullptr;
}
return node;
}
TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
{
if(switchNestingLevel == 0)
{
error(loc, "case labels need to be inside switch statements", "case");
recover();
return nullptr;
}
if(condition == nullptr)
{
error(loc, "case label must have a condition", "case");
recover();
return nullptr;
}
if((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
condition->isMatrix() ||
condition->isArray() ||
condition->isVector())
{
error(condition->getLine(), "case label must be a scalar integer", "case");
recover();
}
TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
if(conditionConst == nullptr)
{
error(condition->getLine(), "case label must be constant", "case");
recover();
}
TIntermCase *node = intermediate.addCase(condition, loc);
if(node == nullptr)
{
error(loc, "erroneous case statement", "case");
recover();
return nullptr;
}
return node;
}
TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
{
if(switchNestingLevel == 0)
{
error(loc, "default labels need to be inside switch statements", "default");
recover();
return nullptr;
}
TIntermCase *node = intermediate.addCase(nullptr, loc);
if(node == nullptr)
{
error(loc, "erroneous default statement", "default");
recover();
return nullptr;
}
return node;
}
TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
{
switch(op)
{
case EOpContinue:
if(loopNestingLevel <= 0)
{
error(loc, "continue statement only allowed in loops", "");
recover();
}
break;
case EOpBreak:
if(loopNestingLevel <= 0 && switchNestingLevel <= 0)
{
error(loc, "break statement only allowed in loops and switch statements", "");
recover();
}
break;
case EOpReturn:
if(currentFunctionType->getBasicType() != EbtVoid)
{
error(loc, "non-void function must return a value", "return");
recover();
}
break;
default:
// No checks for discard
break;
}
return intermediate.addBranch(op, loc);
}
TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc)
{
ASSERT(op == EOpReturn);
functionReturnsValue = true;
if(currentFunctionType->getBasicType() == EbtVoid)
{
error(loc, "void function cannot return a value", "return");
recover();
}
else if(*currentFunctionType != returnValue->getType())
{
error(loc, "function return is not matching type:", "return");
recover();
}
return intermediate.addBranch(op, returnValue, loc);
}
// //
// Parse an array of strings using yyparse. // Parse an array of strings using yyparse.
// //
......
...@@ -34,6 +34,7 @@ struct TParseContext { ...@@ -34,6 +34,7 @@ struct TParseContext {
treeRoot(0), treeRoot(0),
lexAfterType(false), lexAfterType(false),
loopNestingLevel(0), loopNestingLevel(0),
switchNestingLevel(0),
structNestingLevel(0), structNestingLevel(0),
inTypeParen(false), inTypeParen(false),
currentFunctionType(NULL), currentFunctionType(NULL),
...@@ -58,6 +59,7 @@ struct TParseContext { ...@@ -58,6 +59,7 @@ struct TParseContext {
TIntermNode* treeRoot; // root of parse tree being created TIntermNode* treeRoot; // root of parse tree being created
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
int structNestingLevel; // incremented while parsing a struct declaration int structNestingLevel; // incremented while parsing a struct declaration
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
...@@ -82,6 +84,9 @@ struct TParseContext { ...@@ -82,6 +84,9 @@ struct TParseContext {
void trace(const char* str); void trace(const char* str);
void recover(); void recover();
void incrSwitchNestingLevel() { ++switchNestingLevel; }
void decrSwitchNestingLevel() { --switchNestingLevel; }
// This method is guaranteed to succeed, even if no variable with 'name' exists. // This method is guaranteed to succeed, even if no variable with 'name' exists.
const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol); const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
...@@ -189,9 +194,16 @@ struct TParseContext { ...@@ -189,9 +194,16 @@ struct TParseContext {
bool structNestingErrorCheck(const TSourceLoc &line, const TField &field); bool structNestingErrorCheck(const TSourceLoc &line, const TField &field);
TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc);
TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc);
TIntermCase *addDefault(const TSourceLoc &loc);
TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc); TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc); TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
private: private:
bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable); bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
......
//
// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "ValidateSwitch.h"
#include "ParseHelper.h"
bool ValidateSwitch::validate(TBasicType switchType, TParseContext *context,
TIntermAggregate *statementList, const TSourceLoc &loc)
{
ValidateSwitch validate(switchType, context);
ASSERT(statementList);
statementList->traverse(&validate);
return validate.validateInternal(loc);
}
ValidateSwitch::ValidateSwitch(TBasicType switchType, TParseContext *context)
: TIntermTraverser(true, false, true),
mSwitchType(switchType),
mContext(context),
mCaseTypeMismatch(false),
mFirstCaseFound(false),
mStatementBeforeCase(false),
mLastStatementWasCase(false),
mControlFlowDepth(0),
mCaseInsideControlFlow(false),
mDefaultCount(0),
mDuplicateCases(false)
{}
void ValidateSwitch::visitSymbol(TIntermSymbol *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
}
void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *)
{
// Conditions of case labels are not traversed, so this is some other constant
// Could be just a statement like "0;"
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
}
bool ValidateSwitch::visitBinary(Visit, TIntermBinary *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitSelection(Visit visit, TIntermSelection *)
{
if (visit == PreVisit)
++mControlFlowDepth;
if (visit == PostVisit)
--mControlFlowDepth;
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
// Don't go into nested switch statements
return false;
}
bool ValidateSwitch::visitCase(Visit, TIntermCase *node)
{
const char *nodeStr = node->hasCondition() ? "case" : "default";
if (mControlFlowDepth > 0)
{
mContext->error(node->getLine(), "label statement nested inside control flow", nodeStr);
mCaseInsideControlFlow = true;
}
mFirstCaseFound = true;
mLastStatementWasCase = true;
if (!node->hasCondition())
{
++mDefaultCount;
if (mDefaultCount > 1)
{
mContext->error(node->getLine(), "duplicate default label", nodeStr);
}
}
else
{
TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion();
if (condition == nullptr)
{
// This can happen in error cases.
return false;
}
TBasicType conditionType = condition->getBasicType();
if (conditionType != mSwitchType)
{
mContext->error(condition->getLine(),
"case label type does not match switch init-expression type", nodeStr);
mCaseTypeMismatch = true;
}
if (conditionType == EbtInt)
{
int iConst = condition->getIConst(0);
if (mCasesSigned.find(iConst) != mCasesSigned.end())
{
mContext->error(condition->getLine(), "duplicate case label", nodeStr);
mDuplicateCases = true;
}
else
{
mCasesSigned.insert(iConst);
}
}
else if (conditionType == EbtUInt)
{
unsigned int uConst = condition->getUConst(0);
if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end())
{
mContext->error(condition->getLine(), "duplicate case label", nodeStr);
mDuplicateCases = true;
}
else
{
mCasesUnsigned.insert(uConst);
}
}
// Other types are possible only in error cases, where the error has already been generated
// when parsing the case statement.
}
// Don't traverse the condition of the case statement
return false;
}
bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *)
{
if (getParentNode() != nullptr)
{
// This is not the statementList node, but some other node.
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
}
return true;
}
bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *)
{
if (visit == PreVisit)
++mControlFlowDepth;
if (visit == PostVisit)
--mControlFlowDepth;
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitBranch(Visit, TIntermBranch *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::validateInternal(const TSourceLoc &loc)
{
if (mStatementBeforeCase)
{
mContext->error(loc,
"statement before the first label", "switch");
}
if (mLastStatementWasCase)
{
mContext->error(loc,
"no statement between the last label and the end of the switch statement", "switch");
}
return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow &&
!mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases;
}
//
// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_VALIDATESWITCH_H_
#define COMPILER_TRANSLATOR_VALIDATESWITCH_H_
#include "intermediate.h"
#include <set>
struct TParseContext;
class ValidateSwitch : public TIntermTraverser
{
public:
// Check for errors and output messages any remaining errors on the context.
// Returns true if there are no errors.
static bool validate(TBasicType switchType, TParseContext *context,
TIntermAggregate *statementList, const TSourceLoc &loc);
void visitSymbol(TIntermSymbol *) override;
void visitConstantUnion(TIntermConstantUnion *) override;
bool visitBinary(Visit, TIntermBinary *) override;
bool visitUnary(Visit, TIntermUnary *) override;
bool visitSelection(Visit visit, TIntermSelection *) override;
bool visitSwitch(Visit, TIntermSwitch *) override;
bool visitCase(Visit, TIntermCase *) override;
bool visitAggregate(Visit, TIntermAggregate *) override;
bool visitLoop(Visit visit, TIntermLoop *) override;
bool visitBranch(Visit, TIntermBranch *) override;
private:
ValidateSwitch(TBasicType switchType, TParseContext *context);
bool validateInternal(const TSourceLoc &loc);
TBasicType mSwitchType;
TParseContext *mContext;
bool mCaseTypeMismatch;
bool mFirstCaseFound;
bool mStatementBeforeCase;
bool mLastStatementWasCase;
int mControlFlowDepth;
bool mCaseInsideControlFlow;
int mDefaultCount;
std::set<int> mCasesSigned;
std::set<unsigned int> mCasesUnsigned;
bool mDuplicateCases;
};
#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_
...@@ -67,6 +67,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). ...@@ -67,6 +67,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
TIntermNodePair nodePair; TIntermNodePair nodePair;
TIntermTyped* intermTypedNode; TIntermTyped* intermTypedNode;
TIntermAggregate* intermAggregate; TIntermAggregate* intermAggregate;
TIntermSwitch* intermSwitch;
TIntermCase* intermCase;
}; };
union { union {
TPublicType type; TPublicType type;
...@@ -165,6 +167,8 @@ extern void yyerror(TParseContext* context, const char* reason); ...@@ -165,6 +167,8 @@ extern void yyerror(TParseContext* context, const char* reason);
%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
%type <interm.intermSwitch> switch_statement
%type <interm.intermCase> case_label
%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope %type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope
%type <interm> single_declaration init_declarator_list %type <interm> single_declaration init_declarator_list
...@@ -357,7 +361,7 @@ function_call ...@@ -357,7 +361,7 @@ function_call
$$->getAsAggregate()->setName(fnCandidate->getMangledName()); $$->getAsAggregate()->setName(fnCandidate->getMangledName());
TQualifier qual; TQualifier qual;
for (int i = 0; i < fnCandidate->getParamCount(); ++i) { for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
qual = fnCandidate->getParam(i).type->getQualifier(); qual = fnCandidate->getParam(i).type->getQualifier();
if (qual == EvqOut || qual == EvqInOut) { if (qual == EvqOut || qual == EvqInOut) {
if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) { if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {
...@@ -906,7 +910,7 @@ declaration ...@@ -906,7 +910,7 @@ declaration
prototype->setType(function.getReturnType()); prototype->setType(function.getReturnType());
prototype->setName(function.getName()); prototype->setName(function.getName());
for (int i = 0; i < function.getParamCount(); i++) for (size_t i = 0; i < function.getParamCount(); i++)
{ {
const TParameter &param = function.getParam(i); const TParameter &param = function.getParam(i);
if (param.name != 0) if (param.name != 0)
...@@ -973,7 +977,7 @@ function_prototype ...@@ -973,7 +977,7 @@ function_prototype
context->error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString()); context->error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString());
context->recover(); context->recover();
} }
for (int i = 0; i < prevDec->getParamCount(); ++i) { for (size_t i = 0; i < prevDec->getParamCount(); ++i) {
if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) { if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) {
context->error($2.line, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString()); context->error($2.line, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString());
context->recover(); context->recover();
...@@ -1802,6 +1806,8 @@ simple_statement ...@@ -1802,6 +1806,8 @@ simple_statement
: declaration_statement { $$ = $1; } : declaration_statement { $$ = $1; }
| expression_statement { $$ = $1; } | expression_statement { $$ = $1; }
| selection_statement { $$ = $1; } | selection_statement { $$ = $1; }
| switch_statement { $$ = $1; }
| case_label { $$ = $1; }
| iteration_statement { $$ = $1; } | iteration_statement { $$ = $1; }
| jump_statement { $$ = $1; } | jump_statement { $$ = $1; }
; ;
...@@ -1874,7 +1880,23 @@ selection_rest_statement ...@@ -1874,7 +1880,23 @@ selection_rest_statement
} }
; ;
// Grammar Note: No 'switch'. Switch statements not supported. switch_statement
: SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement {
$$ = context->addSwitch($3, $6, $1.line);
context->decrSwitchNestingLevel();
}
;
case_label
: CASE constant_expression COLON {
$$ = context->addCase($2, $1.line);
}
| DEFAULT COLON {
$$ = context->addDefault($1.line);
}
;
// Grammar Note: Labeled statements for SWITCH only; 'goto' is not supported.
condition condition
// In 1996 c++ draft, conditions can include single declarations // In 1996 c++ draft, conditions can include single declarations
...@@ -1950,40 +1972,20 @@ for_rest_statement ...@@ -1950,40 +1972,20 @@ for_rest_statement
jump_statement jump_statement
: CONTINUE SEMICOLON { : CONTINUE SEMICOLON {
if (context->loopNestingLevel <= 0) { $$ = context->addBranch(EOpContinue, $1.line);
context->error($1.line, "continue statement only allowed in loops", "");
context->recover();
}
$$ = context->intermediate.addBranch(EOpContinue, $1.line);
} }
| BREAK SEMICOLON { | BREAK SEMICOLON {
if (context->loopNestingLevel <= 0) { $$ = context->addBranch(EOpBreak, $1.line);
context->error($1.line, "break statement only allowed in loops", "");
context->recover();
}
$$ = context->intermediate.addBranch(EOpBreak, $1.line);
} }
| RETURN SEMICOLON { | RETURN SEMICOLON {
$$ = context->intermediate.addBranch(EOpReturn, $1.line); $$ = context->addBranch(EOpReturn, $1.line);
if (context->currentFunctionType->getBasicType() != EbtVoid) {
context->error($1.line, "non-void function must return a value", "return");
context->recover();
}
} }
| RETURN expression SEMICOLON { | RETURN expression SEMICOLON {
$$ = context->intermediate.addBranch(EOpReturn, $2, $1.line); $$ = context->addBranch(EOpReturn, $2, $1.line);
context->functionReturnsValue = true;
if (context->currentFunctionType->getBasicType() == EbtVoid) {
context->error($1.line, "void function cannot return a value", "return");
context->recover();
} else if (*(context->currentFunctionType) != $2->getType()) {
context->error($1.line, "function return is not matching type:", "return");
context->recover();
}
} }
| DISCARD SEMICOLON { | DISCARD SEMICOLON {
FRAG_ONLY("discard", $1.line); FRAG_ONLY("discard", $1.line);
$$ = context->intermediate.addBranch(EOpKill, $1.line); $$ = context->addBranch(EOpKill, $1.line);
} }
; ;
...@@ -2065,7 +2067,7 @@ function_definition ...@@ -2065,7 +2067,7 @@ function_definition
// knows where to find parameters. // knows where to find parameters.
// //
TIntermAggregate* paramNodes = new TIntermAggregate; TIntermAggregate* paramNodes = new TIntermAggregate;
for (int i = 0; i < function->getParamCount(); i++) { for (size_t i = 0; i < function->getParamCount(); i++) {
const TParameter& param = function->getParam(i); const TParameter& param = function->getParam(i);
if (param.name != 0) { if (param.name != 0) {
TVariable *variable = new TVariable(param.name, *param.type); TVariable *variable = new TVariable(param.name, *param.type);
......
...@@ -193,6 +193,8 @@ typedef union YYSTYPE ...@@ -193,6 +193,8 @@ typedef union YYSTYPE
TIntermNodePair nodePair; TIntermNodePair nodePair;
TIntermTyped* intermTypedNode; TIntermTyped* intermTypedNode;
TIntermAggregate* intermAggregate; TIntermAggregate* intermAggregate;
TIntermSwitch* intermSwitch;
TIntermCase* intermCase;
}; };
union { union {
TPublicType type; TPublicType type;
......
...@@ -78,7 +78,7 @@ void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth) ...@@ -78,7 +78,7 @@ void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
void TOutputTraverser::visitSymbol(TIntermSymbol* node) void TOutputTraverser::visitSymbol(TIntermSymbol* node)
{ {
OutputTreeText(sink, node, depth); OutputTreeText(sink, node, mDepth);
sink << "'" << node->getSymbol() << "' "; sink << "'" << node->getSymbol() << "' ";
sink << "(" << node->getCompleteString() << ")\n"; sink << "(" << node->getCompleteString() << ")\n";
...@@ -88,7 +88,7 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node) ...@@ -88,7 +88,7 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
{ {
TInfoSinkBase& out = sink; TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth); OutputTreeText(out, node, mDepth);
switch (node->getOp()) { switch (node->getOp()) {
case EOpAssign: out << "move second child to first child"; break; case EOpAssign: out << "move second child to first child"; break;
...@@ -152,7 +152,7 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node) ...@@ -152,7 +152,7 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
{ {
TInfoSinkBase& out = sink; TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth); OutputTreeText(out, node, mDepth);
switch (node->getOp()) { switch (node->getOp()) {
case EOpNegative: out << "Negate value"; break; case EOpNegative: out << "Negate value"; break;
...@@ -243,7 +243,7 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) ...@@ -243,7 +243,7 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
return true; return true;
} }
OutputTreeText(out, node, depth); OutputTreeText(out, node, mDepth);
switch (node->getOp()) { switch (node->getOp()) {
case EOpSequence: out << "Sequence\n"; return true; case EOpSequence: out << "Sequence\n"; return true;
...@@ -316,18 +316,18 @@ bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node) ...@@ -316,18 +316,18 @@ bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
{ {
TInfoSinkBase& out = sink; TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth); OutputTreeText(out, node, mDepth);
out << "Test condition and select"; out << "Test condition and select";
out << " (" << node->getCompleteString() << ")\n"; out << " (" << node->getCompleteString() << ")\n";
++depth; ++mDepth;
OutputTreeText(sink, node, depth); OutputTreeText(sink, node, mDepth);
out << "Condition\n"; out << "Condition\n";
node->getCondition()->traverse(this); node->getCondition()->traverse(this);
OutputTreeText(sink, node, depth); OutputTreeText(sink, node, mDepth);
if (node->getTrueBlock()) { if (node->getTrueBlock()) {
out << "true case\n"; out << "true case\n";
node->getTrueBlock()->traverse(this); node->getTrueBlock()->traverse(this);
...@@ -335,12 +335,12 @@ bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node) ...@@ -335,12 +335,12 @@ bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
out << "true case is null\n"; out << "true case is null\n";
if (node->getFalseBlock()) { if (node->getFalseBlock()) {
OutputTreeText(sink, node, depth); OutputTreeText(sink, node, mDepth);
out << "false case\n"; out << "false case\n";
node->getFalseBlock()->traverse(this); node->getFalseBlock()->traverse(this);
} }
--depth; --mDepth;
return false; return false;
} }
...@@ -352,7 +352,7 @@ void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) ...@@ -352,7 +352,7 @@ void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
int size = node->getType().getObjectSize(); int size = node->getType().getObjectSize();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
OutputTreeText(out, node, depth); OutputTreeText(out, node, mDepth);
switch (node->getUnionArrayPointer()[i].getType()) { switch (node->getUnionArrayPointer()[i].getType()) {
case EbtBool: case EbtBool:
if (node->getUnionArrayPointer()[i].getBConst()) if (node->getUnionArrayPointer()[i].getBConst())
...@@ -386,23 +386,23 @@ bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node) ...@@ -386,23 +386,23 @@ bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
{ {
TInfoSinkBase& out = sink; TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth); OutputTreeText(out, node, mDepth);
out << "Loop with condition "; out << "Loop with condition ";
if (node->getType() == ELoopDoWhile) if (node->getType() == ELoopDoWhile)
out << "not "; out << "not ";
out << "tested first\n"; out << "tested first\n";
++depth; ++mDepth;
OutputTreeText(sink, node, depth); OutputTreeText(sink, node, mDepth);
if (node->getCondition()) { if (node->getCondition()) {
out << "Loop Condition\n"; out << "Loop Condition\n";
node->getCondition()->traverse(this); node->getCondition()->traverse(this);
} else } else
out << "No loop condition\n"; out << "No loop condition\n";
OutputTreeText(sink, node, depth); OutputTreeText(sink, node, mDepth);
if (node->getBody()) { if (node->getBody()) {
out << "Loop Body\n"; out << "Loop Body\n";
node->getBody()->traverse(this); node->getBody()->traverse(this);
...@@ -410,12 +410,12 @@ bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node) ...@@ -410,12 +410,12 @@ bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
out << "No loop body\n"; out << "No loop body\n";
if (node->getExpression()) { if (node->getExpression()) {
OutputTreeText(sink, node, depth); OutputTreeText(sink, node, mDepth);
out << "Loop Terminal Expression\n"; out << "Loop Terminal Expression\n";
node->getExpression()->traverse(this); node->getExpression()->traverse(this);
} }
--depth; --mDepth;
return false; return false;
} }
...@@ -424,7 +424,7 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) ...@@ -424,7 +424,7 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
{ {
TInfoSinkBase& out = sink; TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth); OutputTreeText(out, node, mDepth);
switch (node->getFlowOp()) { switch (node->getFlowOp()) {
case EOpKill: out << "Branch: Kill"; break; case EOpKill: out << "Branch: Kill"; break;
...@@ -436,9 +436,9 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) ...@@ -436,9 +436,9 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
if (node->getExpression()) { if (node->getExpression()) {
out << " with expression\n"; out << " with expression\n";
++depth; ++mDepth;
node->getExpression()->traverse(this); node->getExpression()->traverse(this);
--depth; --mDepth;
} else } else
out << "\n"; out << "\n";
......
...@@ -242,6 +242,8 @@ class TIntermSymbol; ...@@ -242,6 +242,8 @@ class TIntermSymbol;
class TIntermLoop; class TIntermLoop;
class TIntermBranch; class TIntermBranch;
class TInfoSink; class TInfoSink;
class TIntermSwitch;
class TIntermCase;
// //
// Base class for the tree nodes // Base class for the tree nodes
...@@ -265,6 +267,8 @@ public: ...@@ -265,6 +267,8 @@ public:
virtual TIntermSymbol* getAsSymbolNode() { return 0; } virtual TIntermSymbol* getAsSymbolNode() { return 0; }
virtual TIntermLoop* getAsLoopNode() { return 0; } virtual TIntermLoop* getAsLoopNode() { return 0; }
virtual TIntermBranch* getAsBranchNode() { return 0; } virtual TIntermBranch* getAsBranchNode() { return 0; }
virtual TIntermSwitch *getAsSwitchNode() { return 0; }
virtual TIntermCase *getAsCaseNode() { return 0; }
virtual ~TIntermNode() { } virtual ~TIntermNode() { }
protected: protected:
...@@ -554,6 +558,49 @@ protected: ...@@ -554,6 +558,49 @@ protected:
TIntermNode* falseBlock; TIntermNode* falseBlock;
}; };
//
// Switch statement.
//
class TIntermSwitch : public TIntermNode
{
public:
TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList)
: TIntermNode(), mInit(init), mStatementList(statementList)
{}
void traverse(TIntermTraverser *it);
TIntermSwitch *getAsSwitchNode() { return this; }
TIntermAggregate *getStatementList() { return mStatementList; }
void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; }
protected:
TIntermTyped *mInit;
TIntermAggregate *mStatementList;
};
//
// Case label.
//
class TIntermCase : public TIntermNode
{
public:
TIntermCase(TIntermTyped *condition)
: TIntermNode(), mCondition(condition)
{}
void traverse(TIntermTraverser *it);
TIntermCase *getAsCaseNode() { return this; }
bool hasCondition() const { return mCondition != nullptr; }
TIntermTyped *getCondition() const { return mCondition; }
protected:
TIntermTyped *mCondition;
};
enum Visit enum Visit
{ {
PreVisit, PreVisit,
...@@ -578,7 +625,7 @@ public: ...@@ -578,7 +625,7 @@ public:
inVisit(inVisit), inVisit(inVisit),
postVisit(postVisit), postVisit(postVisit),
rightToLeft(rightToLeft), rightToLeft(rightToLeft),
depth(0) {} mDepth(0) {}
virtual ~TIntermTraverser() {}; virtual ~TIntermTraverser() {};
virtual void visitSymbol(TIntermSymbol*) {} virtual void visitSymbol(TIntermSymbol*) {}
...@@ -589,9 +636,25 @@ public: ...@@ -589,9 +636,25 @@ public:
virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
virtual bool visitSwitch(Visit, TIntermSwitch*) { return true; }
virtual bool visitCase(Visit, TIntermCase*) { return true; }
void incrementDepth(TIntermNode *current)
{
mDepth++;
mPath.push_back(current);
}
void incrementDepth() {depth++;} void decrementDepth()
void decrementDepth() {depth--;} {
mDepth--;
mPath.pop_back();
}
TIntermNode *getParentNode()
{
return mPath.size() == 0 ? NULL : mPath.back();
}
const bool preVisit; const bool preVisit;
const bool inVisit; const bool inVisit;
...@@ -599,7 +662,23 @@ public: ...@@ -599,7 +662,23 @@ public:
const bool rightToLeft; const bool rightToLeft;
protected: protected:
int depth; int mDepth;
// All the nodes from root to the current node's parent during traversing.
TVector<TIntermNode *> mPath;
private:
struct ParentBlock
{
ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn)
: node(nodeIn), pos(posIn)
{}
TIntermAggregate *node;
TIntermSequence::size_type pos;
};
// All the code blocks from the root to the current node's parent during traversal.
std::vector<ParentBlock> mParentBlockStack;
}; };
#endif // __INTERMEDIATE_H #endif // __INTERMEDIATE_H
...@@ -33,6 +33,8 @@ public: ...@@ -33,6 +33,8 @@ public:
TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc); TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc);
TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc); TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc); TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc);
TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &line);
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc); TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, TSourceLoc); TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, TSourceLoc);
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*); TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*);
......
...@@ -297,6 +297,8 @@ ...@@ -297,6 +297,8 @@
<Unit filename="../compiler/Types.h" /> <Unit filename="../compiler/Types.h" />
<Unit filename="../compiler/ValidateLimitations.cpp" /> <Unit filename="../compiler/ValidateLimitations.cpp" />
<Unit filename="../compiler/ValidateLimitations.h" /> <Unit filename="../compiler/ValidateLimitations.h" />
<Unit filename="../compiler/ValidateSwitch.cpp" />
<Unit filename="../compiler/ValidateSwitch.h" />
<Unit filename="../compiler/debug.cpp" /> <Unit filename="../compiler/debug.cpp" />
<Unit filename="../compiler/debug.h" /> <Unit filename="../compiler/debug.h" />
<Unit filename="../compiler/glslang.h" /> <Unit filename="../compiler/glslang.h" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment