Preprocessor update from ANGLE

- Updated preprocessor code from Angle revision
  9fc8733187c02470a9eadb6d295348b6d37a2004
- Reran generate_parser.sh (flex 2.6.4, bison (GNU Bison) 3.0.4)
- Made a few trivial changes in src/OpenGL/compiler in order to
  adapt to the new preprocessor code.

Fixes all 24 failures in:
dEQP-GLES3.functional.shaders.preprocessor.*

Change-Id: I00d0b511d617ab81a0f57310174e1ba8bf7c22e5
Reviewed-on: https://swiftshader-review.googlesource.com/15109
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp b/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
index ec77c21..9eb044e 100644
--- a/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
+++ b/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
@@ -14,12 +14,13 @@
 
 #include "DirectiveParser.h"
 
+#include <algorithm>
 #include <cassert>
 #include <cstdlib>
 #include <sstream>
 
-#include "Diagnostics.h"
-#include "DirectiveHandler.h"
+#include "DiagnosticsBase.h"
+#include "DirectiveHandlerBase.h"
 #include "ExpressionParser.h"
 #include "MacroExpander.h"
 #include "Token.h"
@@ -45,7 +46,7 @@
 };
 }  // namespace
 
-static DirectiveType getDirective(const pp::Token* token)
+static DirectiveType getDirective(const pp::Token *token)
 {
 	static const std::string kDirectiveDefine("define");
 	static const std::string kDirectiveUndef("undef");
@@ -111,12 +112,12 @@
 }
 
 // Returns true if the token represents End Of Directive.
-static bool isEOD(const pp::Token* token)
+static bool isEOD(const pp::Token *token)
 {
 	return (token->type == '\n') || (token->type == pp::Token::LAST);
 }
 
-static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
+static void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
 {
 	while(!isEOD(token))
 	{
@@ -127,39 +128,105 @@
 static bool isMacroNameReserved(const std::string& name)
 {
 	// Names prefixed with "GL_" are reserved.
-	if (name.substr(0, 3) == "GL_")
-		return true;
+	return (name.substr(0, 3) == "GL_");
+}
 
-	// Names containing two consecutive underscores are reserved.
-	if (name.find("__") != std::string::npos)
-		return true;
-
-	return false;
+bool hasDoubleUnderscores(const std::string &name)
+{
+	return (name.find("__") != std::string::npos);
 }
 
 static bool isMacroPredefined(const std::string& name,
                               const pp::MacroSet& macroSet)
 {
 	pp::MacroSet::const_iterator iter = macroSet.find(name);
-	return iter != macroSet.end() ? iter->second.predefined : false;
+	return iter != macroSet.end() ? iter->second->predefined : false;
 }
 
 namespace pp
 {
 
-DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
-                                 MacroSet* macroSet,
-                                 Diagnostics* diagnostics,
-                                 DirectiveHandler* directiveHandler) :
-	mPastFirstStatement(false),
-	mTokenizer(tokenizer),
-	mMacroSet(macroSet),
-	mDiagnostics(diagnostics),
-	mDirectiveHandler(directiveHandler)
+class DefinedParser : public Lexer
+{
+public:
+	DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
+		: mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
+	{
+	}
+
+protected:
+	void lex(Token *token) override
+	{
+		const char 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::PP_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::PP_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,
+                                 DirectiveHandler *directiveHandler,
+                                 int maxMacroExpansionDepth)
+    : mPastFirstStatement(false),
+      mSeenNonPreprocessorToken(false),
+      mTokenizer(tokenizer),
+      mMacroSet(macroSet),
+      mDiagnostics(diagnostics),
+      mDirectiveHandler(directiveHandler),
+      mShaderVersion(100),
+      mMaxMacroExpansionDepth(maxMacroExpansionDepth)
 {
 }
 
-void DirectiveParser::lex(Token* token)
+DirectiveParser::~DirectiveParser()
+{
+}
+
+void DirectiveParser::lex(Token *token)
 {
 	do
 	{
@@ -170,13 +237,17 @@
 			parseDirective(token);
 			mPastFirstStatement = true;
 		}
+		else if (!isEOD(token))
+		{
+			mSeenNonPreprocessorToken = true;
+		}
 
 		if (token->type == Token::LAST)
 		{
 			if (!mConditionalStack.empty())
 			{
-				const ConditionalBlock& block = mConditionalStack.back();
-				mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
+				const ConditionalBlock &block = mConditionalStack.back();
+				mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
 				                     block.location, block.type);
 			}
 			break;
@@ -187,7 +258,7 @@
 	mPastFirstStatement = true;
 }
 
-void DirectiveParser::parseDirective(Token* token)
+void DirectiveParser::parseDirective(Token *token)
 {
 	assert(token->type == Token::PP_HASH);
 
@@ -211,7 +282,7 @@
 	switch(directive)
 	{
 	case DIRECTIVE_NONE:
-		mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
+		mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		break;
@@ -262,64 +333,74 @@
 	skipUntilEOD(mTokenizer, token);
 	if (token->type == Token::LAST)
 	{
-		mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
+		mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
 		                     token->location, token->text);
 	}
 }
 
-void DirectiveParser::parseDefine(Token* token)
+void DirectiveParser::parseDefine(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_DEFINE);
 
 	mTokenizer->lex(token);
 	if (token->type != Token::IDENTIFIER)
 	{
-		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		return;
 	}
 	if (isMacroPredefined(token->text, *mMacroSet))
 	{
-		mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
+		mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
 		                     token->location, token->text);
 		return;
 	}
 	if (isMacroNameReserved(token->text))
 	{
-		mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
+		mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
 		                     token->location, token->text);
 		return;
 	}
+	// Using double underscores is allowed, but may result in unintended
+	// behavior, so a warning is issued. At the time of writing this was
+	// specified in ESSL 3.10, but the intent judging from Khronos
+	// discussions and dEQP tests was that double underscores should be
+	// allowed in earlier ESSL versions too.
+	if (hasDoubleUnderscores(token->text))
+	{
+		mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
+		                     token->text);
+	}
 
