HLSL: Implement proper nesting of symbol-table scopes and identifier searching.

This commit is contained in:
John Kessenich
2016-06-09 02:02:17 -06:00
parent 71351de879
commit 077e052a8f
9 changed files with 204 additions and 51 deletions

View File

@@ -209,9 +209,6 @@ void HlslGrammar::acceptQualifier(TQualifier& qualifier)
// Otherwise, return false, and don't advance
bool HlslGrammar::acceptType(TType& type)
{
if (! token.isType)
return false;
switch (peek()) {
case EHTokVoid:
new(&type) TType(EbtVoid);
@@ -616,7 +613,7 @@ bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& no
{
TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
// This does a symbol table push
// This does a pushScope()
node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
// compound_statement
@@ -625,7 +622,7 @@ bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& no
node = intermediate.growAggregate(node, functionBody);
intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
parseContext.symbolTable.pop(nullptr);
parseContext.popScope();
return true;
}
@@ -882,7 +879,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
} else if (acceptIdentifier(idToken)) {
// identifier or function_call name
if (! peekTokenClass(EHTokLeftParen)) {
node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
node = parseContext.handleVariable(idToken.loc, token.string);
} else if (acceptFunctionCall(idToken, node)) {
// function_call (nothing else to do yet)
} else {
@@ -1072,17 +1069,17 @@ bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
{
parseContext.pushScope();
bool result = acceptNestedStatement(statement);
bool result = acceptStatement(statement);
parseContext.popScope();
return result;
}
bool HlslGrammar::acceptNestedStatement(TIntermNode*& statement)
bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
{
parseContext.nestStatement();
bool result = acceptStatement(statement);
parseContext.unnestStatement();
parseContext.pushScope();
bool result = acceptCompoundStatement(statement);
parseContext.popScope();
return result;
}
@@ -1111,7 +1108,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
// attributed_statement
switch (peek()) {
case EHTokLeftBrace:
return acceptCompoundStatement(statement);
return acceptScopedCompoundStatement(statement);
case EHTokIf:
return acceptSelectionStatement(statement);

View File

@@ -77,6 +77,7 @@ namespace glslang {
bool acceptCompoundStatement(TIntermNode*&);
bool acceptStatement(TIntermNode*&);
bool acceptScopedStatement(TIntermNode*&);
bool acceptScopedCompoundStatement(TIntermNode*&);
bool acceptNestedStatement(TIntermNode*&);
void acceptAttributes();
bool acceptSelectionStatement(TIntermNode*&);

View File

@@ -51,7 +51,7 @@ HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& int
int version, EProfile profile, int spv, int vulkan, EShLanguage language, TInfoSink& infoSink,
bool forwardCompatible, EShMessages messages) :
TParseContextBase(symbolTable, interm, version, profile, spv, vulkan, language, infoSink, forwardCompatible, messages),
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0),
postMainReturn(false),
limits(resources.limits),
afterEOF(false)
@@ -282,8 +282,9 @@ void C_DECL HlslParseContext::ppWarn(const TSourceLoc& loc, const char* szReason
//
// Handle seeing a variable identifier in the grammar.
//
TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symbol, const TString* string)
TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TString* string)
{
TSymbol* symbol = symbolTable.find(*string);
TIntermTyped* node = nullptr;
// Error check for requiring specific extensions present.
@@ -714,7 +715,7 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
//
// New symbol table scope for body of function plus its arguments
//
symbolTable.push();
pushScope();
//
// Insert parameters into the symbol table.
@@ -747,7 +748,6 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
}
intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
loopNestingLevel = 0;
statementNestingLevel = 0;
controlFlowNestingLevel = 0;
postMainReturn = false;

View File

@@ -65,7 +65,7 @@ public:
bool builtInName(const TString&);
void handlePragma(const TSourceLoc&, const TVector<TString>&);
TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string);
TIntermTyped* handleVariable(const TSourceLoc&, const TString* string);
TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
void checkIndex(const TSourceLoc&, const TType&, int& index);
@@ -139,8 +139,6 @@ public:
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
void nestStatement() { ++statementNestingLevel; }
void unnestStatement() { --statementNestingLevel; }
void nestLooping() { ++loopNestingLevel; }
void unnestLooping() { --loopNestingLevel; }
void pushScope() { symbolTable.push(); }
@@ -163,7 +161,6 @@ protected:
int loopNestingLevel; // 0 if outside all loops
int structNestingLevel; // 0 if outside blocks and structures
int controlFlowNestingLevel; // 0 if outside all flow control
int statementNestingLevel; // 0 if outside all flow control or compound statements
TList<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting
TList<int> switchLevel; // the statementNestingLevel the current switch statement is at, which must match the level of its case statements
bool inEntrypoint; // if inside a function, true if the function is the entry point

View File

@@ -314,11 +314,8 @@ void HlslScanContext::deleteKeywordMap()
// Wrapper for tokenizeClass()"] = to get everything inside the token.
void HlslScanContext::tokenize(HlslToken& token)
{
token.isType = false;
EHlslTokenClass tokenClass = tokenizeClass(token);
token.tokenClass = tokenClass;
if (token.isType)
afterType = true;
}
//
@@ -338,13 +335,13 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token)
loc = ppToken.loc;
parserToken->loc = loc;
switch (ppToken.token) {
case ';': afterType = false; return EHTokSemicolon;
case ',': afterType = false; return EHTokComma;
case ';': return EHTokSemicolon;
case ',': return EHTokComma;
case ':': return EHTokColon;
case '=': afterType = false; return EHTokAssign;
case '(': afterType = false; return EHTokLeftParen;
case ')': afterType = false; return EHTokRightParen;
case '.': field = true; return EHTokDot;
case '=': return EHTokAssign;
case '(': return EHTokLeftParen;
case ')': return EHTokRightParen;
case '.': return EHTokDot;
case '!': return EHTokBang;
case '-': return EHTokDash;
case '~': return EHTokTilde;
@@ -400,7 +397,6 @@ EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token)
case PpAtomIdentifier:
{
EHlslTokenClass token = tokenizeIdentifier();
field = false;
return token;
}
@@ -542,7 +538,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
case EHTokDouble4x2:
case EHTokDouble4x3:
case EHTokDouble4x4:
parserToken->isType = true;
return keyword;
// texturing types
@@ -560,7 +555,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
case EHTokTexture2darray:
case EHTokTexture3d:
case EHTokTextureCube:
parserToken->isType = true;
return keyword;
// variable, user type, ...
@@ -598,19 +592,6 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
EHlslTokenClass HlslScanContext::identifierOrType()
{
parserToken->string = NewPoolTString(tokenText);
if (field)
return EHTokIdentifier;
parserToken->symbol = parseContext.symbolTable.find(*parserToken->string);
if (afterType == false && parserToken->symbol) {
if (const TVariable* variable = parserToken->symbol->getAsVariable()) {
if (variable->isUserType()) {
afterType = true;
return EHTokTypeName;
}
}
}
return EHTokIdentifier;
}

