Commit 407813b4 by Alexis Hetu Committed by Alexis Hétu

Parser cleanup

Ported some changes from Angle. Added 4 new functions to ParserHelper to remove some code from glslang.y. Added some extra checks regarding qualifiers and precision. Change-Id: I2856a764749bef0df500891eb4c003211e634673 Reviewed-on: https://swiftshader-review.googlesource.com/4900Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <capn@google.com>
parent 555f7e1a
......@@ -1751,6 +1751,237 @@ void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
}
}
TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &function, const TSourceLoc &location)
{
// Note: symbolTableFunction could be the same as function if this is the first declaration.
// Either way the instance in the symbol table is used to track whether the function is declared
// multiple times.
TFunction *symbolTableFunction =
static_cast<TFunction *>(symbolTable.find(function.getMangledName(), getShaderVersion()));
if(symbolTableFunction->hasPrototypeDeclaration() && mShaderVersion == 100)
{
// ESSL 1.00.17 section 4.2.7.
// Doesn't apply to ESSL 3.00.4: see section 4.2.3.
error(location, "duplicate function prototype declarations are not allowed", "function");
recover();
}
symbolTableFunction->setHasPrototypeDeclaration();
TIntermAggregate *prototype = new TIntermAggregate;
prototype->setType(function.getReturnType());
prototype->setName(function.getMangledName());
for(size_t i = 0; i < function.getParamCount(); i++)
{
const TParameter &param = function.getParam(i);
if(param.name != 0)
{
TVariable variable(param.name, *param.type);
TIntermSymbol *paramSymbol = intermediate.addSymbol(
variable.getUniqueId(), variable.getName(), variable.getType(), location);
prototype = intermediate.growAggregate(prototype, paramSymbol, location);
}
else
{
TIntermSymbol *paramSymbol = intermediate.addSymbol(0, "", *param.type, location);
prototype = intermediate.growAggregate(prototype, paramSymbol, location);
}
}
prototype->setOp(EOpPrototype);
symbolTable.pop();
if(!symbolTable.atGlobalLevel())
{
// ESSL 3.00.4 section 4.2.4.
error(location, "local function prototype declarations are not allowed", "function");
recover();
}
return prototype;
}
TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function, TIntermAggregate *functionPrototype, TIntermAggregate *functionBody, const TSourceLoc &location)
{
//?? Check that all paths return a value if return type != void ?
// May be best done as post process phase on intermediate code
if(mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue)
{
error(location, "function does not return a value:", "", function.getName().c_str());
recover();
}
TIntermAggregate *aggregate = intermediate.growAggregate(functionPrototype, functionBody, location);
intermediate.setAggregateOperator(aggregate, EOpFunction, location);
aggregate->setName(function.getMangledName().c_str());
aggregate->setType(function.getReturnType());
// store the pragma information for debug and optimize and other vendor specific
// information. This information can be queried from the parse tree
aggregate->setOptimize(pragma().optimize);
aggregate->setDebug(pragma().debug);
if(functionBody && functionBody->getAsAggregate())
aggregate->setEndLine(functionBody->getAsAggregate()->getEndLine());
symbolTable.pop();
return aggregate;
}
void TParseContext::parseFunctionPrototype(const TSourceLoc &location, TFunction *function, TIntermAggregate **aggregateOut)
{
const TSymbol *builtIn = symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
if(builtIn)
{
error(location, "built-in functions cannot be redefined", function->getName().c_str());
recover();
}
TFunction *prevDec = static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
//
// Note: 'prevDec' could be 'function' if this is the first time we've seen function
// as it would have just been put in the symbol table. Otherwise, we're looking up
// an earlier occurance.
//
if(prevDec->isDefined())
{
// Then this function already has a body.
error(location, "function already has a body", function->getName().c_str());
recover();
}
prevDec->setDefined();
//
// Overload the unique ID of the definition to be the same unique ID as the declaration.
// Eventually we will probably want to have only a single definition and just swap the
// arguments to be the definition's arguments.
//
function->setUniqueId(prevDec->getUniqueId());
// Raise error message if main function takes any parameters or return anything other than void
if(function->getName() == "main")
{
if(function->getParamCount() > 0)
{
error(location, "function cannot take any parameter(s)", function->getName().c_str());
recover();
}
if(function->getReturnType().getBasicType() != EbtVoid)
{
error(location, "", function->getReturnType().getBasicString(), "main function cannot return a value");
recover();
}
}
//
// Remember the return type for later checking for RETURN statements.
//
mCurrentFunctionType = &(prevDec->getReturnType());
mFunctionReturnsValue = false;
//
// Insert parameters into the symbol table.
// If the parameter has no name, it's not an error, just don't insert it
// (could be used for unused args).
//
// Also, accumulate the list of parameters into the HIL, so lower level code
// knows where to find parameters.
//
TIntermAggregate *paramNodes = new TIntermAggregate;
for(size_t i = 0; i < function->getParamCount(); i++)
{
const TParameter &param = function->getParam(i);
if(param.name != 0)
{
TVariable *variable = new TVariable(param.name, *param.type);
//
// Insert the parameters with name in the symbol table.
//
if(!symbolTable.declare(*variable))
{
error(location, "redefinition", variable->getName().c_str());
recover();
paramNodes = intermediate.growAggregate(
paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
continue;
}
//
// Add the parameter to the HIL
//
TIntermSymbol *symbol = intermediate.addSymbol(
variable->getUniqueId(), variable->getName(), variable->getType(), location);
paramNodes = intermediate.growAggregate(paramNodes, symbol, location);
}
else
{
paramNodes = intermediate.growAggregate(
paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
}
}
intermediate.setAggregateOperator(paramNodes, EOpParameters, location);
*aggregateOut = paramNodes;
setLoopNestingLevel(0);
}
TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
{
//
// We don't know at this point whether this is a function definition or a prototype.
// The definition production code will check for redefinitions.
// In the case of ESSL 1.00 the prototype production code will also check for redeclarations.
//
// Return types and parameter qualifiers must match in all redeclarations, so those are checked
// here.
//
TFunction *prevDec = static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
if(prevDec)
{
if(prevDec->getReturnType() != function->getReturnType())
{
error(location, "overloaded functions must have the same return type",
function->getReturnType().getBasicString());
recover();
}
for(size_t i = 0; i < prevDec->getParamCount(); ++i)
{
if(prevDec->getParam(i).type->getQualifier() != function->getParam(i).type->getQualifier())
{
error(location, "overloaded functions must have the same parameter qualifiers",
function->getParam(i).type->getQualifierString());
recover();
}
}
}
//
// Check for previously declared variables using the same name.
//
TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
if(prevSym)
{
if(!prevSym->isFunction())
{
error(location, "redefinition", function->getName().c_str(), "function");
recover();
}
}
// We're at the inner scope level of the function's arguments and body statement.
// Add the function prototype to the surrounding scope instead.
symbolTable.getOuterLevel()->insert(*function);
//
// If this is a redeclaration, it could also be a definition, in which case, we want to use the
// variable names from this one, and not the one that's
// being redeclared. So, pass back up this declaration, not the one in the symbol table.
//
return function;
}
TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
{
TPublicType publicType = publicTypeIn;
......
......@@ -34,7 +34,7 @@ public:
lexAfterType(false),
inTypeParen(false),
AfterEOF(false),
mDeferredSingleDeclarationErrorCheck(false),
mDeferredSingleDeclarationErrorCheck(false),
mShaderType(type),
mShaderVersion(100),
mTreeRoot(0),
......@@ -43,13 +43,13 @@ public:
mStructNestingLevel(0),
mCurrentFunctionType(NULL),
mFunctionReturnsValue(false),
mChecksPrecisionErrors(checksPrecErrors),
mChecksPrecisionErrors(checksPrecErrors),
mDefaultMatrixPacking(EmpColumnMajor),
mDefaultBlockStorage(EbsShared),
mDefaultBlockStorage(EbsShared),
mDiagnostics(is),
mDirectiveHandler(ext, mDiagnostics, mShaderVersion),
mPreprocessor(&mDiagnostics, &mDirectiveHandler),
mScanner(NULL),
mScanner(NULL),
mUsesFragData(false),
mUsesFragColor(false) { }
TIntermediate& intermediate; // to hold and build a parse tree
......@@ -60,13 +60,13 @@ public:
bool inTypeParen; // true if in parentheses, looking only for an identifier
bool AfterEOF;
const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
pp::Preprocessor &getPreprocessor() { return mPreprocessor; }
void *getScanner() const { return mScanner; }
void setScanner(void *scanner) { mScanner = scanner; }
int getShaderVersion() const { return mShaderVersion; }
GLenum getShaderType() const { return mShaderType; }
int numErrors() const { return mDiagnostics.numErrors(); }
const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
pp::Preprocessor &getPreprocessor() { return mPreprocessor; }
void *getScanner() const { return mScanner; }
void setScanner(void *scanner) { mScanner = scanner; }
int getShaderVersion() const { return mShaderVersion; }
GLenum getShaderType() const { return mShaderType; }
int numErrors() const { return mDiagnostics.numErrors(); }
TInfoSink &infoSink() { return mDiagnostics.infoSink(); }
void error(const TSourceLoc &loc, const char *reason, const char* token,
const char* extraInfo="");
......@@ -74,30 +74,30 @@ public:
const char* extraInfo="");
void trace(const char* str);
void recover();
TIntermNode *getTreeRoot() const { return mTreeRoot; }
void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; }
bool getFunctionReturnsValue() const { return mFunctionReturnsValue; }
void setFunctionReturnsValue(bool functionReturnsValue)
{
mFunctionReturnsValue = functionReturnsValue;
}
void setLoopNestingLevel(int loopNestintLevel)
{
mLoopNestingLevel = loopNestintLevel;
}
const TType *getCurrentFunctionType() const { return mCurrentFunctionType; }
void setCurrentFunctionType(const TType *currentFunctionType)
{
mCurrentFunctionType = currentFunctionType;
}
void incrLoopNestingLevel() { ++mLoopNestingLevel; }
void decrLoopNestingLevel() { --mLoopNestingLevel; }
void incrSwitchNestingLevel() { ++mSwitchNestingLevel; }
TIntermNode *getTreeRoot() const { return mTreeRoot; }
void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; }
bool getFunctionReturnsValue() const { return mFunctionReturnsValue; }
void setFunctionReturnsValue(bool functionReturnsValue)
{
mFunctionReturnsValue = functionReturnsValue;
}
void setLoopNestingLevel(int loopNestintLevel)
{
mLoopNestingLevel = loopNestintLevel;
}
const TType *getCurrentFunctionType() const { return mCurrentFunctionType; }
void setCurrentFunctionType(const TType *currentFunctionType)
{
mCurrentFunctionType = currentFunctionType;
}
void incrLoopNestingLevel() { ++mLoopNestingLevel; }
void decrLoopNestingLevel() { --mLoopNestingLevel; }
void incrSwitchNestingLevel() { ++mSwitchNestingLevel; }
void decrSwitchNestingLevel() { --mSwitchNestingLevel; }
// This method is guaranteed to succeed, even if no variable with 'name' exists.
......@@ -179,6 +179,10 @@ public:
const TSourceLoc &initLocation, TIntermTyped *initializer);
void parseGlobalLayoutQualifier(const TPublicType &typeQualifier);
TIntermAggregate *addFunctionPrototypeDeclaration(const TFunction &function, const TSourceLoc &location);
TIntermAggregate *addFunctionDefinition(const TFunction &function, TIntermAggregate *functionPrototype, TIntermAggregate *functionBody, const TSourceLoc &location);
void parseFunctionPrototype(const TSourceLoc &location, TFunction *function, TIntermAggregate **aggregateOut);
TFunction *parseFunctionDeclarator(const TSourceLoc &location, TFunction *function);
TFunction *addConstructorFunc(const TPublicType &publicType);
TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&);
TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
......@@ -239,26 +243,26 @@ private:
// Return true if the checks pass
bool binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
// Set to true when the last/current declarator list was started with an empty declaration.
bool mDeferredSingleDeclarationErrorCheck;
GLenum mShaderType; // vertex or fragment language (future: pack or unpack)
int mShaderVersion;
TIntermNode *mTreeRoot; // root of parse tree being created
int mLoopNestingLevel; // 0 if outside all loops
int mSwitchNestingLevel; // 0 if outside all switch statements
int mStructNestingLevel; // incremented while parsing a struct declaration
const TType *mCurrentFunctionType; // the return type of the function that's currently being parsed
bool mFunctionReturnsValue; // true if a non-void function has a return
bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
TLayoutMatrixPacking mDefaultMatrixPacking;
TLayoutBlockStorage mDefaultBlockStorage;
TDiagnostics mDiagnostics;
TDirectiveHandler mDirectiveHandler;
pp::Preprocessor mPreprocessor;
void *mScanner;
bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
// Set to true when the last/current declarator list was started with an empty declaration.
bool mDeferredSingleDeclarationErrorCheck;
GLenum mShaderType; // vertex or fragment language (future: pack or unpack)
int mShaderVersion;
TIntermNode *mTreeRoot; // root of parse tree being created
int mLoopNestingLevel; // 0 if outside all loops
int mSwitchNestingLevel; // 0 if outside all switch statements
int mStructNestingLevel; // incremented while parsing a struct declaration
const TType *mCurrentFunctionType; // the return type of the function that's currently being parsed
bool mFunctionReturnsValue; // true if a non-void function has a return
bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
TLayoutMatrixPacking mDefaultMatrixPacking;
TLayoutBlockStorage mDefaultBlockStorage;
TDiagnostics mDiagnostics;
TDirectiveHandler mDirectiveHandler;
pp::Preprocessor mPreprocessor;
void *mScanner;
bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
bool mUsesFragColor;
};
......
......@@ -134,14 +134,16 @@ public:
TSymbol(0),
returnType(TType(EbtVoid, EbpUndefined)),
op(o),
defined(false) { }
TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull, const char *ext = "") :
defined(false),
prototypeDeclaration(false) { }
TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull, const char *ext = "") :
TSymbol(name),
returnType(retType),
mangledName(TFunction::mangleName(*name)),
op(tOp),
extension(ext),
defined(false) { }
defined(false),
prototypeDeclaration(false) { }
virtual ~TFunction();
virtual bool isFunction() const { return true; }
......@@ -165,6 +167,8 @@ public:
void setDefined() { defined = true; }
bool isDefined() { return defined; }
void setHasPrototypeDeclaration() { prototypeDeclaration = true; }
bool hasPrototypeDeclaration() const { return prototypeDeclaration; }
size_t getParamCount() const { return parameters.size(); }
const TParameter& getParam(int i) const { return parameters[i]; }
......@@ -177,6 +181,7 @@ protected:
TOperator op;
TString extension;
bool defined;
bool prototypeDeclaration;
};
......
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