-	Macro macro;
-	macro.type = Macro::kTypeObj;
-	macro.name = token->text;
+	std::shared_ptr<Macro> macro = std::make_shared<Macro>();
+	macro->type = Macro::kTypeObj;
+	macro->name = token->text;
 
 	mTokenizer->lex(token);
 	if (token->type == '(' && !token->hasLeadingSpace())
 	{
 		// Function-like macro. Collect arguments.
-		macro.type = Macro::kTypeFunc;
+		macro->type = Macro::kTypeFunc;
 		do {
 			mTokenizer->lex(token);
 			if (token->type != Token::IDENTIFIER)
 				break;
 
-			if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
+			if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) != macro->parameters.end())
 			{
-				mDiagnostics->report(Diagnostics::MACRO_DUPLICATE_PARAMETER_NAMES,
+				mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
 				                     token->location, token->text);
 				return;
 			}
 
-			macro.parameters.push_back(token->text);
+			macro->parameters.push_back(token->text);
 
 			mTokenizer->lex(token);  // Get ','.
 		} while (token->type == ',');
 
 		if (token->type != ')')
 		{
-			mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+			mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 			                     token->location,
 			                     token->text);
 			return;
@@ -333,36 +414,34 @@
 		// list. Resetting it also allows us to reuse Token::equals() to
 		// compare macros.
 		token->location = SourceLocation();
-		macro.replacements.push_back(*token);
+		macro->replacements.push_back(*token);
 		mTokenizer->lex(token);
 	}
-	if (!macro.replacements.empty())
+	if (!macro->replacements.empty())
 	{
 		// Whitespace preceding the replacement list is not considered part of
 		// the replacement list for either form of macro.
-		macro.replacements.front().setHasLeadingSpace(false);
+		macro->replacements.front().setHasLeadingSpace(false);
 	}
 
 	// Check for macro redefinition.
-	MacroSet::const_iterator iter = mMacroSet->find(macro.name);
-	if (iter != mMacroSet->end() && !macro.equals(iter->second))
+	MacroSet::const_iterator iter = mMacroSet->find(macro->name);
+	if (iter != mMacroSet->end() && !macro->equals(*iter->second))
 	{
-		mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
-		                     token->location,
-		                     macro.name);
+		mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);
 		return;
 	}
