Commit c3648898 by Nicolas Capens

Support parsing defined operator generated by macro expansion

dEQP tests enforce that the defined operator should be parsed even when it is generated as a result of macro expansion, even though this is undefined according to the C++ preprocessor spec. Implement support for this by putting the parsing for the defined operator inside MacroExpander. The operator gets processed right after it is generated by macro expansion. Parsing the defined operator is toggled with a boolean according to the context where MacroExpander is used. Change-Id: I8557e829f4278ab6cb27eb4a0f84ca0c0dd18d1a Reviewed-on: https://swiftshader-review.googlesource.com/5182Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <capn@google.com> Tested-by: 's avatarNicolas Capens <capn@google.com>
parent d0e6f680
......@@ -139,71 +139,6 @@ static bool isMacroPredefined(const std::string& name,
namespace pp
{
class DefinedParser : public Lexer
{
public:
DefinedParser(Lexer* lexer,
const MacroSet* macroSet,
Diagnostics* diagnostics) :
mLexer(lexer),
mMacroSet(macroSet),
mDiagnostics(diagnostics)
{
}
protected:
virtual void lex(Token* token)
{
static const std::string kDefined("defined");
mLexer->lex(token);
if (token->type != Token::IDENTIFIER)
return;
if (token->text != kDefined)
return;
bool paren = false;
mLexer->lex(token);
if (token->type == '(')
{
paren = true;
mLexer->lex(token);
}
if (token->type != Token::IDENTIFIER)
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
token->location, token->text);
skipUntilEOD(mLexer, token);
return;
}
MacroSet::const_iterator iter = mMacroSet->find(token->text);
std::string expression = iter != mMacroSet->end() ? "1" : "0";
if (paren)
{
mLexer->lex(token);
if (token->type != ')')
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
token->location, token->text);
skipUntilEOD(mLexer, token);
return;
}
}
// We have a valid defined operator.
// Convert the current token into a CONST_INT token.
token->type = Token::CONST_INT;
token->text = expression;
}
private:
Lexer* mLexer;
const MacroSet* mMacroSet;
Diagnostics* mDiagnostics;
};
DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
MacroSet* macroSet,
Diagnostics* diagnostics,
......@@ -794,7 +729,7 @@ void DirectiveParser::parseLine(Token* token)
int line = 0, file = 0;
int state = LINE_NUMBER;
MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);
macroExpander.lex(token);
while ((token->type != '\n') && (token->type != Token::LAST))
{
......@@ -907,8 +842,7 @@ int DirectiveParser::parseExpressionIf(Token* token)
assert((getDirective(token) == DIRECTIVE_IF) ||
(getDirective(token) == DIRECTIVE_ELIF));
DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);
ExpressionParser expressionParser(&macroExpander, mDiagnostics);
int expression = 0;
......
......@@ -48,10 +48,9 @@ class TokenLexer : public Lexer
MacroExpander::MacroExpander(Lexer* lexer,
MacroSet* macroSet,
Diagnostics* diagnostics) :
mLexer(lexer),
mMacroSet(macroSet),
mDiagnostics(diagnostics)
Diagnostics* diagnostics,
bool parseDefined) :
mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mParseDefined(parseDefined)
{
}
......@@ -72,6 +71,47 @@ void MacroExpander::lex(Token* token)
if (token->type != Token::IDENTIFIER)
break;
// Defined operator is parsed here since it may be generated by macro expansion.
// Defined operator produced by macro expansion has undefined behavior according to C++
// spec, which the GLSL spec references (see C++14 draft spec section 16.1.4), but this
// behavior is needed for passing dEQP tests, which enforce stricter compatibility between
// implementations.
if (mParseDefined && token->text == "defined")
{
bool paren = false;
getToken(token);
if (token->type == '(')
{
paren = true;
getToken(token);
}
if (token->type != Token::IDENTIFIER)
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,
token->text);
break;
}
auto iter = mMacroSet->find(token->text);
std::string expression = iter != mMacroSet->end() ? "1" : "0";
if (paren)
{
getToken(token);
if (token->type != ')')
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, token->location,
token->text);
break;
}
}
// We have a valid defined operator.
// Convert the current token into a CONST_INT token.
token->type = Token::CONST_INT;
token->text = expression;
break;
}
if (token->expansionDisabled())
break;
......@@ -315,7 +355,7 @@ bool MacroExpander::collectMacroArgs(const Macro& macro,
{
MacroArg& arg = args->at(i);
TokenLexer lexer(&arg);
MacroExpander expander(&lexer, mMacroSet, mDiagnostics);
MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined);
arg.clear();
expander.lex(&token);
......
......@@ -23,7 +23,7 @@ class Diagnostics;
class MacroExpander : public Lexer
{
public:
MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics);
MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics, bool parseDefined);
virtual ~MacroExpander();
virtual void lex(Token* token);
......@@ -65,6 +65,7 @@ class MacroExpander : public Lexer
Lexer* mLexer;
MacroSet* mMacroSet;
Diagnostics* mDiagnostics;
const bool mParseDefined;
std::auto_ptr<Token> mReserveToken;
std::vector<MacroContext*> mContextStack;
......
......@@ -27,12 +27,11 @@ struct PreprocessorImpl
DirectiveParser directiveParser;
MacroExpander macroExpander;
PreprocessorImpl(Diagnostics* diag,
DirectiveHandler* directiveHandler) :
PreprocessorImpl(Diagnostics* diag, DirectiveHandler* directiveHandler) :
diagnostics(diag),
tokenizer(diag),
directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
macroExpander(&directiveParser, &macroSet, diag)
macroExpander(&directiveParser, &macroSet, diag, false)
{
}
};
......
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