diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /gfx/angle/checkout/src/compiler/preprocessor | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/compiler/preprocessor')
24 files changed, 7330 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/preprocessor/DiagnosticsBase.cpp b/gfx/angle/checkout/src/compiler/preprocessor/DiagnosticsBase.cpp new file mode 100644 index 0000000000..1d613ec4f4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/DiagnosticsBase.cpp @@ -0,0 +1,148 @@ +// +// Copyright 2012 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 "compiler/preprocessor/DiagnosticsBase.h" + +#include "common/debug.h" + +namespace angle +{ + +namespace pp +{ + +Diagnostics::~Diagnostics() {} + +void Diagnostics::report(ID id, const SourceLocation &loc, const std::string &text) +{ + print(id, loc, text); +} + +bool Diagnostics::isError(ID id) +{ + if ((id > PP_ERROR_BEGIN) && (id < PP_ERROR_END)) + return true; + + if ((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END)) + return false; + + UNREACHABLE(); + return true; +} + +const char *Diagnostics::message(ID id) +{ + switch (id) + { + // Errors begin. + case PP_INTERNAL_ERROR: + return "internal error"; + case PP_OUT_OF_MEMORY: + return "out of memory"; + case PP_INVALID_CHARACTER: + return "invalid character"; + case PP_INVALID_NUMBER: + return "invalid number"; + case PP_INTEGER_OVERFLOW: + return "integer overflow"; + case PP_FLOAT_OVERFLOW: + return "float overflow"; + case PP_TOKEN_TOO_LONG: + return "token too long"; + case PP_INVALID_EXPRESSION: + return "invalid expression"; + case PP_DIVISION_BY_ZERO: + return "division by zero"; + case PP_EOF_IN_COMMENT: + return "unexpected end of file found in comment"; + case PP_UNEXPECTED_TOKEN: + return "unexpected token"; + case PP_DIRECTIVE_INVALID_NAME: + return "invalid directive name"; + case PP_MACRO_NAME_RESERVED: + return "macro name is reserved"; + case PP_MACRO_REDEFINED: + return "macro redefined"; + case PP_MACRO_PREDEFINED_REDEFINED: + return "predefined macro redefined"; + case PP_MACRO_PREDEFINED_UNDEFINED: + return "predefined macro undefined"; + case PP_MACRO_UNTERMINATED_INVOCATION: + return "unterminated macro invocation"; + case PP_MACRO_UNDEFINED_WHILE_INVOKED: + return "macro undefined while being invoked"; + case PP_MACRO_TOO_FEW_ARGS: + return "Not enough arguments for macro"; + case PP_MACRO_TOO_MANY_ARGS: + return "Too many arguments for macro"; + case PP_MACRO_DUPLICATE_PARAMETER_NAMES: + return "duplicate macro parameter name"; + case PP_MACRO_INVOCATION_CHAIN_TOO_DEEP: + return "macro invocation chain too deep"; + case PP_CONDITIONAL_ENDIF_WITHOUT_IF: + return "unexpected #endif found without a matching #if"; + case PP_CONDITIONAL_ELSE_WITHOUT_IF: + return "unexpected #else found without a matching #if"; + case PP_CONDITIONAL_ELSE_AFTER_ELSE: + return "unexpected #else found after another #else"; + case PP_CONDITIONAL_ELIF_WITHOUT_IF: + return "unexpected #elif found without a matching #if"; + case PP_CONDITIONAL_ELIF_AFTER_ELSE: + return "unexpected #elif found after #else"; + case PP_CONDITIONAL_UNTERMINATED: + return "unexpected end of file found in conditional block"; + case PP_INVALID_EXTENSION_NAME: + return "invalid extension name"; + case PP_INVALID_EXTENSION_BEHAVIOR: + return "invalid extension behavior"; + case PP_INVALID_EXTENSION_DIRECTIVE: + return "invalid extension directive"; + case PP_INVALID_VERSION_NUMBER: + return "invalid version number"; + case PP_INVALID_VERSION_DIRECTIVE: + return "invalid version directive"; + case PP_VERSION_NOT_FIRST_STATEMENT: + return "#version directive must occur before anything else, " + "except for comments and white space"; + case PP_VERSION_NOT_FIRST_LINE_ESSL3: + return "#version directive must occur on the first line of the shader"; + case PP_INVALID_LINE_NUMBER: + return "invalid line number"; + case PP_INVALID_FILE_NUMBER: + return "invalid file number"; + case PP_INVALID_LINE_DIRECTIVE: + return "invalid line directive"; + case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1: + return "extension directive must occur before any non-preprocessor tokens in ESSL1"; + case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3: + return "extension directive must occur before any non-preprocessor tokens in ESSL3"; + case PP_UNDEFINED_SHIFT: + return "shift exponent is negative or undefined"; + case PP_TOKENIZER_ERROR: + return "internal tokenizer error"; + // Errors end. + // Warnings begin. + case PP_EOF_IN_DIRECTIVE: + return "unexpected end of file found in directive"; + case PP_CONDITIONAL_UNEXPECTED_TOKEN: + return "unexpected token after conditional expression"; + case PP_UNRECOGNIZED_PRAGMA: + return "unrecognized pragma"; + case PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL: + return "extension directive should occur before any non-preprocessor tokens"; + case PP_WARNING_MACRO_NAME_RESERVED: + return "macro name with a double underscore is reserved - unintented behavior is " + "possible"; + // Warnings end. + default: + UNREACHABLE(); + return ""; + } +} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/DiagnosticsBase.h b/gfx/angle/checkout/src/compiler/preprocessor/DiagnosticsBase.h new file mode 100644 index 0000000000..36f717c4a2 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/DiagnosticsBase.h @@ -0,0 +1,102 @@ +// +// Copyright 2012 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_PREPROCESSOR_DIAGNOSTICSBASE_H_ +#define COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_ + +#include <string> + +namespace angle +{ + +namespace pp +{ + +struct SourceLocation; + +// Base class for reporting diagnostic messages. +// Derived classes are responsible for formatting and printing the messages. +class Diagnostics +{ + public: + enum ID + { + PP_ERROR_BEGIN, + PP_INTERNAL_ERROR, + PP_OUT_OF_MEMORY, + PP_INVALID_CHARACTER, + PP_INVALID_NUMBER, + PP_INTEGER_OVERFLOW, + PP_FLOAT_OVERFLOW, + PP_TOKEN_TOO_LONG, + PP_INVALID_EXPRESSION, + PP_DIVISION_BY_ZERO, + PP_EOF_IN_COMMENT, + PP_UNEXPECTED_TOKEN, + PP_DIRECTIVE_INVALID_NAME, + PP_MACRO_NAME_RESERVED, + PP_MACRO_REDEFINED, + PP_MACRO_PREDEFINED_REDEFINED, + PP_MACRO_PREDEFINED_UNDEFINED, + PP_MACRO_UNTERMINATED_INVOCATION, + PP_MACRO_UNDEFINED_WHILE_INVOKED, + PP_MACRO_TOO_FEW_ARGS, + PP_MACRO_TOO_MANY_ARGS, + PP_MACRO_DUPLICATE_PARAMETER_NAMES, + PP_MACRO_INVOCATION_CHAIN_TOO_DEEP, + PP_CONDITIONAL_ENDIF_WITHOUT_IF, + PP_CONDITIONAL_ELSE_WITHOUT_IF, + PP_CONDITIONAL_ELSE_AFTER_ELSE, + PP_CONDITIONAL_ELIF_WITHOUT_IF, + PP_CONDITIONAL_ELIF_AFTER_ELSE, + PP_CONDITIONAL_UNTERMINATED, + PP_CONDITIONAL_UNEXPECTED_TOKEN, + PP_INVALID_EXTENSION_NAME, + PP_INVALID_EXTENSION_BEHAVIOR, + PP_INVALID_EXTENSION_DIRECTIVE, + PP_INVALID_VERSION_NUMBER, + PP_INVALID_VERSION_DIRECTIVE, + PP_VERSION_NOT_FIRST_STATEMENT, + PP_VERSION_NOT_FIRST_LINE_ESSL3, + PP_INVALID_LINE_NUMBER, + PP_INVALID_FILE_NUMBER, + PP_INVALID_LINE_DIRECTIVE, + // This is just a warning on CHROME OS http://anglebug.com/4023 +#if !defined(ANGLE_PLATFORM_CHROMEOS) + PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1, +#endif + PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3, + PP_UNDEFINED_SHIFT, + PP_TOKENIZER_ERROR, + PP_ERROR_END, + + PP_WARNING_BEGIN, + PP_EOF_IN_DIRECTIVE, + PP_UNRECOGNIZED_PRAGMA, +#if defined(ANGLE_PLATFORM_CHROMEOS) + PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1, +#endif + PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL, + PP_WARNING_MACRO_NAME_RESERVED, + PP_WARNING_END + }; + + virtual ~Diagnostics(); + + void report(ID id, const SourceLocation &loc, const std::string &text); + + protected: + bool isError(ID id); + const char *message(ID id); + + virtual void print(ID id, const SourceLocation &loc, const std::string &text) = 0; +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/DirectiveHandlerBase.cpp b/gfx/angle/checkout/src/compiler/preprocessor/DirectiveHandlerBase.cpp new file mode 100644 index 0000000000..7612d136e8 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/DirectiveHandlerBase.cpp @@ -0,0 +1,19 @@ +// +// Copyright 2012 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 "compiler/preprocessor/DirectiveHandlerBase.h" + +namespace angle +{ + +namespace pp +{ + +DirectiveHandler::~DirectiveHandler() {} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/DirectiveHandlerBase.h b/gfx/angle/checkout/src/compiler/preprocessor/DirectiveHandlerBase.h new file mode 100644 index 0000000000..c1fd44510d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/DirectiveHandlerBase.h @@ -0,0 +1,49 @@ +// +// Copyright 2012 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_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ + +#include <string> +#include "GLSLANG/ShaderLang.h" + +namespace angle +{ + +namespace pp +{ + +struct SourceLocation; + +// Base class for handling directives. +// Preprocessor uses this class to notify the clients about certain +// preprocessor directives. Derived classes are responsible for +// handling them in an appropriate manner. +class DirectiveHandler +{ + public: + virtual ~DirectiveHandler(); + + virtual void handleError(const SourceLocation &loc, const std::string &msg) = 0; + + // Handle pragma of form: #pragma name[(value)] + virtual void handlePragma(const SourceLocation &loc, + const std::string &name, + const std::string &value, + bool stdgl) = 0; + + virtual void handleExtension(const SourceLocation &loc, + const std::string &name, + const std::string &behavior) = 0; + + virtual void handleVersion(const SourceLocation &loc, int version, ShShaderSpec spec) = 0; +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/DirectiveParser.cpp b/gfx/angle/checkout/src/compiler/preprocessor/DirectiveParser.cpp new file mode 100644 index 0000000000..30167e2a5a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/DirectiveParser.cpp @@ -0,0 +1,981 @@ +// +// Copyright 2011 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 "compiler/preprocessor/DirectiveParser.h" + +#include <algorithm> +#include <cstdlib> +#include <sstream> + +#include "GLSLANG/ShaderLang.h" +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/DirectiveHandlerBase.h" +#include "compiler/preprocessor/ExpressionParser.h" +#include "compiler/preprocessor/MacroExpander.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/preprocessor/Tokenizer.h" + +namespace angle +{ + +namespace +{ +enum DirectiveType +{ + DIRECTIVE_NONE, + DIRECTIVE_DEFINE, + DIRECTIVE_UNDEF, + DIRECTIVE_IF, + DIRECTIVE_IFDEF, + DIRECTIVE_IFNDEF, + DIRECTIVE_ELSE, + DIRECTIVE_ELIF, + DIRECTIVE_ENDIF, + DIRECTIVE_ERROR, + DIRECTIVE_PRAGMA, + DIRECTIVE_EXTENSION, + DIRECTIVE_VERSION, + DIRECTIVE_LINE +}; + +DirectiveType getDirective(const pp::Token *token) +{ + const char kDirectiveDefine[] = "define"; + const char kDirectiveUndef[] = "undef"; + const char kDirectiveIf[] = "if"; + const char kDirectiveIfdef[] = "ifdef"; + const char kDirectiveIfndef[] = "ifndef"; + const char kDirectiveElse[] = "else"; + const char kDirectiveElif[] = "elif"; + const char kDirectiveEndif[] = "endif"; + const char kDirectiveError[] = "error"; + const char kDirectivePragma[] = "pragma"; + const char kDirectiveExtension[] = "extension"; + const char kDirectiveVersion[] = "version"; + const char kDirectiveLine[] = "line"; + + if (token->type != pp::Token::IDENTIFIER) + return DIRECTIVE_NONE; + + if (token->text == kDirectiveDefine) + return DIRECTIVE_DEFINE; + if (token->text == kDirectiveUndef) + return DIRECTIVE_UNDEF; + if (token->text == kDirectiveIf) + return DIRECTIVE_IF; + if (token->text == kDirectiveIfdef) + return DIRECTIVE_IFDEF; + if (token->text == kDirectiveIfndef) + return DIRECTIVE_IFNDEF; + if (token->text == kDirectiveElse) + return DIRECTIVE_ELSE; + if (token->text == kDirectiveElif) + return DIRECTIVE_ELIF; + if (token->text == kDirectiveEndif) + return DIRECTIVE_ENDIF; + if (token->text == kDirectiveError) + return DIRECTIVE_ERROR; + if (token->text == kDirectivePragma) + return DIRECTIVE_PRAGMA; + if (token->text == kDirectiveExtension) + return DIRECTIVE_EXTENSION; + if (token->text == kDirectiveVersion) + return DIRECTIVE_VERSION; + if (token->text == kDirectiveLine) + return DIRECTIVE_LINE; + + return DIRECTIVE_NONE; +} + +bool isConditionalDirective(DirectiveType directive) +{ + switch (directive) + { + case DIRECTIVE_IF: + case DIRECTIVE_IFDEF: + case DIRECTIVE_IFNDEF: + case DIRECTIVE_ELSE: + case DIRECTIVE_ELIF: + case DIRECTIVE_ENDIF: + return true; + default: + return false; + } +} + +// Returns true if the token represents End Of Directive. +bool isEOD(const pp::Token *token) +{ + return (token->type == '\n') || (token->type == pp::Token::LAST); +} + +void skipUntilEOD(pp::Lexer *lexer, pp::Token *token) +{ + while (!isEOD(token)) + { + lexer->lex(token); + } +} + +bool isMacroNameReserved(const std::string &name) +{ + // Names prefixed with "GL_" and the name "defined" are reserved. + return name == "defined" || (name.substr(0, 3) == "GL_"); +} + +bool hasDoubleUnderscores(const std::string &name) +{ + return (name.find("__") != std::string::npos); +} + +bool isMacroPredefined(const std::string &name, const pp::MacroSet ¯oSet) +{ + pp::MacroSet::const_iterator iter = macroSet.find(name); + return iter != macroSet.end() ? iter->second->predefined : false; +} + +} // namespace + +namespace pp +{ +DirectiveParser::DirectiveParser(Tokenizer *tokenizer, + MacroSet *macroSet, + Diagnostics *diagnostics, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings) + : mPastFirstStatement(false), + mSeenNonPreprocessorToken(false), + mTokenizer(tokenizer), + mMacroSet(macroSet), + mDiagnostics(diagnostics), + mDirectiveHandler(directiveHandler), + mShaderVersion(100), + mSettings(settings) +{} + +DirectiveParser::~DirectiveParser() {} + +void DirectiveParser::lex(Token *token) +{ + do + { + mTokenizer->lex(token); + + if (token->type == Token::PP_HASH) + { + parseDirective(token); + mPastFirstStatement = true; + } + else if (!isEOD(token) && !skipping()) + { + mSeenNonPreprocessorToken = true; + } + + if (token->type == Token::LAST) + { + if (!mConditionalStack.empty()) + { + const ConditionalBlock &block = mConditionalStack.back(); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location, + block.type); + } + break; + } + + } while (skipping() || (token->type == '\n')); + + mPastFirstStatement = true; +} + +void DirectiveParser::parseDirective(Token *token) +{ + ASSERT(token->type == Token::PP_HASH); + + mTokenizer->lex(token); + if (isEOD(token)) + { + // Empty Directive. + return; + } + + DirectiveType directive = getDirective(token); + + // While in an excluded conditional block/group, + // we only parse conditional directives. + if (skipping() && !isConditionalDirective(directive)) + { + skipUntilEOD(mTokenizer, token); + return; + } + + switch (directive) + { + case DIRECTIVE_NONE: + mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + break; + case DIRECTIVE_DEFINE: + parseDefine(token); + break; + case DIRECTIVE_UNDEF: + parseUndef(token); + break; + case DIRECTIVE_IF: + parseIf(token); + break; + case DIRECTIVE_IFDEF: + parseIfdef(token); + break; + case DIRECTIVE_IFNDEF: + parseIfndef(token); + break; + case DIRECTIVE_ELSE: + parseElse(token); + break; + case DIRECTIVE_ELIF: + parseElif(token); + break; + case DIRECTIVE_ENDIF: + parseEndif(token); + break; + case DIRECTIVE_ERROR: + parseError(token); + break; + case DIRECTIVE_PRAGMA: + parsePragma(token); + break; + case DIRECTIVE_EXTENSION: + parseExtension(token); + break; + case DIRECTIVE_VERSION: + parseVersion(token); + break; + case DIRECTIVE_LINE: + parseLine(token); + break; + default: + UNREACHABLE(); + break; + } + + skipUntilEOD(mTokenizer, token); + if (token->type == Token::LAST) + { + mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text); + } +} + +void DirectiveParser::parseDefine(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_DEFINE); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); + return; + } + if (isMacroPredefined(token->text, *mMacroSet)) + { + mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location, + token->text); + return; + } + if (isMacroNameReserved(token->text)) + { + 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); + } + + 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; + do + { + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + break; + + if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) != + macro->parameters.end()) + { + mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES, + token->location, token->text); + return; + } + + macro->parameters.push_back(token->text); + + mTokenizer->lex(token); // Get ','. + } while (token->type == ','); + + if (token->type != ')') + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); + return; + } + mTokenizer->lex(token); // Get ')'. + } + + while ((token->type != '\n') && (token->type != Token::LAST)) + { + // Reset the token location because it is unnecessary in replacement + // list. Resetting it also allows us to reuse Token::equals() to + // compare macros. + token->location = SourceLocation(); + macro->replacements.push_back(*token); + mTokenizer->lex(token); + } + 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); + } + + // Check for macro redefinition. + MacroSet::const_iterator iter = mMacroSet->find(macro->name); + if (iter != mMacroSet->end() && !macro->equals(*iter->second)) + { + mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name); + return; + } + mMacroSet->insert(std::make_pair(macro->name, macro)); +} + +void DirectiveParser::parseUndef(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_UNDEF); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); + return; + } + + MacroSet::iterator iter = mMacroSet->find(token->text); + if (iter != mMacroSet->end()) + { + if (iter->second->predefined) + { + 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 + { + mMacroSet->erase(iter); + } + } + + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); + skipUntilEOD(mTokenizer, token); + } +} + +void DirectiveParser::parseIf(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_IF); + parseConditionalIf(token); +} + +void DirectiveParser::parseIfdef(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_IFDEF); + parseConditionalIf(token); +} + +void DirectiveParser::parseIfndef(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_IFNDEF); + parseConditionalIf(token); +} + +void DirectiveParser::parseElse(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_ELSE); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + ConditionalBlock &block = mConditionalStack.back(); + if (block.skipBlock) + { + // No diagnostics. Just skip the whole line. + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundElseGroup) + { + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + block.foundElseGroup = true; + block.skipGroup = block.foundValidGroup; + block.foundValidGroup = true; + + // Check if there are extra tokens after #else. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + } +} + +void DirectiveParser::parseElif(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_ELIF); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + ConditionalBlock &block = mConditionalStack.back(); + if (block.skipBlock) + { + // No diagnostics. Just skip the whole line. + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundElseGroup) + { + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundValidGroup) + { + // Do not parse the expression. + // Also be careful not to emit a diagnostic. + block.skipGroup = true; + skipUntilEOD(mTokenizer, token); + return; + } + + int expression = parseExpressionIf(token); + block.skipGroup = expression == 0; + block.foundValidGroup = expression != 0; +} + +void DirectiveParser::parseEndif(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_ENDIF); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + mConditionalStack.pop_back(); + + // Check if there are tokens after #endif. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + } +} + +void DirectiveParser::parseError(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_ERROR); + + std::ostringstream stream; + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + stream << *token; + mTokenizer->lex(token); + } + mDirectiveHandler->handleError(token->location, stream.str()); +} + +// Parses pragma of form: #pragma name[(value)]. +void DirectiveParser::parsePragma(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_PRAGMA); + + enum State + { + PRAGMA_NAME, + LEFT_PAREN, + PRAGMA_VALUE, + RIGHT_PAREN + }; + + bool valid = true; + std::string name, value; + 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++) + { + case PRAGMA_NAME: + name = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case LEFT_PAREN: + valid = valid && (token->type == '('); + break; + case PRAGMA_VALUE: + value = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case RIGHT_PAREN: + valid = valid && (token->type == ')'); + break; + default: + valid = false; + break; + } + mTokenizer->lex(token); + } + + valid = valid && ((state == PRAGMA_NAME) || // Empty pragma. + (state == LEFT_PAREN) || // Without value. + (state == RIGHT_PAREN + 1)); // With value. + if (!valid) + { + 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, stdgl); + } +} + +void DirectiveParser::parseExtension(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_EXTENSION); + + enum State + { + EXT_NAME, + COLON, + EXT_BEHAVIOR + }; + + bool valid = true; + std::string name, behavior; + int state = EXT_NAME; + + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch (state++) + { + 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::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 + { + if (mSettings.shaderSpec == SH_WEBGL_SPEC) + { + mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL, + token->location, token->text); + } + else + { + mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1, + token->location, token->text); + // This is just a warning on CHROME OS http://anglebug.com/4023 +#if !defined(ANGLE_PLATFORM_CHROMEOS) + valid = false; +#endif + } + } + } + if (valid) + mDirectiveHandler->handleExtension(token->location, name, behavior); +} + +void DirectiveParser::parseVersion(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_VERSION); + + if (mPastFirstStatement) + { + mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + enum State + { + VERSION_NUMBER, + VERSION_PROFILE_ES, + VERSION_PROFILE_GL, + VERSION_ENDLINE + }; + + bool valid = true; + int version = 0; + int state = VERSION_NUMBER; + + mTokenizer->lex(token); + while (valid && (token->type != '\n') && (token->type != Token::LAST)) + { + switch (state) + { + case VERSION_NUMBER: + if (token->type != Token::CONST_INT) + { + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location, + token->text); + valid = false; + } + if (valid && !token->iValue(&version)) + { + mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location, + token->text); + valid = false; + } + if (valid) + { + if (sh::IsDesktopGLSpec(mSettings.shaderSpec)) + { + state = VERSION_PROFILE_GL; + } + else if (version < 300) + { + state = VERSION_ENDLINE; + } + else + { + state = VERSION_PROFILE_ES; + } + } + break; + case VERSION_PROFILE_ES: + ASSERT(!sh::IsDesktopGLSpec(mSettings.shaderSpec)); + if (token->type != Token::IDENTIFIER || token->text != "es") + { + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location, + token->text); + valid = false; + } + state = VERSION_ENDLINE; + break; + case VERSION_PROFILE_GL: + ASSERT(sh::IsDesktopGLSpec(mSettings.shaderSpec)); + if (token->type != Token::IDENTIFIER || token->text != "core") + { + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location, + token->text); + valid = false; + } + state = VERSION_ENDLINE; + break; + default: + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); + valid = false; + break; + } + + mTokenizer->lex(token); + + if (token->type == '\n' && state == VERSION_PROFILE_GL) + { + state = VERSION_ENDLINE; + } + } + + if (valid && (state != VERSION_ENDLINE)) + { + 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, mSettings.shaderSpec); + mShaderVersion = version; + PredefineMacro(mMacroSet, "__VERSION__", version); + } +} + +void DirectiveParser::parseLine(Token *token) +{ + ASSERT(getDirective(token) == DIRECTIVE_LINE); + + bool valid = true; + bool parsedFileNumber = false; + int line = 0, file = 0; + + MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, false); + + // Lex the first token after "#line" so we can check it for EOD. + macroExpander.lex(token); + + if (isEOD(token)) + { + mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text); + valid = false; + } + else + { + ExpressionParser expressionParser(¯oExpander, 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 (parsedFileNumber) + mTokenizer->setFileNumber(file); + } +} + +bool DirectiveParser::skipping() const +{ + if (mConditionalStack.empty()) + return false; + + const ConditionalBlock &block = mConditionalStack.back(); + return block.skipBlock || block.skipGroup; +} + +void DirectiveParser::parseConditionalIf(Token *token) +{ + ConditionalBlock block; + block.type = token->text; + block.location = token->location; + + if (skipping()) + { + // This conditional block is inside another conditional group + // which is skipped. As a consequence this whole block is skipped. + // Be careful not to parse the conditional expression that might + // emit a diagnostic. + skipUntilEOD(mTokenizer, token); + block.skipBlock = true; + } + else + { + DirectiveType directive = getDirective(token); + + int expression = 0; + switch (directive) + { + case DIRECTIVE_IF: + expression = parseExpressionIf(token); + break; + case DIRECTIVE_IFDEF: + expression = parseExpressionIfdef(token); + break; + case DIRECTIVE_IFNDEF: + expression = parseExpressionIfdef(token) == 0 ? 1 : 0; + break; + default: + UNREACHABLE(); + break; + } + block.skipGroup = expression == 0; + block.foundValidGroup = expression != 0; + } + mConditionalStack.push_back(block); +} + +int DirectiveParser::parseExpressionIf(Token *token) +{ + ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF)); + + MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, true); + ExpressionParser expressionParser(¯oExpander, mDiagnostics); + + int expression = 0; + 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::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + } + + return expression; +} + +int DirectiveParser::parseExpressionIfdef(Token *token) +{ + ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF)); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); + skipUntilEOD(mTokenizer, token); + return 0; + } + + MacroSet::const_iterator iter = mMacroSet->find(token->text); + int expression = iter != mMacroSet->end() ? 1 : 0; + + // Check if there are tokens after #ifdef expression. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + } + return expression; +} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/DirectiveParser.h b/gfx/angle/checkout/src/compiler/preprocessor/DirectiveParser.h new file mode 100644 index 0000000000..16be79d9a1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/DirectiveParser.h @@ -0,0 +1,88 @@ +// +// Copyright 2012 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_PREPROCESSOR_DIRECTIVEPARSER_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ + +#include "compiler/preprocessor/Lexer.h" +#include "compiler/preprocessor/Macro.h" +#include "compiler/preprocessor/Preprocessor.h" +#include "compiler/preprocessor/SourceLocation.h" + +namespace angle +{ + +namespace pp +{ + +class Diagnostics; +class DirectiveHandler; +class Tokenizer; + +class DirectiveParser : public Lexer +{ + public: + DirectiveParser(Tokenizer *tokenizer, + MacroSet *macroSet, + Diagnostics *diagnostics, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings); + ~DirectiveParser() override; + + void lex(Token *token) override; + + private: + void parseDirective(Token *token); + void parseDefine(Token *token); + void parseUndef(Token *token); + void parseIf(Token *token); + void parseIfdef(Token *token); + void parseIfndef(Token *token); + void parseElse(Token *token); + void parseElif(Token *token); + void parseEndif(Token *token); + void parseError(Token *token); + void parsePragma(Token *token); + void parseExtension(Token *token); + void parseVersion(Token *token); + void parseLine(Token *token); + + bool skipping() const; + void parseConditionalIf(Token *token); + int parseExpressionIf(Token *token); + int parseExpressionIfdef(Token *token); + + struct ConditionalBlock + { + std::string type; + SourceLocation location; + bool skipBlock; + bool skipGroup; + bool foundValidGroup; + bool foundElseGroup; + + ConditionalBlock() + : skipBlock(false), skipGroup(false), foundValidGroup(false), foundElseGroup(false) + {} + }; + bool mPastFirstStatement; + bool mSeenNonPreprocessorToken; // Tracks if a non-preprocessor token has been seen yet. Some + // macros, such as + // #extension must be declared before all shader code. + std::vector<ConditionalBlock> mConditionalStack; + Tokenizer *mTokenizer; + MacroSet *mMacroSet; + Diagnostics *mDiagnostics; + DirectiveHandler *mDirectiveHandler; + int mShaderVersion; + const PreprocessorSettings mSettings; +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/ExpressionParser.h b/gfx/angle/checkout/src/compiler/preprocessor/ExpressionParser.h new file mode 100644 index 0000000000..3bb9d13c20 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/ExpressionParser.h @@ -0,0 +1,48 @@ +// +// Copyright 2012 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_PREPROCESSOR_EXPRESSIONPARSER_H_ +#define COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ + +#include "common/angleutils.h" +#include "compiler/preprocessor/DiagnosticsBase.h" + +namespace angle +{ + +namespace pp +{ + +class Lexer; +struct Token; + +class ExpressionParser : angle::NonCopyable +{ + public: + struct ErrorSettings + { + Diagnostics::ID unexpectedIdentifier; + bool integerLiteralsMustFit32BitSignedRange; + }; + + ExpressionParser(Lexer *lexer, Diagnostics *diagnostics); + + bool parse(Token *token, + int *result, + bool parsePresetToken, + const ErrorSettings &errorSettings, + bool *valid); + + private: + Lexer *mLexer; + Diagnostics *mDiagnostics; +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Input.cpp b/gfx/angle/checkout/src/compiler/preprocessor/Input.cpp new file mode 100644 index 0000000000..2ddb9467d2 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Input.cpp @@ -0,0 +1,130 @@ +// +// Copyright 2011 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 "compiler/preprocessor/Input.h" + +#include <algorithm> +#include <cstring> + +#include "common/debug.h" + +namespace angle +{ + +namespace pp +{ + +Input::Input() : mCount(0), mString(0) {} + +Input::~Input() {} + +Input::Input(size_t count, const char *const string[], const int length[]) + : mCount(count), mString(string) +{ + mLength.reserve(mCount); + for (size_t i = 0; i < mCount; ++i) + { + int len = length ? length[i] : -1; + mLength.push_back(len < 0 ? std::strlen(mString[i]) : len); + } +} + +const char *Input::skipChar() +{ + // This function should only be called when there is a character to skip. + ASSERT(mReadLoc.cIndex < mLength[mReadLoc.sIndex]); + ++mReadLoc.cIndex; + if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) + { + ++mReadLoc.sIndex; + mReadLoc.cIndex = 0; + } + if (mReadLoc.sIndex >= mCount) + { + return nullptr; + } + return mString[mReadLoc.sIndex] + mReadLoc.cIndex; +} + +size_t Input::read(char *buf, size_t maxSize, int *lineNo) +{ + size_t nRead = 0; + // The previous call to read might have stopped copying the string when encountering a line + // continuation. Check for this possibility first. + if (mReadLoc.sIndex < mCount && maxSize > 0) + { + const char *c = mString[mReadLoc.sIndex] + mReadLoc.cIndex; + if ((*c) == '\\') + { + c = skipChar(); + if (c != nullptr && (*c) == '\n') + { + // Line continuation of backslash + newline. + skipChar(); + // Fake an EOF if the line number would overflow. + if (*lineNo == INT_MAX) + { + return 0; + } + ++(*lineNo); + } + else if (c != nullptr && (*c) == '\r') + { + // Line continuation. Could be backslash + '\r\n' or just backslash + '\r'. + c = skipChar(); + if (c != nullptr && (*c) == '\n') + { + skipChar(); + } + // Fake an EOF if the line number would overflow. + if (*lineNo == INT_MAX) + { + return 0; + } + ++(*lineNo); + } + else + { + // Not line continuation, so write the skipped backslash to buf. + *buf = '\\'; + ++nRead; + } + } + } + + size_t maxRead = maxSize; + while ((nRead < maxRead) && (mReadLoc.sIndex < mCount)) + { + size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex; + size = std::min(size, maxSize); + for (size_t i = 0; i < size; ++i) + { + // Stop if a possible line continuation is encountered. + // It will be processed on the next call on input, which skips it + // and increments line number if necessary. + if (*(mString[mReadLoc.sIndex] + mReadLoc.cIndex + i) == '\\') + { + size = i; + maxRead = nRead + size; // Stop reading right before the backslash. + } + } + std::memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size); + nRead += size; + mReadLoc.cIndex += size; + + // Advance string if we reached the end of current string. + if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) + { + ++mReadLoc.sIndex; + mReadLoc.cIndex = 0; + } + } + return nRead; +} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Input.h b/gfx/angle/checkout/src/compiler/preprocessor/Input.h new file mode 100644 index 0000000000..6f42a112d4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Input.h @@ -0,0 +1,59 @@ +// +// Copyright 2011 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_PREPROCESSOR_INPUT_H_ +#define COMPILER_PREPROCESSOR_INPUT_H_ + +#include <cstddef> +#include <vector> + +namespace angle +{ + +namespace pp +{ + +// Holds and reads input for Lexer. +class Input +{ + public: + Input(); + ~Input(); + Input(size_t count, const char *const string[], const int length[]); + + size_t count() const { return mCount; } + const char *string(size_t index) const { return mString[index]; } + size_t length(size_t index) const { return mLength[index]; } + + size_t read(char *buf, size_t maxSize, int *lineNo); + + struct Location + { + size_t sIndex; // String index; + size_t cIndex; // Char index. + + Location() : sIndex(0), cIndex(0) {} + }; + const Location &readLoc() const { return mReadLoc; } + + private: + // Skip a character and return the next character after the one that was skipped. + // Return nullptr if data runs out. + const char *skipChar(); + + // Input. + size_t mCount; + const char *const *mString; + std::vector<size_t> mLength; + + Location mReadLoc; +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_INPUT_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Lexer.cpp b/gfx/angle/checkout/src/compiler/preprocessor/Lexer.cpp new file mode 100644 index 0000000000..49bd15fe90 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Lexer.cpp @@ -0,0 +1,19 @@ +// +// Copyright 2012 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 "compiler/preprocessor/Lexer.h" + +namespace angle +{ + +namespace pp +{ + +Lexer::~Lexer() {} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Lexer.h b/gfx/angle/checkout/src/compiler/preprocessor/Lexer.h new file mode 100644 index 0000000000..42fd5b0d8f --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Lexer.h @@ -0,0 +1,32 @@ +// +// Copyright 2012 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_PREPROCESSOR_LEXER_H_ +#define COMPILER_PREPROCESSOR_LEXER_H_ + +#include "common/angleutils.h" + +namespace angle +{ + +namespace pp +{ + +struct Token; + +class Lexer : angle::NonCopyable +{ + public: + virtual ~Lexer(); + + virtual void lex(Token *token) = 0; +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_LEXER_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Macro.cpp b/gfx/angle/checkout/src/compiler/preprocessor/Macro.cpp new file mode 100644 index 0000000000..132145bd23 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Macro.cpp @@ -0,0 +1,45 @@ +// +// Copyright 2011 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 "compiler/preprocessor/Macro.h" + +#include "common/angleutils.h" +#include "compiler/preprocessor/Token.h" + +namespace angle +{ + +namespace pp +{ + +Macro::Macro() : predefined(false), disabled(false), expansionCount(0), type(kTypeObj) {} + +Macro::~Macro() {} + +bool Macro::equals(const Macro &other) const +{ + return (type == other.type) && (name == other.name) && (parameters == other.parameters) && + (replacements == other.replacements); +} + +void PredefineMacro(MacroSet *macroSet, const char *name, int value) +{ + Token token; + token.type = Token::CONST_INT; + token.text = ToString(value); + + std::shared_ptr<Macro> macro = std::make_shared<Macro>(); + macro->predefined = true; + macro->type = Macro::kTypeObj; + macro->name = name; + macro->replacements.push_back(token); + + (*macroSet)[name] = macro; +} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Macro.h b/gfx/angle/checkout/src/compiler/preprocessor/Macro.h new file mode 100644 index 0000000000..bd6312c047 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Macro.h @@ -0,0 +1,55 @@ +// +// Copyright 2012 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_PREPROCESSOR_MACRO_H_ +#define COMPILER_PREPROCESSOR_MACRO_H_ + +#include <map> +#include <memory> +#include <string> +#include <vector> + +namespace angle +{ + +namespace pp +{ + +struct Token; + +struct Macro +{ + enum Type + { + kTypeObj, + kTypeFunc + }; + typedef std::vector<std::string> Parameters; + typedef std::vector<Token> Replacements; + + Macro(); + ~Macro(); + bool equals(const Macro &other) const; + + bool predefined; + mutable bool disabled; + mutable int expansionCount; + + Type type; + std::string name; + Parameters parameters; + Replacements replacements; +}; + +typedef std::map<std::string, std::shared_ptr<Macro>> MacroSet; + +void PredefineMacro(MacroSet *macroSet, const char *name, int value); + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_MACRO_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/MacroExpander.cpp b/gfx/angle/checkout/src/compiler/preprocessor/MacroExpander.cpp new file mode 100644 index 0000000000..759617b5a1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/MacroExpander.cpp @@ -0,0 +1,531 @@ +// +// Copyright 2011 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 "compiler/preprocessor/MacroExpander.h" + +#include <GLSLANG/ShaderLang.h> +#include <algorithm> + +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/Token.h" + +namespace angle +{ + +namespace pp +{ + +namespace +{ + +const size_t kMaxContextTokens = 10000; + +class TokenLexer : public Lexer +{ + public: + typedef std::vector<Token> TokenVector; + + TokenLexer(TokenVector *tokens) + { + tokens->swap(mTokens); + mIter = mTokens.begin(); + } + + void lex(Token *token) override + { + if (mIter == mTokens.end()) + { + token->reset(); + token->type = Token::LAST; + } + else + { + *token = *mIter++; + } + } + + private: + TokenVector mTokens; + TokenVector::const_iterator mIter; +}; + +} // anonymous namespace + +class [[nodiscard]] MacroExpander::ScopedMacroReenabler final : angle::NonCopyable +{ + public: + ScopedMacroReenabler(MacroExpander *expander); + ~ScopedMacroReenabler(); + + private: + MacroExpander *mExpander; +}; + +MacroExpander::ScopedMacroReenabler::ScopedMacroReenabler(MacroExpander *expander) + : mExpander(expander) +{ + mExpander->mDeferReenablingMacros = true; +} + +MacroExpander::ScopedMacroReenabler::~ScopedMacroReenabler() +{ + mExpander->mDeferReenablingMacros = false; + for (const std::shared_ptr<Macro> ¯o : mExpander->mMacrosToReenable) + { + // Copying the string here by using substr is a check for use-after-free. It detects + // use-after-free more reliably than just toggling the disabled flag. + ASSERT(macro->name.substr() != ""); + macro->disabled = false; + } + mExpander->mMacrosToReenable.clear(); +} + +MacroExpander::MacroExpander(Lexer *lexer, + MacroSet *macroSet, + Diagnostics *diagnostics, + const PreprocessorSettings &settings, + bool parseDefined) + : mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics), + mParseDefined(parseDefined), + mTotalTokensInContexts(0), + mSettings(settings), + mDeferReenablingMacros(false) +{} + +MacroExpander::~MacroExpander() +{ + ASSERT(mMacrosToReenable.empty()); + for (MacroContext *context : mContextStack) + { + delete context; + } +} + +void MacroExpander::lex(Token *token) +{ + while (true) + { + getToken(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 == kDefined) + { + // Defined inside a macro is forbidden in WebGL. + if (!mContextStack.empty() && sh::IsWebGLBasedSpec(mSettings.shaderSpec)) + break; + + bool paren = false; + getToken(token); + if (token->type == '(') + { + paren = true; + getToken(token); + } + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::PP_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::PP_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; + + MacroSet::const_iterator iter = mMacroSet->find(token->text); + if (iter == mMacroSet->end()) + break; + + std::shared_ptr<Macro> macro = iter->second; + if (macro->disabled) + { + // If a particular token is not expanded, it is never expanded. + token->setExpansionDisabled(true); + break; + } + + // Bump the expansion count before peeking if the next token is a '(' + // otherwise there could be a #undef of the macro before the next token. + macro->expansionCount++; + if ((macro->type == Macro::kTypeFunc) && !isNextTokenLeftParen()) + { + // If the token immediately after the macro name is not a '(', + // this macro should not be expanded. + macro->expansionCount--; + break; + } + + pushMacro(macro, *token); + } +} + +void MacroExpander::getToken(Token *token) +{ + if (mReserveToken.get()) + { + *token = *mReserveToken; + mReserveToken.reset(); + return; + } + + // First pop all empty macro contexts. + while (!mContextStack.empty() && mContextStack.back()->empty()) + { + popMacro(); + } + + if (!mContextStack.empty()) + { + *token = mContextStack.back()->get(); + } + else + { + ASSERT(mTotalTokensInContexts == 0); + mLexer->lex(token); + } +} + +void MacroExpander::ungetToken(const Token &token) +{ + if (!mContextStack.empty()) + { + MacroContext *context = mContextStack.back(); + context->unget(); + ASSERT(context->replacements[context->index] == token); + } + else + { + ASSERT(!mReserveToken.get()); + mReserveToken.reset(new Token(token)); + } +} + +bool MacroExpander::isNextTokenLeftParen() +{ + Token token; + getToken(&token); + + bool lparen = token.type == '('; + ungetToken(token); + + return lparen; +} + +bool MacroExpander::pushMacro(std::shared_ptr<Macro> macro, const Token &identifier) +{ + ASSERT(!macro->disabled); + ASSERT(!identifier.expansionDisabled()); + ASSERT(identifier.type == Token::IDENTIFIER); + ASSERT(identifier.text == macro->name); + + std::vector<Token> replacements; + if (!expandMacro(*macro, identifier, &replacements)) + return false; + + // Macro is disabled for expansion until it is popped off the stack. + macro->disabled = true; + + MacroContext *context = new MacroContext; + context->macro = macro; + context->replacements.swap(replacements); + mContextStack.push_back(context); + mTotalTokensInContexts += context->replacements.size(); + return true; +} + +void MacroExpander::popMacro() +{ + ASSERT(!mContextStack.empty()); + + MacroContext *context = mContextStack.back(); + mContextStack.pop_back(); + + ASSERT(context->empty()); + ASSERT(context->macro->disabled); + ASSERT(context->macro->expansionCount > 0); + if (mDeferReenablingMacros) + { + mMacrosToReenable.push_back(context->macro); + } + else + { + context->macro->disabled = false; + } + context->macro->expansionCount--; + mTotalTokensInContexts -= context->replacements.size(); + delete context; +} + +bool MacroExpander::expandMacro(const Macro ¯o, + const Token &identifier, + std::vector<Token> *replacements) +{ + replacements->clear(); + + // In the case of an object-like macro, the replacement list gets its location + // from the identifier, but in the case of a function-like macro, the replacement + // list gets its location from the closing parenthesis of the macro invocation. + // This is tested by dEQP-GLES3.functional.shaders.preprocessor.predefined_macros.* + SourceLocation replacementLocation = identifier.location; + if (macro.type == Macro::kTypeObj) + { + replacements->assign(macro.replacements.begin(), macro.replacements.end()); + + if (macro.predefined) + { + const char kLine[] = "__LINE__"; + const char kFile[] = "__FILE__"; + + ASSERT(replacements->size() == 1); + Token &repl = replacements->front(); + if (macro.name == kLine) + { + repl.text = ToString(identifier.location.line); + } + else if (macro.name == kFile) + { + repl.text = ToString(identifier.location.file); + } + } + } + else + { + ASSERT(macro.type == Macro::kTypeFunc); + std::vector<MacroArg> args; + args.reserve(macro.parameters.size()); + if (!collectMacroArgs(macro, identifier, &args, &replacementLocation)) + return false; + + replaceMacroParams(macro, args, replacements); + } + + for (std::size_t i = 0; i < replacements->size(); ++i) + { + Token &repl = replacements->at(i); + if (i == 0) + { + // The first token in the replacement list inherits the padding + // properties of the identifier token. + repl.setAtStartOfLine(identifier.atStartOfLine()); + repl.setHasLeadingSpace(identifier.hasLeadingSpace()); + } + repl.location = replacementLocation; + } + return true; +} + +bool MacroExpander::collectMacroArgs(const Macro ¯o, + const Token &identifier, + std::vector<MacroArg> *args, + SourceLocation *closingParenthesisLocation) +{ + Token token; + getToken(&token); + ASSERT(token.type == '('); + + args->push_back(MacroArg()); + + // Defer reenabling macros until args collection is finished to avoid the possibility of + // infinite recursion. Otherwise infinite recursion might happen when expanding the args after + // macros have been popped from the context stack when parsing the args. + ScopedMacroReenabler deferReenablingMacros(this); + + int openParens = 1; + while (openParens != 0) + { + getToken(&token); + + if (token.type == Token::LAST) + { + mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION, identifier.location, + identifier.text); + // Do not lose EOF token. + ungetToken(token); + return false; + } + + bool isArg = false; // True if token is part of the current argument. + switch (token.type) + { + case '(': + ++openParens; + isArg = true; + break; + case ')': + --openParens; + isArg = openParens != 0; + *closingParenthesisLocation = token.location; + break; + case ',': + // The individual arguments are separated by comma tokens, but + // the comma tokens between matching inner parentheses do not + // seperate arguments. + if (openParens == 1) + args->push_back(MacroArg()); + isArg = openParens != 1; + break; + default: + isArg = true; + break; + } + if (isArg) + { + MacroArg &arg = args->back(); + // Initial whitespace is not part of the argument. + if (arg.empty()) + token.setHasLeadingSpace(false); + arg.push_back(token); + } + } + + const Macro::Parameters ¶ms = macro.parameters; + // If there is only one empty argument, it is equivalent to no argument. + if (params.empty() && (args->size() == 1) && args->front().empty()) + { + args->clear(); + } + // Validate the number of arguments. + if (args->size() != params.size()) + { + Diagnostics::ID id = args->size() < macro.parameters.size() + ? Diagnostics::PP_MACRO_TOO_FEW_ARGS + : Diagnostics::PP_MACRO_TOO_MANY_ARGS; + mDiagnostics->report(id, identifier.location, identifier.text); + return false; + } + + // Pre-expand each argument before substitution. + // This step expands each argument individually before they are + // inserted into the macro body. + size_t numTokens = 0; + for (auto &arg : *args) + { + TokenLexer lexer(&arg); + if (mSettings.maxMacroExpansionDepth < 1) + { + mDiagnostics->report(Diagnostics::PP_MACRO_INVOCATION_CHAIN_TOO_DEEP, token.location, + token.text); + return false; + } + PreprocessorSettings nestedSettings(mSettings.shaderSpec); + nestedSettings.maxMacroExpansionDepth = mSettings.maxMacroExpansionDepth - 1; + MacroExpander expander(&lexer, mMacroSet, mDiagnostics, nestedSettings, mParseDefined); + + arg.clear(); + expander.lex(&token); + while (token.type != Token::LAST) + { + arg.push_back(token); + expander.lex(&token); + numTokens++; + if (numTokens + mTotalTokensInContexts > kMaxContextTokens) + { + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text); + return false; + } + } + } + return true; +} + +void MacroExpander::replaceMacroParams(const Macro ¯o, + const std::vector<MacroArg> &args, + std::vector<Token> *replacements) +{ + for (std::size_t i = 0; i < macro.replacements.size(); ++i) + { + if (!replacements->empty() && + replacements->size() + mTotalTokensInContexts > kMaxContextTokens) + { + const Token &token = replacements->back(); + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text); + return; + } + + const Token &repl = macro.replacements[i]; + if (repl.type != Token::IDENTIFIER) + { + replacements->push_back(repl); + continue; + } + + // TODO(alokp): Optimize this. + // There is no need to search for macro params every time. + // The param index can be cached with the replacement token. + Macro::Parameters::const_iterator iter = + std::find(macro.parameters.begin(), macro.parameters.end(), repl.text); + if (iter == macro.parameters.end()) + { + replacements->push_back(repl); + continue; + } + + std::size_t iArg = std::distance(macro.parameters.begin(), iter); + const MacroArg &arg = args[iArg]; + if (arg.empty()) + { + continue; + } + std::size_t iRepl = replacements->size(); + replacements->insert(replacements->end(), arg.begin(), arg.end()); + // The replacement token inherits padding properties from + // macro replacement token. + replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace()); + } +} + +MacroExpander::MacroContext::MacroContext() : macro(0), index(0) {} + +MacroExpander::MacroContext::~MacroContext() {} + +bool MacroExpander::MacroContext::empty() const +{ + return index == replacements.size(); +} + +const Token &MacroExpander::MacroContext::get() +{ + return replacements[index++]; +} + +void MacroExpander::MacroContext::unget() +{ + ASSERT(index > 0); + --index; +} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/MacroExpander.h b/gfx/angle/checkout/src/compiler/preprocessor/MacroExpander.h new file mode 100644 index 0000000000..10aee6fc39 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/MacroExpander.h @@ -0,0 +1,91 @@ +// +// Copyright 2012 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_PREPROCESSOR_MACROEXPANDER_H_ +#define COMPILER_PREPROCESSOR_MACROEXPANDER_H_ + +#include <memory> +#include <vector> + +#include "compiler/preprocessor/Lexer.h" +#include "compiler/preprocessor/Macro.h" +#include "compiler/preprocessor/Preprocessor.h" + +namespace angle +{ + +namespace pp +{ + +class Diagnostics; +struct SourceLocation; + +class MacroExpander : public Lexer +{ + public: + MacroExpander(Lexer *lexer, + MacroSet *macroSet, + Diagnostics *diagnostics, + const PreprocessorSettings &settings, + bool parseDefined); + ~MacroExpander() override; + + void lex(Token *token) override; + + private: + void getToken(Token *token); + void ungetToken(const Token &token); + bool isNextTokenLeftParen(); + + bool pushMacro(std::shared_ptr<Macro> macro, const Token &identifier); + void popMacro(); + + bool expandMacro(const Macro ¯o, const Token &identifier, std::vector<Token> *replacements); + + typedef std::vector<Token> MacroArg; + bool collectMacroArgs(const Macro ¯o, + const Token &identifier, + std::vector<MacroArg> *args, + SourceLocation *closingParenthesisLocation); + void replaceMacroParams(const Macro ¯o, + const std::vector<MacroArg> &args, + std::vector<Token> *replacements); + + struct MacroContext + { + MacroContext(); + ~MacroContext(); + bool empty() const; + const Token &get(); + void unget(); + + std::shared_ptr<Macro> macro; + std::size_t index; + std::vector<Token> replacements; + }; + + Lexer *mLexer; + MacroSet *mMacroSet; + Diagnostics *mDiagnostics; + bool mParseDefined; + + std::unique_ptr<Token> mReserveToken; + std::vector<MacroContext *> mContextStack; + size_t mTotalTokensInContexts; + + PreprocessorSettings mSettings; + + bool mDeferReenablingMacros; + std::vector<std::shared_ptr<Macro>> mMacrosToReenable; + + class ScopedMacroReenabler; +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_MACROEXPANDER_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Preprocessor.cpp b/gfx/angle/checkout/src/compiler/preprocessor/Preprocessor.cpp new file mode 100644 index 0000000000..8ff4a76632 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Preprocessor.cpp @@ -0,0 +1,107 @@ +// +// Copyright 2011 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 "compiler/preprocessor/Preprocessor.h" + +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/DirectiveParser.h" +#include "compiler/preprocessor/Macro.h" +#include "compiler/preprocessor/MacroExpander.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/preprocessor/Tokenizer.h" + +namespace angle +{ + +namespace pp +{ + +struct PreprocessorImpl +{ + Diagnostics *diagnostics; + MacroSet macroSet; + Tokenizer tokenizer; + DirectiveParser directiveParser; + MacroExpander macroExpander; + + PreprocessorImpl(Diagnostics *diag, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings) + : diagnostics(diag), + tokenizer(diag), + directiveParser(&tokenizer, ¯oSet, diag, directiveHandler, settings), + macroExpander(&directiveParser, ¯oSet, diag, settings, false) + {} +}; + +Preprocessor::Preprocessor(Diagnostics *diagnostics, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings) +{ + mImpl = new PreprocessorImpl(diagnostics, directiveHandler, settings); +} + +Preprocessor::~Preprocessor() +{ + delete mImpl; +} + +bool Preprocessor::init(size_t count, const char *const string[], const int length[]) +{ + static const int kDefaultGLSLVersion = 100; + + // Add standard pre-defined macros. + predefineMacro("__LINE__", 0); + predefineMacro("__FILE__", 0); + predefineMacro("__VERSION__", kDefaultGLSLVersion); + predefineMacro("GL_ES", 1); + + return mImpl->tokenizer.init(count, string, length); +} + +void Preprocessor::predefineMacro(const char *name, int value) +{ + PredefineMacro(&mImpl->macroSet, name, value); +} + +void Preprocessor::lex(Token *token) +{ + bool validToken = false; + while (!validToken) + { + mImpl->macroExpander.lex(token); + switch (token->type) + { + // We should not be returning internal preprocessing tokens. + // Convert preprocessing tokens to compiler tokens or report + // diagnostics. + case Token::PP_HASH: + UNREACHABLE(); + break; + case Token::PP_NUMBER: + mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER, token->location, + token->text); + break; + case Token::PP_OTHER: + mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER, token->location, + token->text); + break; + default: + validToken = true; + break; + } + } +} + +void Preprocessor::setMaxTokenSize(size_t maxTokenSize) +{ + mImpl->tokenizer.setMaxTokenSize(maxTokenSize); +} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Preprocessor.h b/gfx/angle/checkout/src/compiler/preprocessor/Preprocessor.h new file mode 100644 index 0000000000..566904de14 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Preprocessor.h @@ -0,0 +1,72 @@ +// +// Copyright 2011 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_PREPROCESSOR_PREPROCESSOR_H_ +#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_ + +#include <cstddef> + +#include "GLSLANG/ShaderLang.h" +#include "common/angleutils.h" + +namespace angle +{ + +namespace pp +{ + +class Diagnostics; +class DirectiveHandler; +struct PreprocessorImpl; +struct Token; + +struct PreprocessorSettings final +{ + PreprocessorSettings(ShShaderSpec shaderSpec) + : maxMacroExpansionDepth(1000), shaderSpec(shaderSpec) + {} + + PreprocessorSettings(const PreprocessorSettings &other) = default; + + int maxMacroExpansionDepth; + ShShaderSpec shaderSpec; +}; + +class Preprocessor : angle::NonCopyable +{ + public: + Preprocessor(Diagnostics *diagnostics, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings); + ~Preprocessor(); + + // count: specifies the number of elements in the string and length arrays. + // string: specifies an array of pointers to strings. + // length: specifies an array of string lengths. + // If length is NULL, each string is assumed to be null terminated. + // If length is a value other than NULL, it points to an array containing + // a string length for each of the corresponding elements of string. + // Each element in the length array may contain the length of the + // corresponding string or a value less than 0 to indicate that the string + // is null terminated. + bool init(size_t count, const char *const string[], const int length[]); + // Adds a pre-defined macro. + void predefineMacro(const char *name, int value); + + void lex(Token *token); + + // Set maximum preprocessor token size + void setMaxTokenSize(size_t maxTokenSize); + + private: + PreprocessorImpl *mImpl; +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/SourceLocation.h b/gfx/angle/checkout/src/compiler/preprocessor/SourceLocation.h new file mode 100644 index 0000000000..de48abcdb6 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/SourceLocation.h @@ -0,0 +1,44 @@ +// +// Copyright 2012 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_PREPROCESSOR_SOURCELOCATION_H_ +#define COMPILER_PREPROCESSOR_SOURCELOCATION_H_ + +namespace angle +{ + +namespace pp +{ + +struct SourceLocation +{ + SourceLocation() : file(0), line(0) {} + SourceLocation(int f, int l) : file(f), line(l) {} + + bool equals(const SourceLocation &other) const + { + return (file == other.file) && (line == other.line); + } + + int file; + int line; +}; + +inline bool operator==(const SourceLocation &lhs, const SourceLocation &rhs) +{ + return lhs.equals(rhs); +} + +inline bool operator!=(const SourceLocation &lhs, const SourceLocation &rhs) +{ + return !lhs.equals(rhs); +} + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_SOURCELOCATION_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Token.cpp b/gfx/angle/checkout/src/compiler/preprocessor/Token.cpp new file mode 100644 index 0000000000..72d917a39a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Token.cpp @@ -0,0 +1,79 @@ +// +// Copyright 2011 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 "compiler/preprocessor/Token.h" + +#include "common/debug.h" +#include "compiler/preprocessor/numeric_lex.h" + +namespace angle +{ + +namespace pp +{ + +void Token::reset() +{ + type = 0; + flags = 0; + location = SourceLocation(); + text.clear(); +} + +bool Token::equals(const Token &other) const +{ + return (type == other.type) && (flags == other.flags) && (location == other.location) && + (text == other.text); +} + +void Token::setAtStartOfLine(bool start) +{ + if (start) + flags |= AT_START_OF_LINE; + else + flags &= ~AT_START_OF_LINE; +} + +void Token::setHasLeadingSpace(bool space) +{ + if (space) + flags |= HAS_LEADING_SPACE; + else + flags &= ~HAS_LEADING_SPACE; +} + +void Token::setExpansionDisabled(bool disable) +{ + if (disable) + flags |= EXPANSION_DISABLED; + else + flags &= ~EXPANSION_DISABLED; +} + +bool Token::iValue(int *value) const +{ + ASSERT(type == CONST_INT); + return numeric_lex_int(text, value); +} + +bool Token::uValue(unsigned int *value) const +{ + ASSERT(type == CONST_INT); + return numeric_lex_int(text, value); +} + +std::ostream &operator<<(std::ostream &out, const Token &token) +{ + if (token.hasLeadingSpace()) + out << " "; + + out << token.text; + return out; +} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Token.h b/gfx/angle/checkout/src/compiler/preprocessor/Token.h new file mode 100644 index 0000000000..1c65f2fe41 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Token.h @@ -0,0 +1,115 @@ +// +// Copyright 2011 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_PREPROCESSOR_TOKEN_H_ +#define COMPILER_PREPROCESSOR_TOKEN_H_ + +#include <ostream> +#include <string> + +#include "compiler/preprocessor/SourceLocation.h" + +namespace angle +{ + +namespace pp +{ + +struct Token +{ + enum Type + { + // Calling this ERROR causes a conflict with wingdi.h + GOT_ERROR = -1, + LAST = 0, // EOF. + + IDENTIFIER = 258, + + CONST_INT, + CONST_FLOAT, + + OP_INC, + OP_DEC, + OP_LEFT, + OP_RIGHT, + OP_LE, + OP_GE, + OP_EQ, + OP_NE, + OP_AND, + OP_XOR, + OP_OR, + OP_ADD_ASSIGN, + OP_SUB_ASSIGN, + OP_MUL_ASSIGN, + OP_DIV_ASSIGN, + OP_MOD_ASSIGN, + OP_LEFT_ASSIGN, + OP_RIGHT_ASSIGN, + OP_AND_ASSIGN, + OP_XOR_ASSIGN, + OP_OR_ASSIGN, + + // Preprocessing token types. + // These types are used by the preprocessor internally. + // Preprocessor clients must not depend or check for them. + PP_HASH, + PP_NUMBER, + PP_OTHER + }; + enum Flags + { + AT_START_OF_LINE = 1 << 0, + HAS_LEADING_SPACE = 1 << 1, + EXPANSION_DISABLED = 1 << 2 + }; + + Token() : type(0), flags(0) {} + + void reset(); + bool equals(const Token &other) const; + + // Returns true if this is the first token on line. + // It disregards any leading whitespace. + bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; } + void setAtStartOfLine(bool start); + + bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; } + void setHasLeadingSpace(bool space); + + bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; } + void setExpansionDisabled(bool disable); + + // Converts text into numeric value for CONST_INT and CONST_FLOAT token. + // Returns false if the parsed value cannot fit into an int or float. + bool iValue(int *value) const; + bool uValue(unsigned int *value) const; + + int type; + unsigned int flags; + SourceLocation location; + std::string text; +}; + +inline bool operator==(const Token &lhs, const Token &rhs) +{ + return lhs.equals(rhs); +} + +inline bool operator!=(const Token &lhs, const Token &rhs) +{ + return !lhs.equals(rhs); +} + +std::ostream &operator<<(std::ostream &out, const Token &token); + +constexpr char kDefined[] = "defined"; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_TOKEN_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/Tokenizer.h b/gfx/angle/checkout/src/compiler/preprocessor/Tokenizer.h new file mode 100644 index 0000000000..ec6a8ed83a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/Tokenizer.h @@ -0,0 +1,63 @@ +// +// Copyright 2012 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_PREPROCESSOR_TOKENIZER_H_ +#define COMPILER_PREPROCESSOR_TOKENIZER_H_ + +#include "common/angleutils.h" +#include "compiler/preprocessor/Input.h" +#include "compiler/preprocessor/Lexer.h" + +namespace angle +{ + +namespace pp +{ + +class Diagnostics; + +class Tokenizer : public Lexer +{ + public: + struct Context + { + Diagnostics *diagnostics; + + Input input; + // The location where yytext points to. Token location should track + // scanLoc instead of Input::mReadLoc because they may not be the same + // if text is buffered up in the scanner input buffer. + Input::Location scanLoc; + + bool leadingSpace; + bool lineStart; + }; + + Tokenizer(Diagnostics *diagnostics); + ~Tokenizer() override; + + bool init(size_t count, const char *const string[], const int length[]); + + void setFileNumber(int file); + void setLineNumber(int line); + void setMaxTokenSize(size_t maxTokenSize); + + void lex(Token *token) override; + + private: + bool initScanner(); + void destroyScanner(); + + void *mHandle; // Scanner handle. + Context mContext; // Scanner extra. + size_t mMaxTokenSize; // Maximum token size +}; + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/numeric_lex.h b/gfx/angle/checkout/src/compiler/preprocessor/numeric_lex.h new file mode 100644 index 0000000000..dc505ad8b5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/numeric_lex.h @@ -0,0 +1,54 @@ +// +// Copyright 2012 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. +// + +// numeric_lex.h: Functions to extract numeric values from string. + +#ifndef COMPILER_PREPROCESSOR_NUMERICLEX_H_ +#define COMPILER_PREPROCESSOR_NUMERICLEX_H_ + +#include <sstream> + +namespace angle +{ + +namespace pp +{ + +inline std::ios::fmtflags numeric_base_int(const std::string &str) +{ + if ((str.size() >= 2) && (str[0] == '0') && (str[1] == 'x' || str[1] == 'X')) + { + return std::ios::hex; + } + if ((str.size() >= 1) && (str[0] == '0')) + { + return std::ios::oct; + } + return std::ios::dec; +} + +// The following functions parse the given string to extract a numerical +// value of the given type. These functions assume that the string is +// of the correct form. They can only fail if the parsed value is too big, +// in which case false is returned. + +template <typename IntType> +bool numeric_lex_int(const std::string &str, IntType *value) +{ + std::istringstream stream(str); + // This should not be necessary, but MSVS has a buggy implementation. + // It returns incorrect results if the base is not specified. + stream.setf(numeric_base_int(str), std::ios::basefield); + + stream >> (*value); + return !stream.fail(); +} + +} // namespace pp + +} // namespace angle + +#endif // COMPILER_PREPROCESSOR_NUMERICLEX_H_ diff --git a/gfx/angle/checkout/src/compiler/preprocessor/preprocessor_lex_autogen.cpp b/gfx/angle/checkout/src/compiler/preprocessor/preprocessor_lex_autogen.cpp new file mode 100644 index 0000000000..190d53a47a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/preprocessor_lex_autogen.cpp @@ -0,0 +1,2626 @@ +#line 16 "preprocessor.l" +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_parser.py from preprocessor.l +// +// Copyright 2019 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. +// +// preprocessor.l: +// Lexer for the OpenGL shading language preprocessor. + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +# define FLEX_BETA +#endif + +#ifdef yy_create_buffer +# define pp_create_buffer_ALREADY_DEFINED +#else +# define yy_create_buffer pp_create_buffer +#endif + +#ifdef yy_delete_buffer +# define pp_delete_buffer_ALREADY_DEFINED +#else +# define yy_delete_buffer pp_delete_buffer +#endif + +#ifdef yy_scan_buffer +# define pp_scan_buffer_ALREADY_DEFINED +#else +# define yy_scan_buffer pp_scan_buffer +#endif + +#ifdef yy_scan_string +# define pp_scan_string_ALREADY_DEFINED +#else +# define yy_scan_string pp_scan_string +#endif + +#ifdef yy_scan_bytes +# define pp_scan_bytes_ALREADY_DEFINED +#else +# define yy_scan_bytes pp_scan_bytes +#endif + +#ifdef yy_init_buffer +# define pp_init_buffer_ALREADY_DEFINED +#else +# define yy_init_buffer pp_init_buffer +#endif + +#ifdef yy_flush_buffer +# define pp_flush_buffer_ALREADY_DEFINED +#else +# define yy_flush_buffer pp_flush_buffer +#endif + +#ifdef yy_load_buffer_state +# define pp_load_buffer_state_ALREADY_DEFINED +#else +# define yy_load_buffer_state pp_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +# define pp_switch_to_buffer_ALREADY_DEFINED +#else +# define yy_switch_to_buffer pp_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +# define pppush_buffer_state_ALREADY_DEFINED +#else +# define yypush_buffer_state pppush_buffer_state +#endif + +#ifdef yypop_buffer_state +# define pppop_buffer_state_ALREADY_DEFINED +#else +# define yypop_buffer_state pppop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +# define ppensure_buffer_stack_ALREADY_DEFINED +#else +# define yyensure_buffer_stack ppensure_buffer_stack +#endif + +#ifdef yylex +# define pplex_ALREADY_DEFINED +#else +# define yylex pplex +#endif + +#ifdef yyrestart +# define pprestart_ALREADY_DEFINED +#else +# define yyrestart pprestart +#endif + +#ifdef yylex_init +# define pplex_init_ALREADY_DEFINED +#else +# define yylex_init pplex_init +#endif + +#ifdef yylex_init_extra +# define pplex_init_extra_ALREADY_DEFINED +#else +# define yylex_init_extra pplex_init_extra +#endif + +#ifdef yylex_destroy +# define pplex_destroy_ALREADY_DEFINED +#else +# define yylex_destroy pplex_destroy +#endif + +#ifdef yyget_debug +# define ppget_debug_ALREADY_DEFINED +#else +# define yyget_debug ppget_debug +#endif + +#ifdef yyset_debug +# define ppset_debug_ALREADY_DEFINED +#else +# define yyset_debug ppset_debug +#endif + +#ifdef yyget_extra +# define ppget_extra_ALREADY_DEFINED +#else +# define yyget_extra ppget_extra +#endif + +#ifdef yyset_extra +# define ppset_extra_ALREADY_DEFINED +#else +# define yyset_extra ppset_extra +#endif + +#ifdef yyget_in +# define ppget_in_ALREADY_DEFINED +#else +# define yyget_in ppget_in +#endif + +#ifdef yyset_in +# define ppset_in_ALREADY_DEFINED +#else +# define yyset_in ppset_in +#endif + +#ifdef yyget_out +# define ppget_out_ALREADY_DEFINED +#else +# define yyget_out ppget_out +#endif + +#ifdef yyset_out +# define ppset_out_ALREADY_DEFINED +#else +# define yyset_out ppset_out +#endif + +#ifdef yyget_leng +# define ppget_leng_ALREADY_DEFINED +#else +# define yyget_leng ppget_leng +#endif + +#ifdef yyget_text +# define ppget_text_ALREADY_DEFINED +#else +# define yyget_text ppget_text +#endif + +#ifdef yyget_lineno +# define ppget_lineno_ALREADY_DEFINED +#else +# define yyget_lineno ppget_lineno +#endif + +#ifdef yyset_lineno +# define ppset_lineno_ALREADY_DEFINED +#else +# define yyset_lineno ppset_lineno +#endif + +#ifdef yyget_column +# define ppget_column_ALREADY_DEFINED +#else +# define yyget_column ppget_column +#endif + +#ifdef yyset_column +# define ppset_column_ALREADY_DEFINED +#else +# define yyset_column ppset_column +#endif + +#ifdef yywrap +# define ppwrap_ALREADY_DEFINED +#else +# define yywrap ppwrap +#endif + +#ifdef yyget_lval +# define ppget_lval_ALREADY_DEFINED +#else +# define yyget_lval ppget_lval +#endif + +#ifdef yyset_lval +# define ppset_lval_ALREADY_DEFINED +#else +# define yyset_lval ppset_lval +#endif + +#ifdef yyget_lloc +# define ppget_lloc_ALREADY_DEFINED +#else +# define yyget_lloc ppget_lloc +#endif + +#ifdef yyset_lloc +# define ppset_lloc_ALREADY_DEFINED +#else +# define yyset_lloc ppset_lloc +#endif + +#ifdef yyalloc +# define ppalloc_ALREADY_DEFINED +#else +# define yyalloc ppalloc +#endif + +#ifdef yyrealloc +# define pprealloc_ALREADY_DEFINED +#else +# define yyrealloc pprealloc +#endif + +#ifdef yyfree +# define ppfree_ALREADY_DEFINED +#else +# define yyfree ppfree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +# define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +# endif + +# include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +# else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +# ifndef INT8_MIN +# define INT8_MIN (-128) +# endif +# ifndef INT16_MIN +# define INT16_MIN (-32767 - 1) +# endif +# ifndef INT32_MIN +# define INT32_MIN (-2147483647 - 1) +# endif +# ifndef INT8_MAX +# define INT8_MAX (127) +# endif +# ifndef INT16_MAX +# define INT16_MAX (32767) +# endif +# ifndef INT32_MAX +# define INT32_MAX (2147483647) +# endif +# ifndef UINT8_MAX +# define UINT8_MAX (255U) +# endif +# ifndef UINT16_MAX +# define UINT16_MAX (65535U) +# endif +# ifndef UINT32_MAX +# define UINT32_MAX (4294967295U) +# endif + +# ifndef SIZE_MAX +# define SIZE_MAX (~(size_t)0) +# endif + +# endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +# define yynoreturn __attribute__((__noreturn__)) +#else +# define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR)(c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +# define YY_TYPEDEF_YY_SCANNER_T +typedef void *yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin, yyscanner) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +# ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +# define YY_BUF_SIZE 32768 +# else +# define YY_BUF_SIZE 16384 +# endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +# define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +# define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +#define YY_LESS_LINENO(n) +#define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg); \ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } while (0) +#define unput(c) yyunput(c, yyg->yytext_ptr, yyscanner) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +# define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state +{ + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +# define YY_BUFFER_NEW 0 +# define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +# define YY_BUFFER_EOF_PENDING 2 +}; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER \ + (yyg->yy_buffer_stack ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart(FILE *input_file, yyscan_t yyscanner); +void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner); +YY_BUFFER_STATE yy_create_buffer(FILE *file, int size, yyscan_t yyscanner); +void yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner); +void yy_flush_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner); +void yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner); +void yypop_buffer_state(yyscan_t yyscanner); + +static void yyensure_buffer_stack(yyscan_t yyscanner); +static void yy_load_buffer_state(yyscan_t yyscanner); +static void yy_init_buffer(YY_BUFFER_STATE b, FILE *file, yyscan_t yyscanner); +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER, yyscanner) + +YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner); +YY_BUFFER_STATE yy_scan_string(const char *yy_str, yyscan_t yyscanner); +YY_BUFFER_STATE yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner); + +void *yyalloc(yy_size_t, yyscan_t yyscanner); +void *yyrealloc(void *, yy_size_t, yyscan_t yyscanner); +void yyfree(void *, yyscan_t yyscanner); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if (!YY_CURRENT_BUFFER) \ + { \ + yyensure_buffer_stack(yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if (!YY_CURRENT_BUFFER) \ + { \ + yyensure_buffer_stack(yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define ppwrap(yyscanner) (/*CONSTCOND*/ 1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state(yyscan_t yyscanner); +static yy_state_type yy_try_NUL_trans(yy_state_type current_state, yyscan_t yyscanner); +static int yy_get_next_buffer(yyscan_t yyscanner); +static void yynoreturn yy_fatal_error(const char *msg, yyscan_t yyscanner); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int)(yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 37 +#define YY_END_OF_BUFFER 38 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info +{ + flex_int32_t yy_verify; + flex_int32_t yy_nxt; +}; +static const flex_int16_t yy_accept[95] = { + 0, 0, 0, 0, 0, 38, 36, 34, 35, 35, 33, 7, 33, 33, 33, 33, 33, 33, 33, 33, 9, 9, 33, 33, + 33, 8, 33, 33, 3, 5, 5, 4, 34, 35, 19, 27, 20, 30, 25, 12, 23, 13, 24, 10, 2, 1, 26, 10, + 9, 11, 11, 11, 9, 11, 9, 9, 14, 16, 18, 17, 15, 8, 31, 21, 32, 22, 3, 5, 6, 11, 10, 11, + 10, 1, 10, 11, 10, 0, 10, 9, 9, 9, 28, 29, 0, 10, 10, 10, 10, 9, 10, 10, 9, 10, 0 + +}; + +static const YY_CHAR yy_ec[256] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 1, 6, 1, 7, 8, 1, 9, 9, + 10, 11, 9, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 17, 17, 9, 9, 18, 19, 20, + 9, 1, 21, 21, 21, 21, 22, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 25, 24, 24, 26, 24, 24, 9, 1, 9, 27, 24, 1, 21, 21, 21, 21, + + 22, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 24, 24, 26, 24, + 24, 9, 28, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + +static const YY_CHAR yy_meta[29] = {0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 3, 1, 1, 4, 1, + 5, 5, 5, 1, 1, 1, 5, 5, 5, 5, 5, 5, 1, 1}; + +static const flex_int16_t yy_base[100] = { + 0, 0, 0, 26, 28, 133, 195, 130, 195, 128, 105, 195, 104, 25, 195, 100, 23, + 27, 32, 31, 38, 50, 38, 93, 49, 0, 16, 51, 0, 195, 105, 87, 93, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 67, 195, 0, 195, 81, 55, 84, 98, + 110, 53, 61, 0, 52, 39, 195, 195, 195, 33, 0, 195, 195, 195, 195, 0, 195, + 195, 113, 0, 126, 0, 0, 0, 133, 0, 56, 128, 0, 133, 0, 195, 195, 101, + 141, 143, 145, 0, 15, 154, 195, 0, 195, 195, 177, 32, 182, 187, 189 + +}; + +static const flex_int16_t yy_def[100] = { + 0, 94, 1, 95, 95, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 20, 94, 94, 94, 96, 94, 94, 97, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 98, 94, 94, 20, 20, 49, 50, 50, 99, 21, 50, 94, 94, 94, 94, 94, 96, 94, + 94, 94, 94, 97, 94, 94, 43, 43, 69, 69, 98, 47, 50, 50, 94, 51, 50, 99, 50, 94, 94, + 94, 71, 75, 94, 50, 50, 94, 94, 50, 94, 0, 94, 94, 94, 94, 94 + +}; + +static const flex_int16_t yy_nxt[224] = { + 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 21, 22, 23, 24, 25, 25, + 25, 25, 25, 25, 26, 27, 29, 30, 29, 30, 36, 39, 62, 31, 61, 31, 41, 92, 44, 40, 63, 37, 45, + 42, 43, 43, 43, 46, 47, 83, 48, 48, 49, 56, 57, 82, 50, 51, 50, 50, 52, 53, 54, 54, 54, 59, + 60, 64, 87, 87, 87, 50, 55, 50, 81, 79, 65, 69, 50, 70, 70, 70, 50, 50, 50, 69, 71, 72, 69, + 69, 69, 50, 32, 74, 74, 74, 49, 49, + + 68, 50, 75, 76, 50, 50, 50, 67, 50, 50, 50, 58, 50, 50, 50, 90, 90, 90, 38, 50, 77, 77, 35, + 34, 78, 78, 78, 69, 69, 69, 33, 32, 94, 94, 69, 69, 84, 84, 94, 94, 85, 85, 85, 84, 84, 50, + 94, 86, 86, 86, 88, 94, 94, 94, 94, 94, 50, 89, 50, 87, 87, 87, 94, 72, 94, 76, 94, 91, 90, + 90, 90, 94, 94, 94, 94, 94, 93, 28, 28, 28, 28, 28, 66, 94, 94, 66, 66, 73, 94, 73, 73, 73, + 80, 80, 5, 94, 94, 94, 94, 94, + + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94}; + +static const flex_int16_t yy_chk[224] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 4, 4, 13, 16, 26, 3, 96, 4, 17, 89, 19, 16, 26, 13, 19, + 17, 18, 18, 18, 19, 20, 60, 20, 20, 20, 22, 22, 56, 20, 20, 20, 20, 20, 20, 21, 21, 21, 24, + 24, 27, 77, 77, 77, 53, 21, 21, 55, 52, 27, 43, 48, 43, 43, 43, 53, 53, 53, 43, 43, 43, 43, + 43, 43, 47, 32, 47, 47, 47, 49, 49, + + 31, 47, 47, 47, 47, 47, 47, 30, 49, 49, 50, 23, 50, 50, 50, 84, 84, 84, 15, 50, 51, 51, 12, + 10, 51, 51, 51, 69, 69, 69, 9, 7, 5, 0, 69, 69, 71, 71, 78, 78, 71, 71, 71, 75, 75, 80, + 0, 75, 75, 75, 78, 85, 85, 86, 86, 0, 80, 80, 80, 87, 87, 87, 0, 85, 0, 86, 0, 87, 90, + 90, 90, 0, 0, 0, 0, 0, 90, 95, 95, 95, 95, 95, 97, 0, 0, 97, 97, 98, 0, 98, 98, 98, + 99, 99, 94, 94, 94, 94, 94, 94, + + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94}; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +/* +// +// Copyright 2002 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. +// + +This file contains the Lex specification for GLSL ES preprocessor. +Based on Microsoft Visual Studio 2010 Preprocessor Grammar: +http://msdn.microsoft.com/en-us/library/2scxys89.aspx + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN scripts/run_code_generation.py +*/ + +#if defined(_MSC_VER) +# pragma warning(disable : 4005) +#endif + +#include "compiler/preprocessor/Tokenizer.h" + +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/Token.h" + +#if defined(__GNUC__) +// Triggered by the auto-generated yy_fatal_error function. +# pragma GCC diagnostic ignored "-Wmissing-noreturn" +#elif defined(_MSC_VER) +# pragma warning(disable : 4244) +#endif +#if defined(__clang__) +// Flex uses `/*FALLTHROUGH*/` instead of dedicated statements. +# pragma clang diagnostic ignored "-Wimplicit-fallthrough" +# if defined(__APPLE__) +// Older clang versions don't have -Wextra-semi-stmt, and detecting Apple clang versions is +// difficult because they use different yet overlapping version numbers vs. regular clang. +# pragma clang diagnostic ignored "-Wunknown-warning-option" +# endif +// Flex isn't semi-colon clean. +# pragma clang diagnostic ignored "-Wextra-semi-stmt" +# pragma clang diagnostic ignored "-Wunreachable-code" +#endif + +// Workaround for flex using the register keyword, deprecated in C++11. +#ifdef __cplusplus +# if __cplusplus > 199711L +# define register +# endif +#endif + +typedef std::string YYSTYPE; +typedef angle::pp::SourceLocation YYLTYPE; + +// Use the unused yycolumn variable to track file (string) number. +#define yyfileno yycolumn + +#define YY_USER_INIT \ + do \ + { \ + yyfileno = 0; \ + yylineno = 1; \ + yyextra->leadingSpace = false; \ + yyextra->lineStart = true; \ + } while (0); + +#define YY_NO_INPUT +#define YY_USER_ACTION \ + do \ + { \ + angle::pp::Input *input = &yyextra->input; \ + angle::pp::Input::Location *scanLoc = &yyextra->scanLoc; \ + while ((scanLoc->sIndex < input->count()) && \ + (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \ + { \ + scanLoc->cIndex -= input->length(scanLoc->sIndex++); \ + ++yyfileno; \ + yylineno = 1; \ + } \ + yylloc->file = yyfileno; \ + yylloc->line = yylineno; \ + scanLoc->cIndex += yyleng; \ + } while (0); + +#define YY_INPUT(buf, result, maxSize) result = yyextra->input.read(buf, maxSize, &yylineno); + +#define INITIAL 0 +#define COMMENT 1 + +#define YY_EXTRA_TYPE angle::pp::Tokenizer::Context * + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t +{ + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE *yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char *yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE *yylval_r; + + YYLTYPE *yylloc_r; + +}; /* end struct yyguts_t */ + +static int yy_init_globals(yyscan_t yyscanner); + +/* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ +#define yylval yyg->yylval_r + +#define yylloc yyg->yylloc_r + +int yylex_init(yyscan_t *scanner); + +int yylex_init_extra(YY_EXTRA_TYPE user_defined, yyscan_t *scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy(yyscan_t yyscanner); + +int yyget_debug(yyscan_t yyscanner); + +void yyset_debug(int debug_flag, yyscan_t yyscanner); + +YY_EXTRA_TYPE yyget_extra(yyscan_t yyscanner); + +void yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner); + +FILE *yyget_in(yyscan_t yyscanner); + +void yyset_in(FILE *_in_str, yyscan_t yyscanner); + +FILE *yyget_out(yyscan_t yyscanner); + +void yyset_out(FILE *_out_str, yyscan_t yyscanner); + +int yyget_leng(yyscan_t yyscanner); + +char *yyget_text(yyscan_t yyscanner); + +int yyget_lineno(yyscan_t yyscanner); + +void yyset_lineno(int _line_number, yyscan_t yyscanner); + +int yyget_column(yyscan_t yyscanner); + +void yyset_column(int _column_no, yyscan_t yyscanner); + +YYSTYPE *yyget_lval(yyscan_t yyscanner); + +void yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner); + +YYLTYPE *yyget_lloc(yyscan_t yyscanner); + +void yyset_lloc(YYLTYPE *yylloc_param, yyscan_t yyscanner); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +# ifdef __cplusplus +extern "C" int yywrap(yyscan_t yyscanner); +# else +extern int yywrap(yyscan_t yyscanner); +# endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy(char *, const char *, int, yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen(const char *, yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +# ifdef __cplusplus +static int yyinput(yyscan_t yyscanner); +# else +static int input(yyscan_t yyscanner); +# endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +# ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +# define YY_READ_BUF_SIZE 16384 +# else +# define YY_READ_BUF_SIZE 8192 +# endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +# define ECHO \ + do \ + { \ + if (fwrite(yytext, (size_t)yyleng, 1, yyout)) \ + {} \ + } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +# define YY_INPUT(buf, result, max_size) \ + if (YY_CURRENT_BUFFER_LVALUE->yy_is_interactive) \ + { \ + int c = '*'; \ + int n; \ + for (n = 0; n < max_size && (c = getc(yyin)) != EOF && c != '\n'; ++n) \ + buf[n] = (char)c; \ + if (c == '\n') \ + buf[n++] = (char)c; \ + if (c == EOF && ferror(yyin)) \ + YY_FATAL_ERROR("input in flex scanner failed"); \ + result = n; \ + } \ + else \ + { \ + errno = 0; \ + while ((result = (int)fread(buf, 1, (yy_size_t)max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if (errno != EINTR) \ + { \ + YY_FATAL_ERROR("input in flex scanner failed"); \ + break; \ + } \ + errno = 0; \ + clearerr(yyin); \ + } \ + } + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +# define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +# define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +# define YY_FATAL_ERROR(msg) yy_fatal_error(msg, yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +# define YY_DECL_IS_OURS 1 + +extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner); + +# define YY_DECL int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +# define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +# define YY_BREAK /*LINTED*/ break; +#endif + +#define YY_RULE_SETUP YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + yylval = yylval_param; + + yylloc = yylloc_param; + + if (!yyg->yy_init) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if (!yyg->yy_start) + yyg->yy_start = 1; /* first start state */ + + if (!yyin) + yyin = stdin; + + if (!yyout) + yyout = stdout; + + if (!YY_CURRENT_BUFFER) + { + yyensure_buffer_stack(yyscanner); + YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner); + } + + yy_load_buffer_state(yyscanner); + } + + { + + /* Line comment */ + + while (/*CONSTCOND*/ 1) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; + yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if (yy_accept[yy_current_state]) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) + { + yy_current_state = (int)yy_def[yy_current_state]; + if (yy_current_state >= 95) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } while (yy_current_state != 94); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + + yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + do_action: /* This label is used only to access EOF actions. */ + + switch (yy_act) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + + case 1: + YY_RULE_SETUP + + YY_BREAK + /* Block comment */ + /* Line breaks are just counted - not returned. */ + /* The comment is replaced by a single space. */ + case 2: + YY_RULE_SETUP + { + BEGIN(COMMENT); + } + YY_BREAK + case 3: + YY_RULE_SETUP + + YY_BREAK + case 4: + YY_RULE_SETUP + + YY_BREAK + case 5: + /* rule 5 can match eol */ + YY_RULE_SETUP + { + if (yylineno == INT_MAX) + { + *yylval = "Integer overflow on line number"; + return angle::pp::Token::GOT_ERROR; + } + ++yylineno; + } + YY_BREAK + case 6: + YY_RULE_SETUP + { + yyextra->leadingSpace = true; + BEGIN(INITIAL); + } + YY_BREAK + case 7: + YY_RULE_SETUP + { + // # is only valid at start of line for preprocessor directives. + yylval->assign(1, yytext[0]); + return yyextra->lineStart ? angle::pp::Token::PP_HASH + : angle::pp::Token::PP_OTHER; + } + YY_BREAK + case 8: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::IDENTIFIER; + } + YY_BREAK + case 9: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::CONST_INT; + } + YY_BREAK + case 10: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::CONST_FLOAT; + } + YY_BREAK + /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */ + /* Rule to catch all invalid integers and floats. */ + case 11: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::PP_NUMBER; + } + YY_BREAK + case 12: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_INC; + } + YY_BREAK + case 13: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_DEC; + } + YY_BREAK + case 14: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_LEFT; + } + YY_BREAK + case 15: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_RIGHT; + } + YY_BREAK + case 16: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_LE; + } + YY_BREAK + case 17: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_GE; + } + YY_BREAK + case 18: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_EQ; + } + YY_BREAK + case 19: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_NE; + } + YY_BREAK + case 20: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_AND; + } + YY_BREAK + case 21: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_XOR; + } + YY_BREAK + case 22: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_OR; + } + YY_BREAK + case 23: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_ADD_ASSIGN; + } + YY_BREAK + case 24: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_SUB_ASSIGN; + } + YY_BREAK + case 25: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_MUL_ASSIGN; + } + YY_BREAK + case 26: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_DIV_ASSIGN; + } + YY_BREAK + case 27: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_MOD_ASSIGN; + } + YY_BREAK + case 28: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_LEFT_ASSIGN; + } + YY_BREAK + case 29: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_RIGHT_ASSIGN; + } + YY_BREAK + case 30: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_AND_ASSIGN; + } + YY_BREAK + case 31: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_XOR_ASSIGN; + } + YY_BREAK + case 32: + YY_RULE_SETUP + { + yylval->assign(yytext, yyleng); + return angle::pp::Token::OP_OR_ASSIGN; + } + YY_BREAK + case 33: + YY_RULE_SETUP + { + yylval->assign(1, yytext[0]); + return yytext[0]; + } + YY_BREAK + case 34: + YY_RULE_SETUP + { + yyextra->leadingSpace = true; + } + YY_BREAK + case 35: + /* rule 35 can match eol */ + YY_RULE_SETUP + { + if (yylineno == INT_MAX) + { + *yylval = "Integer overflow on line number"; + return angle::pp::Token::GOT_ERROR; + } + ++yylineno; + yylval->assign(1, '\n'); + return '\n'; + } + YY_BREAK + case 36: + YY_RULE_SETUP + { + yylval->assign(1, yytext[0]); + return angle::pp::Token::PP_OTHER; + } + YY_BREAK + case YY_STATE_EOF(INITIAL): + case YY_STATE_EOF(COMMENT): + { + // YY_USER_ACTION is not invoked for handling EOF. + // Set the location for EOF token manually. + angle::pp::Input *input = &yyextra->input; + angle::pp::Input::Location *scanLoc = &yyextra->scanLoc; + yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0; + if (scanLoc->sIndex != sIndexMax) + { + // We can only reach here if there are empty strings at the + // end of the input. + scanLoc->sIndex = sIndexMax; + scanLoc->cIndex = 0; + // FIXME: this is not 64-bit clean. + yyfileno = static_cast<int>(sIndexMax); + yylineno = 1; + } + yylloc->file = yyfileno; + yylloc->line = yylineno; + yylval->clear(); + + // Line number overflows fake EOFs to exit early, check for this case. + if (yylineno == INT_MAX) + { + yyextra->diagnostics->report(angle::pp::Diagnostics::PP_TOKENIZER_ERROR, + angle::pp::SourceLocation(yyfileno, yylineno), + "Integer overflow on line number"); + } + else if (YY_START == COMMENT) + { + yyextra->diagnostics->report(angle::pp::Diagnostics::PP_EOF_IN_COMMENT, + angle::pp::SourceLocation(yyfileno, yylineno), + "EOF while in a comment"); + } + yyterminate(); + } + YY_BREAK + case 37: + YY_RULE_SETUP + ECHO; + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int)(yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if (YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if (yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(yyscanner); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans(yy_current_state, yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if (yy_next_state) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else + switch (yy_get_next_buffer(yyscanner)) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if (yywrap(yyscanner)) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if (!yyg->yy_did_buffer_switch_on_eof) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(yyscanner); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state(yyscanner); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR("fatal flex scanner internal error--no action found"); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if (yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1]) + YY_FATAL_ERROR("fatal flex scanner internal error--end of buffer missed"); + + if (YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0) + { /* Don't try to fill the buffer, so this is an EOF. */ + if (yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int)(yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for (i = 0; i < number_to_move; ++i) + *(dest++) = *(source++); + + if (YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while (num_to_read <= 0) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = (int)(yyg->yy_c_buf_p - b->yy_ch_buf); + + if (b->yy_is_our_buffer) + { + int new_size = b->yy_buf_size * 2; + + if (new_size <= 0) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *)b->yy_ch_buf, (yy_size_t)(b->yy_buf_size + 2), yyscanner); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if (!b->yy_ch_buf) + YY_FATAL_ERROR("fatal error - scanner input buffer overflow"); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + } + + if (num_to_read > YY_READ_BUF_SIZE) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + yy_size_t ret = 0; + YY_INPUT((&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), ret, num_to_read); + yyg->yy_n_chars = static_cast<int>(ret); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if (yyg->yy_n_chars == 0) + { + if (number_to_move == YY_MORE_ADJ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin, yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) + { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *)yyrealloc( + (void *)YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t)new_size, yyscanner); + if (!YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) + YY_FATAL_ERROR("out of dynamic memory in yy_get_next_buffer()"); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int)(new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state(yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + yy_current_state = yyg->yy_start; + + for (yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if (yy_accept[yy_current_state]) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) + { + yy_current_state = (int)yy_def[yy_current_state]; + if (yy_current_state >= 95) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ +static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state, yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t *yyg = + (struct yyguts_t *)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if (yy_accept[yy_current_state]) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) + { + yy_current_state = (int)yy_def[yy_current_state]; + if (yy_current_state >= 95) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 94); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +# ifdef __cplusplus +static int yyinput(yyscan_t yyscanner) +# else +static int input(yyscan_t yyscanner) +# endif + +{ + int c; + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if (*yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if (yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int)(yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch (yy_get_next_buffer(yyscanner)) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin, yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if (yywrap(yyscanner)) + return 0; + + if (!yyg->yy_did_buffer_switch_on_eof) + YY_NEW_FILE; +# ifdef __cplusplus + return yyinput(yyscanner); +# else + return input(yyscanner); +# endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *)yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ +void yyrestart(FILE *input_file, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + if (!YY_CURRENT_BUFFER) + { + yyensure_buffer_stack(yyscanner); + YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner); + } + + yy_init_buffer(YY_CURRENT_BUFFER, input_file, yyscanner); + yy_load_buffer_state(yyscanner); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ +void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack(yyscanner); + if (YY_CURRENT_BUFFER == new_buffer) + return; + + if (YY_CURRENT_BUFFER) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state(yyscanner); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ +YY_BUFFER_STATE yy_create_buffer(FILE *file, int size, yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE)yyalloc(sizeof(struct yy_buffer_state), yyscanner); + if (!b) + YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()"); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *)yyalloc((yy_size_t)(b->yy_buf_size + 2), yyscanner); + if (!b->yy_ch_buf) + YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()"); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b, file, yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ +void yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + if (!b) + return; + + if (b == YY_CURRENT_BUFFER) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE)0; + + if (b->yy_is_our_buffer) + yyfree((void *)b->yy_ch_buf, yyscanner); + + yyfree((void *)b, yyscanner); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ +static void yy_init_buffer(YY_BUFFER_STATE b, FILE *file, yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + yy_flush_buffer(b, yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER) + { + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ +void yy_flush_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + if (!b) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if (b == YY_CURRENT_BUFFER) + yy_load_buffer_state(yyscanner); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if (YY_CURRENT_BUFFER) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state(yyscanner); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) + { + yy_load_buffer_state(yyscanner); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack(yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + if (!yyg->yy_buffer_stack) + { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state **)yyalloc( + num_to_alloc * sizeof(struct yy_buffer_state *), yyscanner); + if (!yyg->yy_buffer_stack) + YY_FATAL_ERROR("out of dynamic memory in yyensure_buffer_stack()"); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state *)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1) + { + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state **)yyrealloc( + yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state *), yyscanner); + if (!yyg->yy_buffer_stack) + YY_FATAL_ERROR("out of dynamic memory in yyensure_buffer_stack()"); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, + grow_size * sizeof(struct yy_buffer_state *)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if (size < 2 || base[size - 2] != YY_END_OF_BUFFER_CHAR || + base[size - 1] != YY_END_OF_BUFFER_CHAR) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE)yyalloc(sizeof(struct yy_buffer_state), yyscanner); + if (!b) + YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()"); + + b->yy_buf_size = (int)(size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b, yyscanner); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string(const char *yystr, yyscan_t yyscanner) +{ + + return yy_scan_bytes(yystr, (int)strlen(yystr), yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes(const char *yybytes, int _yybytes_len, yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t)(_yybytes_len + 2); + buf = (char *)yyalloc(n, yyscanner); + if (!buf) + YY_FATAL_ERROR("out of dynamic memory in yy_scan_bytes()"); + + for (i = 0; i < _yybytes_len; ++i) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len + 1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf, n, yyscanner); + if (!b) + YY_FATAL_ERROR("bad buffer in yy_scan_bytes()"); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +# define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error(const char *msg, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + (void)yyg; + fprintf(stderr, "%s\n", msg); + exit(YY_EXIT_FAILURE); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg); \ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } while (0) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + if (!YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + if (!YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + yyextra = user_defined; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno(int _line_number, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (!YY_CURRENT_BUFFER) + YY_FATAL_ERROR("yyset_lineno called with no buffer"); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column(int _column_no, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (!YY_CURRENT_BUFFER) + YY_FATAL_ERROR("yyset_column called with no buffer"); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in(FILE *_in_str, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + yyin = _in_str; +} + +void yyset_out(FILE *_out_str, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + yyout = _out_str; +} + +int yyget_debug(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + return yy_flex_debug; +} + +void yyset_debug(int _bdebug, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + yy_flex_debug = _bdebug; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE *yyget_lval(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + return yylval; +} + +void yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *yyget_lloc(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + return yylloc; +} + +void yyset_lloc(YYLTYPE *yylloc_param, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t *ptr_yy_globals) +{ + if (ptr_yy_globals == NULL) + { + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t)yyalloc(sizeof(struct yyguts_t), NULL); + + if (*ptr_yy_globals == NULL) + { + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals, 0x00, sizeof(struct yyguts_t)); + + return yy_init_globals(*ptr_yy_globals); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined, yyscan_t *ptr_yy_globals) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra(yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL) + { + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t)yyalloc(sizeof(struct yyguts_t), &dummy_yyguts); + + if (*ptr_yy_globals == NULL) + { + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals, 0x00, sizeof(struct yyguts_t)); + + yyset_extra(yy_user_defined, *ptr_yy_globals); + + return yy_init_globals(*ptr_yy_globals); +} + +static int yy_init_globals(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy(yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while (YY_CURRENT_BUFFER) + { + yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack, yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree(yyg->yy_start_stack, yyscanner); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals(yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree(yyscanner, yyscanner); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy(char *s1, const char *s2, int n, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + (void)yyg; + + int i; + for (i = 0; i < n; ++i) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen(const char *s, yyscan_t yyscanner) +{ + int n; + for (n = 0; s[n]; ++n) + ; + + return n; +} +#endif + +void *yyalloc(yy_size_t size, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree(void *ptr, yyscan_t yyscanner) +{ + struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; + (void)yyg; + free((char *)ptr); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +namespace angle +{ + +namespace pp +{ + +Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(256) +{ + mContext.diagnostics = diagnostics; +} + +Tokenizer::~Tokenizer() +{ + destroyScanner(); +} + +bool Tokenizer::init(size_t count, const char *const string[], const int length[]) +{ + if ((count > 0) && (string == 0)) + return false; + + mContext.input = Input(count, string, length); + return initScanner(); +} + +void Tokenizer::setFileNumber(int file) +{ + // We use column number as file number. + // See macro yyfileno. + yyset_column(file, mHandle); +} + +void Tokenizer::setLineNumber(int line) +{ + yyset_lineno(line, mHandle); +} + +void Tokenizer::setMaxTokenSize(size_t maxTokenSize) +{ + mMaxTokenSize = maxTokenSize; +} + +void Tokenizer::lex(Token *token) +{ + int tokenType = yylex(&token->text, &token->location, mHandle); + + if (tokenType == Token::GOT_ERROR) + { + mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text); + token->type = Token::LAST; + } + else + { + token->type = tokenType; + } + + if (token->text.size() > mMaxTokenSize) + { + mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG, token->location, token->text); + token->text.erase(mMaxTokenSize); + } + + token->flags = 0; + + token->setAtStartOfLine(mContext.lineStart); + mContext.lineStart = token->type == '\n'; + + token->setHasLeadingSpace(mContext.leadingSpace); + mContext.leadingSpace = false; +} + +bool Tokenizer::initScanner() +{ + if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle)) + return false; + + yyrestart(0, mHandle); + return true; +} + +void Tokenizer::destroyScanner() +{ + if (mHandle == nullptr) + return; + + yylex_destroy(mHandle); + mHandle = nullptr; +} + +} // namespace pp + +} // namespace angle diff --git a/gfx/angle/checkout/src/compiler/preprocessor/preprocessor_tab_autogen.cpp b/gfx/angle/checkout/src/compiler/preprocessor/preprocessor_tab_autogen.cpp new file mode 100644 index 0000000000..a7607c9e52 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/preprocessor/preprocessor_tab_autogen.cpp @@ -0,0 +1,1773 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output, and Bison version. */ +#define YYBISON 30802 + +/* Bison version string. */ +#define YYBISON_VERSION "3.8.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Substitute the type names. */ +#define YYSTYPE PPSTYPE +/* Substitute the variable and function names. */ +#define yyparse ppparse +#define yylex pplex +#define yyerror pperror +#define yydebug ppdebug +#define yynerrs ppnerrs + +/* First part of user prologue. */ + +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_parser.py from preprocessor.y +// +// Copyright 2019 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. +// +// preprocessor.y: +// Parser for the OpenGL shading language preprocessor. + +#if defined(__GNUC__) +// Triggered by the auto-generated pplval variable. +# if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +# else +# pragma GCC diagnostic ignored "-Wuninitialized" +# endif +#elif defined(_MSC_VER) +# pragma warning(disable : 4065 4244 4701 4702) +#endif +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunreachable-code" +# pragma clang diagnostic ignored "-Wunused-but-set-variable" +#endif + +#include "ExpressionParser.h" + +#if defined(_MSC_VER) +# include <malloc.h> +#else +# include <stdlib.h> +#endif + +#include <stdint.h> +#include <cassert> +#include <sstream> + +#include "DiagnosticsBase.h" +#include "Lexer.h" +#include "Token.h" +#include "common/mathutil.h" + +typedef int32_t YYSTYPE; +typedef uint32_t UNSIGNED_TYPE; + +#define YYENABLE_NLS 0 +#define YYLTYPE_IS_TRIVIAL 1 +#define YYSTYPE_IS_TRIVIAL 1 +#define YYSTYPE_IS_DECLARED 1 + +namespace +{ +struct Context +{ + angle::pp::Diagnostics *diagnostics; + angle::pp::Lexer *lexer; + angle::pp::Token *token; + int *result; + bool parsePresetToken; + + angle::pp::ExpressionParser::ErrorSettings errorSettings; + bool *valid; + + void startIgnoreErrors() { ++ignoreErrors; } + void endIgnoreErrors() { --ignoreErrors; } + + bool isIgnoringErrors() { return ignoreErrors > 0; } + + int ignoreErrors; +}; +} // namespace + +static int yylex(YYSTYPE *lvalp, Context *context); +static void yyerror(Context *context, const char *reason); + +#ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast<Type>(Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type>(Val) +# else +# define YY_CAST(Type, Val) ((Type)(Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type)(Val)) +# endif +#endif +#ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void *)0) +# endif +#endif + +/* Debug traces. */ +#ifndef PPDEBUG +# if defined YYDEBUG +# if YYDEBUG +# define PPDEBUG 1 +# else +# define PPDEBUG 0 +# endif +# else /* ! defined YYDEBUG */ +# define PPDEBUG 0 +# endif /* ! defined YYDEBUG */ +#endif /* ! defined PPDEBUG */ +#if PPDEBUG +extern int ppdebug; +#endif + +/* Token kinds. */ +#ifndef PPTOKENTYPE +# define PPTOKENTYPE +enum pptokentype +{ + PPEMPTY = -2, + PPEOF = 0, /* "end of file" */ + PPerror = 256, /* error */ + PPUNDEF = 257, /* "invalid token" */ + TOK_CONST_INT = 258, /* TOK_CONST_INT */ + TOK_IDENTIFIER = 259, /* TOK_IDENTIFIER */ + TOK_OP_OR = 260, /* TOK_OP_OR */ + TOK_OP_AND = 261, /* TOK_OP_AND */ + TOK_OP_EQ = 262, /* TOK_OP_EQ */ + TOK_OP_NE = 263, /* TOK_OP_NE */ + TOK_OP_LE = 264, /* TOK_OP_LE */ + TOK_OP_GE = 265, /* TOK_OP_GE */ + TOK_OP_LEFT = 266, /* TOK_OP_LEFT */ + TOK_OP_RIGHT = 267, /* TOK_OP_RIGHT */ + TOK_UNARY = 268 /* TOK_UNARY */ +}; +typedef enum pptokentype pptoken_kind_t; +#endif + +/* Value type. */ +#if !defined PPSTYPE && !defined PPSTYPE_IS_DECLARED +typedef int PPSTYPE; +# define PPSTYPE_IS_TRIVIAL 1 +# define PPSTYPE_IS_DECLARED 1 +#endif + +int ppparse(Context *context); + +/* Symbol kind. */ +enum yysymbol_kind_t +{ + YYSYMBOL_YYEMPTY = -2, + YYSYMBOL_YYEOF = 0, /* "end of file" */ + YYSYMBOL_YYerror = 1, /* error */ + YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ + YYSYMBOL_TOK_CONST_INT = 3, /* TOK_CONST_INT */ + YYSYMBOL_TOK_IDENTIFIER = 4, /* TOK_IDENTIFIER */ + YYSYMBOL_TOK_OP_OR = 5, /* TOK_OP_OR */ + YYSYMBOL_TOK_OP_AND = 6, /* TOK_OP_AND */ + YYSYMBOL_7_ = 7, /* '|' */ + YYSYMBOL_8_ = 8, /* '^' */ + YYSYMBOL_9_ = 9, /* '&' */ + YYSYMBOL_TOK_OP_EQ = 10, /* TOK_OP_EQ */ + YYSYMBOL_TOK_OP_NE = 11, /* TOK_OP_NE */ + YYSYMBOL_12_ = 12, /* '<' */ + YYSYMBOL_13_ = 13, /* '>' */ + YYSYMBOL_TOK_OP_LE = 14, /* TOK_OP_LE */ + YYSYMBOL_TOK_OP_GE = 15, /* TOK_OP_GE */ + YYSYMBOL_TOK_OP_LEFT = 16, /* TOK_OP_LEFT */ + YYSYMBOL_TOK_OP_RIGHT = 17, /* TOK_OP_RIGHT */ + YYSYMBOL_18_ = 18, /* '+' */ + YYSYMBOL_19_ = 19, /* '-' */ + YYSYMBOL_20_ = 20, /* '*' */ + YYSYMBOL_21_ = 21, /* '/' */ + YYSYMBOL_22_ = 22, /* '%' */ + YYSYMBOL_TOK_UNARY = 23, /* TOK_UNARY */ + YYSYMBOL_24_ = 24, /* '!' */ + YYSYMBOL_25_ = 25, /* '~' */ + YYSYMBOL_26_ = 26, /* '(' */ + YYSYMBOL_27_ = 27, /* ')' */ + YYSYMBOL_YYACCEPT = 28, /* $accept */ + YYSYMBOL_input = 29, /* input */ + YYSYMBOL_expression = 30, /* expression */ + YYSYMBOL_31_1 = 31, /* $@1 */ + YYSYMBOL_32_2 = 32 /* $@2 */ +}; +typedef enum yysymbol_kind_t yysymbol_kind_t; + +#ifdef short +# undef short +#endif + +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + <limits.h> and (if available) <stdint.h> are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include <limits.h> /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include <stdint.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif +#endif + +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; +#else +typedef short yytype_int16; +#endif + +/* Work around bug in HP-UX 11.23, which defines these macros + incorrectly for preprocessor constants. This workaround can likely + be removed in 2023, as HPE has promised support for HP-UX 11.23 + (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of + <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>. */ +#ifdef __hpux +# undef UINT_LEAST8_MAX +# undef UINT_LEAST16_MAX +# define UINT_LEAST8_MAX 255 +# define UINT_LEAST16_MAX 65535 +#endif + +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; +#else +typedef short yytype_uint8; +#endif + +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; +#else +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned +# endif +#endif + +#define YYSIZE_MAXIMUM \ + YY_CAST(YYPTRDIFF_T, (YYPTRDIFF_MAXIMUM < YY_CAST(YYSIZE_T, -1) ? YYPTRDIFF_MAXIMUM \ + : YY_CAST(YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST(YYPTRDIFF_T, sizeof(X)) + +/* Stored state numbers (used for stacks). */ +typedef yytype_int8 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if !defined lint || defined __GNUC__ +# define YY_USE(E) ((void)(E)) +#else +# define YY_USE(E) /* empty */ +#endif + +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +#if defined __GNUC__ && !defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ +# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") +# else +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# endif +# define YY_IGNORE_MAYBE_UNINITIALIZED_END _Pragma("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && !defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END _Pragma("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + +#define YY_ASSERT(E) ((void)(0 && (E))) + +#if !defined yyoverflow + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if !defined _ALLOCA_H && !defined EXIT_SUCCESS +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +/* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC +/* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) \ + do \ + { /* empty */ \ + ; \ + } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM +/* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && !defined EXIT_SUCCESS && \ + !((defined YYMALLOC || defined malloc) && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if !defined malloc && !defined EXIT_SUCCESS +void *malloc(YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if !defined free && !defined EXIT_SUCCESS +void free(void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* !defined yyoverflow */ + +#if (!defined yyoverflow && \ + (!defined __cplusplus || (defined PPSTYPE_IS_TRIVIAL && PPSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yy_state_t yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF(union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (YYSIZEOF(yy_state_t) + YYSIZEOF(YYSTYPE)) + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYPTRDIFF_T yynewbytes; \ + YYCOPY(&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * YYSIZEOF(*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF(*yyptr); \ + } while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy(Dst, Src, YY_CAST(YYSIZE_T, (Count)) * sizeof(*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYPTRDIFF_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 15 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 176 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 28 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 5 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 29 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 55 + +/* YYMAXUTOK -- Last valid token kind. */ +#define YYMAXUTOK 268 + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ +#define YYTRANSLATE(YYX) \ + (0 <= (YYX) && (YYX) <= YYMAXUTOK ? YY_CAST(yysymbol_kind_t, yytranslate[YYX]) \ + : YYSYMBOL_YYUNDEF) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex. */ +static const yytype_int8 yytranslate[] = { + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 24, 2, 2, 2, 22, 9, 2, 26, 27, 20, 18, 2, 19, 2, 21, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 12, 2, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 25, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 10, 11, 14, 15, 16, 17, 23}; + +#if PPDEBUG +/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_int16 yyrline[] = {0, 114, 114, 121, 122, 133, 133, 154, 154, 175, + 178, 181, 184, 187, 190, 193, 196, 199, 202, 227, + 249, 252, 255, 281, 308, 311, 314, 317, 329, 332}; +#endif + +/** Accessing symbol of state STATE. */ +#define YY_ACCESSING_SYMBOL(State) YY_CAST(yysymbol_kind_t, yystos[State]) + +#if PPDEBUG || 0 +/* The user-facing name of the symbol whose (internal) number is + YYSYMBOL. No bounds checking. */ +static const char *yysymbol_name(yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; + +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = {"\"end of file\"", + "error", + "\"invalid token\"", + "TOK_CONST_INT", + "TOK_IDENTIFIER", + "TOK_OP_OR", + "TOK_OP_AND", + "'|'", + "'^'", + "'&'", + "TOK_OP_EQ", + "TOK_OP_NE", + "'<'", + "'>'", + "TOK_OP_LE", + "TOK_OP_GE", + "TOK_OP_LEFT", + "TOK_OP_RIGHT", + "'+'", + "'-'", + "'*'", + "'/'", + "'%'", + "TOK_UNARY", + "'!'", + "'~'", + "'('", + "')'", + "$accept", + "input", + "expression", + "$@1", + "$@2", + YY_NULLPTR}; + +static const char *yysymbol_name(yysymbol_kind_t yysymbol) +{ + return yytname[yysymbol]; +} +#endif + +#define YYPACT_NINF (-12) + +#define yypact_value_is_default(Yyn) ((Yyn) == YYPACT_NINF) + +#define YYTABLE_NINF (-1) + +#define yytable_value_is_error(Yyn) 0 + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = { + 31, -12, -12, 31, 31, 31, 31, 31, 51, 76, -12, -12, -12, -12, 53, -12, -12, -12, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, -12, 31, 31, 124, + 138, 26, 149, 149, -11, -11, -11, -11, 154, 154, -8, -8, -12, -12, -12, 93, 109}; + +/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_int8 yydefact[] = {0, 3, 4, 0, 0, 0, 0, 0, 0, 2, 28, 27, 25, 26, + 0, 1, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 29, 0, 0, 9, 10, 11, 13, 12, + 17, 16, 15, 14, 19, 18, 21, 20, 24, 23, 22, 6, 8}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = {-12, -12, -3, -12, -12}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = {0, 8, 9, 35, 36}; + +/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int8 yytable[] = { + 10, 11, 12, 13, 14, 27, 28, 29, 30, 31, 32, 33, 31, 32, 33, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 0, 53, 54, 1, 2, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 3, 4, 15, 0, 0, 0, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 0, 0, 0, 0, 34, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 29, 30, 31, 32, 33}; + +static const yytype_int8 yycheck[] = { + 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 20, 21, 22, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 18, 19, 0, -1, -1, -1, 24, 25, 26, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, -1, -1, -1, -1, 27, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 18, 19, 20, 21, 22}; + +/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of + state STATE-NUM. */ +static const yytype_int8 yystos[] = {0, 3, 4, 18, 19, 24, 25, 26, 29, 30, 30, 30, 30, 30, + 30, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 27, 31, 32, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}; + +/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr1[] = {0, 28, 29, 30, 30, 31, 30, 32, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}; + +/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr2[] = {0, 2, 1, 1, 1, 0, 4, 0, 4, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3}; + +enum +{ + YYENOMEM = -2 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = PPEMPTY) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == PPEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK(yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror(context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) + +/* Backward compatibility with an undocumented macro. + Use PPerror or PPUNDEF. */ +#define YYERRCODE PPUNDEF + +/* Enable debugging if requested. */ +#if PPDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ + do \ + { \ + if (yydebug) \ + YYFPRINTF Args; \ + } while (0) + +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ + do \ + { \ + if (yydebug) \ + { \ + YYFPRINTF(stderr, "%s ", Title); \ + yy_symbol_print(stderr, Kind, Value, context); \ + YYFPRINTF(stderr, "\n"); \ + } \ + } while (0) + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void yy_symbol_value_print(FILE *yyo, + yysymbol_kind_t yykind, + YYSTYPE const *const yyvaluep, + Context *context) +{ + FILE *yyoutput = yyo; + YY_USE(yyoutput); + YY_USE(context); + if (!yyvaluep) + return; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE(yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ + +static void yy_symbol_print(FILE *yyo, + yysymbol_kind_t yykind, + YYSTYPE const *const yyvaluep, + Context *context) +{ + YYFPRINTF(yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name(yykind)); + + yy_symbol_value_print(yyo, yykind, yyvaluep, context); + YYFPRINTF(yyo, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void yy_stack_print(yy_state_t *yybottom, yy_state_t *yytop) +{ + YYFPRINTF(stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF(stderr, " %d", yybot); + } + YYFPRINTF(stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ + do \ + { \ + if (yydebug) \ + yy_stack_print((Bottom), (Top)); \ + } while (0) + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void yy_reduce_print(yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule, Context *context) +{ + int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF(stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF(stderr, " $%d = ", yyi + 1); + yy_symbol_print(stderr, YY_ACCESSING_SYMBOL(+yyssp[yyi + 1 - yynrhs]), + &yyvsp[(yyi + 1) - (yynrhs)], context); + YYFPRINTF(stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ + do \ + { \ + if (yydebug) \ + yy_reduce_print(yyssp, yyvsp, Rule, context); \ + } while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !PPDEBUG */ +# define YYDPRINTF(Args) ((void)0) +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !PPDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void yydestruct(const char *yymsg, + yysymbol_kind_t yykind, + YYSTYPE *yyvaluep, + Context *context) +{ + YY_USE(yyvaluep); + YY_USE(context); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT(yymsg, yykind, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE(yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + +/*----------. +| yyparse. | +`----------*/ + +int yyparse(Context *context) +{ + /* Lookahead token kind. */ + int yychar; + + /* The semantic value of the lookahead symbol. */ + /* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ + YY_INITIAL_VALUE(static YYSTYPE yyval_default;) + YYSTYPE yylval YY_INITIAL_VALUE(= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs = 0; + + yy_state_fast_t yystate = 0; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus = 0; + + /* Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* Their size. */ + YYPTRDIFF_T yystacksize = YYINITDEPTH; + + /* The state stack: array, bottom, top. */ + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss = yyssa; + yy_state_t *yyssp = yyss; + + /* The semantic value stack: array, bottom, top. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp = yyvs; + + int yyn; + /* The return value of yyparse. */ + int yyresult; + /* Lookahead symbol kind. */ + yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF((stderr, "Starting parse\n")); + + yychar = PPEMPTY; /* Cause a token to be read. */ + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- push a new state, which is found in yystate. | +`------------------------------------------------------------*/ +yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + +/*--------------------------------------------------------------------. +| yysetstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + YYDPRINTF((stderr, "Entering state %d\n", yystate)); + YY_ASSERT(0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST(yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END + YY_STACK_PRINT(yyss, yyssp); + + if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + YYNOMEM; +#else + { + /* Get the current used size of the three stacks, in elements. */ + YYPTRDIFF_T yysize = yyssp - yyss + 1; + +# if defined yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + yy_state_t *yyss1 = yyss; + YYSTYPE *yyvs1 = yyvs; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow(YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF(*yyssp), &yyvs1, + yysize * YYSIZEOF(*yyvsp), &yystacksize); + yyss = yyss1; + yyvs = yyvs1; + } +# else /* defined YYSTACK_RELOCATE */ + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + YYNOMEM; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yy_state_t *yyss1 = yyss; + union yyalloc *yyptr = YY_CAST( + union yyalloc *, YYSTACK_ALLOC(YY_CAST(YYSIZE_T, YYSTACK_BYTES(yystacksize)))); + if (!yyptr) + YYNOMEM; + YYSTACK_RELOCATE(yyss_alloc, yyss); + YYSTACK_RELOCATE(yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE(yyss1); + } +# endif + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF((stderr, "Stack size increased to %ld\n", YY_CAST(long, yystacksize))); + YY_IGNORE_USELESS_CAST_END + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default(yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ + if (yychar == PPEMPTY) + { + YYDPRINTF((stderr, "Reading a token\n")); + yychar = yylex(&yylval, context); + } + + if (yychar <= PPEOF) + { + yychar = PPEOF; + yytoken = YYSYMBOL_YYEOF; + YYDPRINTF((stderr, "Now at end of input.\n")); + } + else if (yychar == PPerror) + { + /* The scanner already issued an error message, process directly + to error recovery. But do not keep the error token as + lookahead, it is too special and may lead us to an endless + loop in error recovery. */ + yychar = PPUNDEF; + yytoken = YYSYMBOL_YYerror; + goto yyerrlab1; + } + else + { + yytoken = YYTRANSLATE(yychar); + YY_SYMBOL_PRINT("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error(yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT("Shifting", yytoken, &yylval, &yylloc); + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + /* Discard the shifted token. */ + yychar = PPEMPTY; + goto yynewstate; + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + +/*-----------------------------. +| yyreduce -- do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1 - yylen]; + + YY_REDUCE_PRINT(yyn); + switch (yyn) + { + case 2: /* input: expression */ + { + *(context->result) = static_cast<int>(yyvsp[0]); + YYACCEPT; + } + break; + + case 4: /* expression: TOK_IDENTIFIER */ + { + if (!context->isIgnoringErrors()) + { + // This rule should be applied right after the token is lexed, so we can + // refer to context->token in the error message. + context->diagnostics->report(context->errorSettings.unexpectedIdentifier, + context->token->location, context->token->text); + *(context->valid) = false; + } + yyval = yyvsp[0]; + } + break; + + case 5: /* $@1: %empty */ + { + if (yyvsp[-1] != 0) + { + // Ignore errors in the short-circuited part of the expression. + // ESSL3.00 section 3.4: + // If an operand is not evaluated, the presence of undefined identifiers + // in the operand will not cause an error. + // Unevaluated division by zero should not cause an error either. + context->startIgnoreErrors(); + } + } + break; + + case 6: /* expression: expression TOK_OP_OR $@1 expression */ + { + if (yyvsp[-3] != 0) + { + context->endIgnoreErrors(); + yyval = static_cast<YYSTYPE>(1); + } + else + { + yyval = yyvsp[-3] || yyvsp[0]; + } + } + break; + + case 7: /* $@2: %empty */ + { + if (yyvsp[-1] == 0) + { + // Ignore errors in the short-circuited part of the expression. + // ESSL3.00 section 3.4: + // If an operand is not evaluated, the presence of undefined identifiers + // in the operand will not cause an error. + // Unevaluated division by zero should not cause an error either. + context->startIgnoreErrors(); + } + } + break; + + case 8: /* expression: expression TOK_OP_AND $@2 expression */ + { + if (yyvsp[-3] == 0) + { + context->endIgnoreErrors(); + yyval = static_cast<YYSTYPE>(0); + } + else + { + yyval = yyvsp[-3] && yyvsp[0]; + } + } + break; + + case 9: /* expression: expression '|' expression */ + { + yyval = yyvsp[-2] | yyvsp[0]; + } + break; + + case 10: /* expression: expression '^' expression */ + { + yyval = yyvsp[-2] ^ yyvsp[0]; + } + break; + + case 11: /* expression: expression '&' expression */ + { + yyval = yyvsp[-2] & yyvsp[0]; + } + break; + + case 12: /* expression: expression TOK_OP_NE expression */ + { + yyval = yyvsp[-2] != yyvsp[0]; + } + break; + + case 13: /* expression: expression TOK_OP_EQ expression */ + { + yyval = yyvsp[-2] == yyvsp[0]; + } + break; + + case 14: /* expression: expression TOK_OP_GE expression */ + { + yyval = yyvsp[-2] >= yyvsp[0]; + } + break; + + case 15: /* expression: expression TOK_OP_LE expression */ + { + yyval = yyvsp[-2] <= yyvsp[0]; + } + break; + + case 16: /* expression: expression '>' expression */ + { + yyval = yyvsp[-2] > yyvsp[0]; + } + break; + + case 17: /* expression: expression '<' expression */ + { + yyval = yyvsp[-2] < yyvsp[0]; + } + break; + + case 18: /* expression: expression TOK_OP_RIGHT expression */ + { + if (yyvsp[0] < 0 || yyvsp[0] > 31) + { + if (!context->isIgnoringErrors()) + { + std::ostringstream stream; + stream << yyvsp[-2] << " >> " << yyvsp[0]; + std::string text = stream.str(); + context->diagnostics->report(angle::pp::Diagnostics::PP_UNDEFINED_SHIFT, + context->token->location, text.c_str()); + *(context->valid) = false; + } + yyval = static_cast<YYSTYPE>(0); + } + else if (yyvsp[-2] < 0) + { + // Logical shift right. + yyval = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>(yyvsp[-2]) >> yyvsp[0]); + } + else + { + yyval = yyvsp[-2] >> yyvsp[0]; + } + } + break; + + case 19: /* expression: expression TOK_OP_LEFT expression */ + { + if (yyvsp[0] < 0 || yyvsp[0] > 31) + { + if (!context->isIgnoringErrors()) + { + std::ostringstream stream; + stream << yyvsp[-2] << " << " << yyvsp[0]; + std::string text = stream.str(); + context->diagnostics->report(angle::pp::Diagnostics::PP_UNDEFINED_SHIFT, + context->token->location, text.c_str()); + *(context->valid) = false; + } + yyval = static_cast<YYSTYPE>(0); + } + else + { + // Logical shift left. Casting to unsigned is needed to ensure there's no signed + // integer overflow, which some tools treat as an error. + yyval = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>(yyvsp[-2]) << yyvsp[0]); + } + } + break; + + case 20: /* expression: expression '-' expression */ + { + yyval = gl::WrappingDiff<YYSTYPE>(yyvsp[-2], yyvsp[0]); + } + break; + + case 21: /* expression: expression '+' expression */ + { + yyval = gl::WrappingSum<YYSTYPE>(yyvsp[-2], yyvsp[0]); + } + break; + + case 22: /* expression: expression '%' expression */ + { + if (yyvsp[0] == 0) + { + if (!context->isIgnoringErrors()) + { + std::ostringstream stream; + stream << yyvsp[-2] << " % " << yyvsp[0]; + std::string text = stream.str(); + context->diagnostics->report(angle::pp::Diagnostics::PP_DIVISION_BY_ZERO, + context->token->location, text.c_str()); + *(context->valid) = false; + } + yyval = static_cast<YYSTYPE>(0); + } + else if ((yyvsp[-2] == std::numeric_limits<YYSTYPE>::min()) && (yyvsp[0] == -1)) + { + // Check for the special case where the minimum representable number is + // divided by -1. If left alone this has undefined results. + yyval = 0; + } + else + { + yyval = yyvsp[-2] % yyvsp[0]; + } + } + break; + + case 23: /* expression: expression '/' expression */ + { + if (yyvsp[0] == 0) + { + if (!context->isIgnoringErrors()) + { + std::ostringstream stream; + stream << yyvsp[-2] << " / " << yyvsp[0]; + std::string text = stream.str(); + context->diagnostics->report(angle::pp::Diagnostics::PP_DIVISION_BY_ZERO, + context->token->location, text.c_str()); + *(context->valid) = false; + } + yyval = static_cast<YYSTYPE>(0); + } + else if ((yyvsp[-2] == std::numeric_limits<YYSTYPE>::min()) && (yyvsp[0] == -1)) + { + // Check for the special case where the minimum representable number is + // divided by -1. If left alone this leads to integer overflow in C++, which + // has undefined results. + yyval = std::numeric_limits<YYSTYPE>::max(); + } + else + { + yyval = yyvsp[-2] / yyvsp[0]; + } + } + break; + + case 24: /* expression: expression '*' expression */ + { + yyval = gl::WrappingMul(yyvsp[-2], yyvsp[0]); + } + break; + + case 25: /* expression: '!' expression */ + { + yyval = !yyvsp[0]; + } + break; + + case 26: /* expression: '~' expression */ + { + yyval = ~yyvsp[0]; + } + break; + + case 27: /* expression: '-' expression */ + { + // Check for negation of minimum representable integer to prevent undefined signed int + // overflow. + if (yyvsp[0] == std::numeric_limits<YYSTYPE>::min()) + { + yyval = std::numeric_limits<YYSTYPE>::min(); + } + else + { + yyval = -yyvsp[0]; + } + } + break; + + case 28: /* expression: '+' expression */ + { + yyval = +yyvsp[0]; + } + break; + + case 29: /* expression: '(' expression ')' */ + { + yyval = yyvsp[-1]; + } + break; + + default: + break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT("-> $$ =", YY_CAST(yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); + + YYPOPSTACK(yylen); + yylen = 0; + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = + (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); + } + + goto yynewstate; + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == PPEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE(yychar); + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + yyerror(context, YY_("syntax error")); + } + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= PPEOF) + { + /* Return failure if at end of input. */ + if (yychar == PPEOF) + YYABORT; + } + else + { + yydestruct("Error: discarding", yytoken, &yylval, context); + yychar = PPEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; + ++yynerrs; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK(yylen); + yylen = 0; + YY_STACK_PRINT(yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + /* Pop stack until we find a state that shifts the error token. */ + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default(yyn)) + { + yyn += YYSYMBOL_YYerror; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yydestruct("Error: popping", YY_ACCESSING_SYMBOL(yystate), yyvsp, context); + YYPOPSTACK(1); + yystate = *yyssp; + YY_STACK_PRINT(yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + /* Shift the error token. */ + YY_SYMBOL_PRINT("Shifting", YY_ACCESSING_SYMBOL(yyn), yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturnlab; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturnlab; + +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ +yyexhaustedlab: + yyerror(context, YY_("memory exhausted")); + yyresult = 2; + goto yyreturnlab; + +/*----------------------------------------------------------. +| yyreturnlab -- parsing is finished, clean up and return. | +`----------------------------------------------------------*/ +yyreturnlab: + if (yychar != PPEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE(yychar); + yydestruct("Cleanup: discarding lookahead", yytoken, &yylval, context); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK(yylen); + YY_STACK_PRINT(yyss, yyssp); + while (yyssp != yyss) + { + yydestruct("Cleanup: popping", YY_ACCESSING_SYMBOL(+*yyssp), yyvsp, context); + YYPOPSTACK(1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE(yyss); +#endif + + return yyresult; +} + +int yylex(YYSTYPE *lvalp, Context *context) +{ + angle::pp::Token *token = context->token; + if (!context->parsePresetToken) + { + context->lexer->lex(token); + } + context->parsePresetToken = false; + + int type = 0; + + switch (token->type) + { + case angle::pp::Token::CONST_INT: + { + unsigned int val = 0; + int testVal = 0; + if (!token->uValue(&val) || + (!token->iValue(&testVal) && + context->errorSettings.integerLiteralsMustFit32BitSignedRange)) + { + context->diagnostics->report(angle::pp::Diagnostics::PP_INTEGER_OVERFLOW, + token->location, token->text); + *(context->valid) = false; + } + *lvalp = static_cast<YYSTYPE>(val); + type = TOK_CONST_INT; + break; + } + case angle::pp::Token::IDENTIFIER: + *lvalp = static_cast<YYSTYPE>(-1); + type = TOK_IDENTIFIER; + break; + case angle::pp::Token::OP_OR: + type = TOK_OP_OR; + break; + case angle::pp::Token::OP_AND: + type = TOK_OP_AND; + break; + case angle::pp::Token::OP_NE: + type = TOK_OP_NE; + break; + case angle::pp::Token::OP_EQ: + type = TOK_OP_EQ; + break; + case angle::pp::Token::OP_GE: + type = TOK_OP_GE; + break; + case angle::pp::Token::OP_LE: + type = TOK_OP_LE; + break; + case angle::pp::Token::OP_RIGHT: + type = TOK_OP_RIGHT; + break; + case angle::pp::Token::OP_LEFT: + type = TOK_OP_LEFT; + break; + case '|': + case '^': + case '&': + case '>': + case '<': + case '-': + case '+': + case '%': + case '/': + case '*': + case '!': + case '~': + case '(': + case ')': + type = token->type; + break; + + default: + break; + } + + return type; +} + +void yyerror(Context *context, const char *reason) +{ + context->diagnostics->report(angle::pp::Diagnostics::PP_INVALID_EXPRESSION, + context->token->location, reason); +} + +namespace angle +{ + +namespace pp +{ + +ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics) + : mLexer(lexer), mDiagnostics(diagnostics) +{} + +bool ExpressionParser::parse(Token *token, + int *result, + bool parsePresetToken, + const ErrorSettings &errorSettings, + bool *valid) +{ + Context context; + context.diagnostics = mDiagnostics; + context.lexer = mLexer; + context.token = token; + context.result = result; + context.ignoreErrors = 0; + context.parsePresetToken = parsePresetToken; + context.errorSettings = errorSettings; + context.valid = valid; + int ret = yyparse(&context); + switch (ret) + { + case 0: + case 1: + break; + + case 2: + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, ""); + break; + + default: + assert(false); + mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, ""); + break; + } + + return ret == 0; +} + +} // namespace pp + +} // namespace angle |