-	mMacroSet->insert(std::make_pair(macro.name, macro));
+	mMacroSet->insert(std::make_pair(macro->name, macro));
 }
 
-void DirectiveParser::parseUndef(Token* token)
+void DirectiveParser::parseUndef(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_UNDEF);
 
 	mTokenizer->lex(token);
 	if (token->type != Token::IDENTIFIER)
 	{
-		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		return;
 	}
@@ -370,10 +449,17 @@
 	MacroSet::iterator iter = mMacroSet->find(token->text);
 	if (iter != mMacroSet->end())
 	{
-		if (iter->second.predefined)
+		if (iter->second->predefined)
 		{
-			mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+			mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
 			                     token->location, token->text);
+			return;
+		}
+		else if (iter->second->expansionCount > 0)
+		{
+			mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED,
+			                     token->location, token->text);
+			return;
 		}
 		else
 		{
@@ -382,39 +468,44 @@
 	}
 
 	mTokenizer->lex(token);
+	if (!isEOD(token))
+	{
+		mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+	}
 }
 
-void DirectiveParser::parseIf(Token* token)
+void DirectiveParser::parseIf(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_IF);
 	parseConditionalIf(token);
 }
 
-void DirectiveParser::parseIfdef(Token* token)
+void DirectiveParser::parseIfdef(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_IFDEF);
 	parseConditionalIf(token);
 }
 
-void DirectiveParser::parseIfndef(Token* token)
+void DirectiveParser::parseIfndef(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_IFNDEF);
 	parseConditionalIf(token);
 }
 
-void DirectiveParser::parseElse(Token* token)
+void DirectiveParser::parseElse(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_ELSE);
 
 	if (mConditionalStack.empty())
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
 	}
 
-	ConditionalBlock& block = mConditionalStack.back();
+	ConditionalBlock &block = mConditionalStack.back();
 	if (block.skipBlock)
 	{
 		// No diagnostics. Just skip the whole line.
@@ -423,7 +514,7 @@
 	}
 	if (block.foundElseGroup)
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
@@ -437,25 +528,25 @@
 	mTokenizer->lex(token);
 	if (!isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 	}
 }
 
-void DirectiveParser::parseElif(Token* token)
+void DirectiveParser::parseElif(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_ELIF);
 
 	if (mConditionalStack.empty())
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
 	}
 
-	ConditionalBlock& block = mConditionalStack.back();
+	ConditionalBlock &block = mConditionalStack.back();
 	if (block.skipBlock)
 	{
 		// No diagnostics. Just skip the whole line.
@@ -464,7 +555,7 @@
 	}
 	if (block.foundElseGroup)
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
@@ -483,13 +574,13 @@
 	block.foundValidGroup = expression != 0;
 }
 
-void DirectiveParser::parseEndif(Token* token)
+void DirectiveParser::parseEndif(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_ENDIF);
 
 	if (mConditionalStack.empty())
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
@@ -501,13 +592,13 @@
 	mTokenizer->lex(token);
 	if (!isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 	}
 }
 
-void DirectiveParser::parseError(Token* token)
+void DirectiveParser::parseError(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_ERROR);
 
@@ -522,7 +613,7 @@
 }
 
 // Parses pragma of form: #pragma name[(value)].
-void DirectiveParser::parsePragma(Token* token)
+void DirectiveParser::parsePragma(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_PRAGMA);
 
@@ -539,6 +630,11 @@
 	int state = PRAGMA_NAME;
 
 	mTokenizer->lex(token);
+	bool stdgl = token->text == "STDGL";
+	if (stdgl)
+	{
+		mTokenizer->lex(token);
+	}
 	while ((token->type != '\n') && (token->type != Token::LAST))
 	{
 		switch(state++)
@@ -569,16 +665,15 @@
 	                  (state == RIGHT_PAREN + 1));  // With value.
 	if (!valid)
 	{
-		mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
-		                     token->location, name);
+		mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);
 	}
 	else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.
 	{
-		mDirectiveHandler->handlePragma(token->location, name, value);
+		mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
 	}
 }
 
-void DirectiveParser::parseExtension(Token* token)
+void DirectiveParser::parseExtension(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_EXTENSION);
 