View File

@@ -54,10 +54,9 @@ class TPpToken;
// Everything needed to fully describe a token.
//
struct HlslToken {
HlslToken() : isType(false), string(nullptr), symbol(nullptr) { loc.init(); }
HlslToken() : string(nullptr) { loc.init(); }
TSourceLoc loc; // location of token in the source
EHlslTokenClass tokenClass; // what kind of token it is
bool isType; // true if the token represents a type
union { // what data the token holds
glslang::TString *string; // for identifiers
int i; // for literals
@@ -65,7 +64,6 @@ struct HlslToken {
bool b;
double d;
};
glslang::TSymbol* symbol; // if a symbol table lookup was done already, this is the result
};
//
@@ -76,7 +74,7 @@ struct HlslToken {
class HlslScanContext {
public:
HlslScanContext(TParseContextBase& parseContext, TPpContext& ppContext)
: parseContext(parseContext), ppContext(ppContext), afterType(false), field(false) { }
: parseContext(parseContext), ppContext(ppContext) { }
virtual ~HlslScanContext() { }
static void fillInKeywordMap();
@@ -97,8 +95,6 @@ protected:
TParseContextBase& parseContext;
TPpContext& ppContext;
bool afterType; // true if we've recognized a type, so can only be looking for an identifier
bool field; // true if we're on a field, right after a '.'
TSourceLoc loc;
TPpToken* ppToken;
HlslToken* parserToken;