@@ -598,61 +693,77 @@
 	{
 		switch (state++)
 		{
-		case EXT_NAME:
-			if (valid && (token->type != Token::IDENTIFIER))
-			{
-				mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
-				                     token->location, token->text);
-				valid = false;
-			}
-			if (valid) name = token->text;
-			break;
-		case COLON:
-			if (valid && (token->type != ':'))
-			{
-				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
-		case EXT_BEHAVIOR:
-			if (valid && (token->type != Token::IDENTIFIER))
-			{
-				mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
-				                     token->location, token->text);
-				valid = false;
-			}
-			if (valid) behavior = token->text;
-			break;
-		default:
-			if (valid)
-			{
-				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
+			case EXT_NAME:
+				if (valid && (token->type != Token::IDENTIFIER))
+				{
+					mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,
+					                     token->text);
+					valid = false;
+				}
+				if (valid)
+					name = token->text;
+				break;
+			case COLON:
+				if (valid && (token->type != ':'))
+				{
+					mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+					                     token->text);
+					valid = false;
+				}
+				break;
+			case EXT_BEHAVIOR:
+				if (valid && (token->type != Token::IDENTIFIER))
+				{
+					mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
+					                     token->location, token->text);
+					valid = false;
+				}
+				if (valid)
+					behavior = token->text;
+				break;
+			default:
+				if (valid)
+				{
+					mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+					                     token->text);
+					valid = false;
+				}
+				break;
 		}
 		mTokenizer->lex(token);
 	}
 	if (valid && (state != EXT_BEHAVIOR + 1))
 	{
-		mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
-		                     token->location, token->text);
+		mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,
+		                     token->text);
 		valid = false;
 	}
+	if (valid && mSeenNonPreprocessorToken)
+	{
+		if (mShaderVersion >= 300)
+		{
+			mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
+			                     token->location, token->text);
+			valid = false;
+		}
+		else
+		{
+			mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
+			                     token->location, token->text);
+		}
+	}
 	if (valid)
 		mDirectiveHandler->handleExtension(token->location, name, behavior);
 }
 
-void DirectiveParser::parseVersion(Token* token)
+void DirectiveParser::parseVersion(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_VERSION);
 
 	if (mPastFirstStatement)
 	{
-		mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,
-		                     token->location, token->text);
+		mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,
+		                     token->text);
 		skipUntilEOD(mTokenizer, token);
 		return;
 	}
@@ -676,13 +787,13 @@
 		case VERSION_NUMBER:
 			if (token->type != Token::CONST_INT)
 			{
-				mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
+				mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
 				                     token->location, token->text);
 				valid = false;
 			}
 			if (valid && !token->iValue(&version))
 			{
-				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+				mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
 				                     token->location, token->text);
 				valid = false;
 			}
@@ -694,14 +805,14 @@
 		case VERSION_PROFILE:
 			if (token->type != Token::IDENTIFIER || token->text != "es")
 			{
-				mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+				mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
 				                     token->location, token->text);
 				valid = false;
 			}
 			state = VERSION_ENDLINE;
 			break;
 		default:
-			mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+			mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 			                     token->location, token->text);
 			valid = false;
 			break;
@@ -712,99 +823,98 @@
 
 	if (valid && (state != VERSION_ENDLINE))
 	{
-		mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+		mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
 		                     token->location, token->text);
 		valid = false;
 	}
 
+	if (valid && version >= 300 && token->location.line > 1)
+	{
+		mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,
+		                     token->text);
+		valid = false;
+	}
+
 	if (valid)
 	{
 		mDirectiveHandler->handleVersion(token->location, version);
+		mShaderVersion = version;
+		PredefineMacro(mMacroSet, "__VERSION__", version);
 	}
 }
 
-void DirectiveParser::parseLine(Token* token)
+void DirectiveParser::parseLine(Token *token)
 {
 	assert(getDirective(token) == DIRECTIVE_LINE);
 
-	enum State
-	{
-		LINE_NUMBER,
-		FILE_NUMBER
-	};
-
 	bool valid = true;
+	bool parsedFileNumber = false;
 	int line = 0, file = 0;
-	int state = LINE_NUMBER;
 
-	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);
+	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false, mMaxMacroExpansionDepth);
+
+	// Lex the first token after "#line" so we can check it for EOD.
 	macroExpander.lex(token);
-	while ((token->type != '\n') && (token->type != Token::LAST))
-	{
-		switch (state++)
-		{
-		case LINE_NUMBER:
-			if (valid && (token->type != Token::CONST_INT))
-			{
-				mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
-				                     token->location, token->text);
-				valid = false;
-			}
-			if (valid && !token->iValue(&line))
-			{
-				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
-		case FILE_NUMBER:
-			if (valid && (token->type != Token::CONST_INT))
-			{
-				mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
-				                     token->location, token->text);
-				valid = false;
-			}
-			if (valid && !token->iValue(&file))
-			{
-				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
-		default:
-			if (valid)
-			{
-				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
-				                     token->location, token->text);
-				valid = false;
-			}
-			break;
-		}
-		macroExpander.lex(token);
-	}
 
-	if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
+	if (isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
-		                     token->location, token->text);
+		mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
 		valid = false;
 	}
+	else
+	{
+		ExpressionParser expressionParser(&macroExpander, mDiagnostics);
+		ExpressionParser::ErrorSettings errorSettings;
+
+		// See GLES3 section 12.42
+		errorSettings.integerLiteralsMustFit32BitSignedRange = true;
+
+		errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
+		// The first token was lexed earlier to check if it was EOD. Include
+		// the token in parsing for a second time by setting the
+		// parsePresetToken flag to true.
+		expressionParser.parse(token, &line, true, errorSettings, &valid);
+		if (!isEOD(token) && valid)
+		{
+			errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
+			// After parsing the line expression expressionParser has also
+			// advanced to the first token of the file expression - this is the
+			// token that makes the parser reduce the "input" rule for the line
+			// expression and stop. So we're using parsePresetToken = true here
+			// as well.
+			expressionParser.parse(token, &file, true, errorSettings, &valid);
+			parsedFileNumber = true;
+		}
+		if (!isEOD(token))
+		{
+			if (valid)
+			{
+				mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
+				                     token->location, token->text);
+				valid = false;
+			}
+			skipUntilEOD(mTokenizer, token);
+		}
+	}
+
 	if (valid)
 	{
 		mTokenizer->setLineNumber(line);
-		if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
+		if (parsedFileNumber)
+			mTokenizer->setFileNumber(file);
 	}
 }
 
 bool DirectiveParser::skipping() const
 {
-	if (mConditionalStack.empty()) return false;
+	if (mConditionalStack.empty())
+		return false;
 
-	const ConditionalBlock& block = mConditionalStack.back();
+	const ConditionalBlock &block = mConditionalStack.back();
 	return block.skipBlock || block.skipGroup;
 }
 
-void DirectiveParser::parseConditionalIf(Token* token)
+void DirectiveParser::parseConditionalIf(Token *token)
 {
 	ConditionalBlock block;
 	block.type = token->text;
@@ -845,22 +955,26 @@
 	mConditionalStack.push_back(block);
 }
 
-int DirectiveParser::parseExpressionIf(Token* token)
+int DirectiveParser::parseExpressionIf(Token *token)
 {
-	assert((getDirective(token) == DIRECTIVE_IF) ||
-	       (getDirective(token) == DIRECTIVE_ELIF));
+	assert((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
 
-	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);
+	DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
+	MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, true, mMaxMacroExpansionDepth);
 	ExpressionParser expressionParser(&macroExpander, mDiagnostics);
 
 	int expression = 0;
-	macroExpander.lex(token);
-	expressionParser.parse(token, &expression);
+	ExpressionParser::ErrorSettings errorSettings;
+	errorSettings.integerLiteralsMustFit32BitSignedRange = false;
+	errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
+
+	bool valid = true;
+	expressionParser.parse(token, &expression, false, errorSettings, &valid);
 
 	// Check if there are tokens after #if expression.
 	if (!isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 	}
@@ -876,7 +990,7 @@
 	mTokenizer->lex(token);
 	if (token->type != Token::IDENTIFIER)
 	{
-		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 		return 0;
@@ -889,7 +1003,7 @@
 	mTokenizer->lex(token);
 	if (!isEOD(token))
 	{
-		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
 		                     token->location, token->text);
 		skipUntilEOD(mTokenizer, token);
 	}