Commit e13238e0 by Alexis Hetu Committed by Alexis Hétu

Preprocessor update from ANGLE

- Updated preprocessor code from Angle revision 9fc8733187c02470a9eadb6d295348b6d37a2004 - Reran generate_parser.sh (flex 2.6.4, bison (GNU Bison) 3.0.4) - Made a few trivial changes in src/OpenGL/compiler in order to adapt to the new preprocessor code. Fixes all 24 failures in: dEQP-GLES3.functional.shaders.preprocessor.* Change-Id: I00d0b511d617ab81a0f57310174e1ba8bf7c22e5 Reviewed-on: https://swiftshader-review.googlesource.com/15109Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent f46493fe
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#ifndef COMPILER_DIAGNOSTICS_H_ #ifndef COMPILER_DIAGNOSTICS_H_
#define COMPILER_DIAGNOSTICS_H_ #define COMPILER_DIAGNOSTICS_H_
#include "preprocessor/Diagnostics.h" #include "preprocessor/DiagnosticsBase.h"
class TInfoSink; class TInfoSink;
......
...@@ -54,7 +54,8 @@ void TDirectiveHandler::handleError(const pp::SourceLocation& loc, ...@@ -54,7 +54,8 @@ void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
const std::string& name, const std::string& name,
const std::string& value) const std::string& value,
bool stdgl)
{ {
static const std::string kSTDGL("STDGL"); static const std::string kSTDGL("STDGL");
static const std::string kOptimize("optimize"); static const std::string kOptimize("optimize");
...@@ -63,7 +64,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, ...@@ -63,7 +64,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
static const std::string kOff("off"); static const std::string kOff("off");
bool invalidValue = false; bool invalidValue = false;
if (name == kSTDGL) if (stdgl || (name == kSTDGL))
{ {
// The STDGL pragma is used to reserve pragmas for use by future // The STDGL pragma is used to reserve pragmas for use by future
// revisions of GLSL. Ignore it. // revisions of GLSL. Ignore it.
...@@ -83,7 +84,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, ...@@ -83,7 +84,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
} }
else else
{ {
mDiagnostics.report(pp::Diagnostics::UNRECOGNIZED_PRAGMA, loc, name); mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
return; return;
} }
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include "ExtensionBehavior.h" #include "ExtensionBehavior.h"
#include "Pragma.h" #include "Pragma.h"
#include "preprocessor/DirectiveHandler.h" #include "preprocessor/DirectiveHandlerBase.h"
class TDiagnostics; class TDiagnostics;
...@@ -37,7 +37,8 @@ public: ...@@ -37,7 +37,8 @@ public:
virtual void handlePragma(const pp::SourceLocation& loc, virtual void handlePragma(const pp::SourceLocation& loc,
const std::string& name, const std::string& name,
const std::string& value); const std::string& value,
bool stdgl);
virtual void handleExtension(const pp::SourceLocation& loc, virtual void handleExtension(const pp::SourceLocation& loc,
const std::string& name, const std::string& name,
......
...@@ -1122,10 +1122,10 @@ void TParseContext::handleExtensionDirective(const TSourceLoc &line, const char* ...@@ -1122,10 +1122,10 @@ void TParseContext::handleExtensionDirective(const TSourceLoc &line, const char*
mDirectiveHandler.handleExtension(loc, extName, behavior); mDirectiveHandler.handleExtension(loc, extName, behavior);
} }
void TParseContext::handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value) void TParseContext::handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value, bool stdgl)
{ {
pp::SourceLocation loc(line.first_file, line.first_line); pp::SourceLocation loc(line.first_file, line.first_line);
mDirectiveHandler.handlePragma(loc, name, value); mDirectiveHandler.handlePragma(loc, name, value, stdgl);
} }
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
mDefaultBlockStorage(EbsShared), mDefaultBlockStorage(EbsShared),
mDiagnostics(is), mDiagnostics(is),
mDirectiveHandler(ext, mDiagnostics, mShaderVersion), mDirectiveHandler(ext, mDiagnostics, mShaderVersion),
mPreprocessor(&mDiagnostics, &mDirectiveHandler), mPreprocessor(&mDiagnostics, &mDirectiveHandler, pp::PreprocessorSettings()),
mScanner(nullptr), mScanner(nullptr),
mUsesFragData(false), mUsesFragData(false),
mUsesFragColor(false) { } mUsesFragColor(false) { }
...@@ -148,7 +148,7 @@ public: ...@@ -148,7 +148,7 @@ public:
void handleExtensionDirective(const TSourceLoc &line, const char* extName, const char* behavior); void handleExtensionDirective(const TSourceLoc &line, const char* extName, const char* behavior);
const TPragma& pragma() const { return mDirectiveHandler.pragma(); } const TPragma& pragma() const { return mDirectiveHandler.pragma(); }
void handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value); void handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value, bool stdgl);
bool containsSampler(TType& type); bool containsSampler(TType& type);
const TFunction* findFunction(const TSourceLoc &line, TFunction* pfnCall, bool *builtIn = 0); const TFunction* findFunction(const TSourceLoc &line, TFunction* pfnCall, bool *builtIn = 0);
......
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
#include <string>
namespace pp
{
struct SourceLocation;
// Base class for reporting diagnostic messages.
// Derived classes are responsible for formatting and printing the messages.
class Diagnostics
{
public:
enum Severity
{
PP_ERROR,
PP_WARNING
};
enum ID
{
ERROR_BEGIN,
INTERNAL_ERROR,
OUT_OF_MEMORY,
INVALID_CHARACTER,
INVALID_NUMBER,
INTEGER_OVERFLOW,
FLOAT_OVERFLOW,
TOKEN_TOO_LONG,
INVALID_EXPRESSION,
DIVISION_BY_ZERO,
EOF_IN_COMMENT,
UNEXPECTED_TOKEN,
DIRECTIVE_INVALID_NAME,
MACRO_NAME_RESERVED,
MACRO_REDEFINED,
MACRO_PREDEFINED_REDEFINED,
MACRO_PREDEFINED_UNDEFINED,
MACRO_UNTERMINATED_INVOCATION,
MACRO_TOO_FEW_ARGS,
MACRO_TOO_MANY_ARGS,
MACRO_DUPLICATE_PARAMETER_NAMES,
CONDITIONAL_ENDIF_WITHOUT_IF,
CONDITIONAL_ELSE_WITHOUT_IF,
CONDITIONAL_ELSE_AFTER_ELSE,
CONDITIONAL_ELIF_WITHOUT_IF,
CONDITIONAL_ELIF_AFTER_ELSE,
CONDITIONAL_UNTERMINATED,
CONDITIONAL_UNEXPECTED_TOKEN,
INVALID_EXTENSION_NAME,
INVALID_EXTENSION_BEHAVIOR,
INVALID_EXTENSION_DIRECTIVE,
INVALID_VERSION_NUMBER,
INVALID_VERSION_DIRECTIVE,
VERSION_NOT_FIRST_STATEMENT,
INVALID_LINE_NUMBER,
INVALID_FILE_NUMBER,
INVALID_LINE_DIRECTIVE,
UNDEFINED_IDENTIFIER,
ERROR_END,
WARNING_BEGIN,
EOF_IN_DIRECTIVE,
UNRECOGNIZED_PRAGMA,
WARNING_END
};
virtual ~Diagnostics();
void report(ID id, const SourceLocation& loc, const std::string& text);
protected:
Severity severity(ID id);
std::string message(ID id);
virtual void print(ID id,
const SourceLocation& loc,
const std::string& text) = 0;
};
} // namespace pp
#endif // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // Copyright 2017 The SwiftShader Authors. All Rights Reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "Diagnostics.h" #include "DiagnosticsBase.h"
#include <cassert> #include <cassert>
...@@ -23,116 +23,140 @@ Diagnostics::~Diagnostics() ...@@ -23,116 +23,140 @@ Diagnostics::~Diagnostics()
{ {
} }
void Diagnostics::report(ID id, void Diagnostics::report(ID id, const SourceLocation &loc, const std::string &text)
const SourceLocation& loc,
const std::string& text)
{ {
// TODO(alokp): Keep a count of errors and warnings.
print(id, loc, 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;
assert(false);
return true;
}
Diagnostics::Severity Diagnostics::severity(ID id) Diagnostics::Severity Diagnostics::severity(ID id)
{ {
if ((id > ERROR_BEGIN) && (id < ERROR_END)) if((id > PP_ERROR_BEGIN) && (id < PP_ERROR_END))
return PP_ERROR; return PP_ERROR;
if ((id > WARNING_BEGIN) && (id < WARNING_END)) if((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END))
return PP_WARNING; return PP_WARNING;
assert(false); assert(false);
return PP_ERROR; return PP_ERROR;
} }
std::string Diagnostics::message(ID id) const char *Diagnostics::message(ID id)
{ {
switch (id) switch (id)
{ {
// Errors begin. // Errors begin.
case INTERNAL_ERROR: case PP_INTERNAL_ERROR:
return "internal error"; return "internal error";
case OUT_OF_MEMORY: case PP_OUT_OF_MEMORY:
return "out of memory"; return "out of memory";
case INVALID_CHARACTER: case PP_INVALID_CHARACTER:
return "invalid character"; return "invalid character";
case INVALID_NUMBER: case PP_INVALID_NUMBER:
return "invalid number"; return "invalid number";
case INTEGER_OVERFLOW: case PP_INTEGER_OVERFLOW:
return "integer overflow"; return "integer overflow";
case FLOAT_OVERFLOW: case PP_FLOAT_OVERFLOW:
return "float overflow"; return "float overflow";
case TOKEN_TOO_LONG: case PP_TOKEN_TOO_LONG:
return "token too long"; return "token too long";
case INVALID_EXPRESSION: case PP_INVALID_EXPRESSION:
return "invalid expression"; return "invalid expression";
case DIVISION_BY_ZERO: case PP_DIVISION_BY_ZERO:
return "division by zero"; return "division by zero";
case EOF_IN_COMMENT: case PP_EOF_IN_COMMENT:
return "unexpected end of file found in comment"; return "unexpected end of file found in comment";
case UNEXPECTED_TOKEN: case PP_UNEXPECTED_TOKEN:
return "unexpected token"; return "unexpected token";
case DIRECTIVE_INVALID_NAME: case PP_DIRECTIVE_INVALID_NAME:
return "invalid directive name"; return "invalid directive name";
case MACRO_NAME_RESERVED: case PP_MACRO_NAME_RESERVED:
return "macro name is reserved"; return "macro name is reserved";
case MACRO_REDEFINED: case PP_MACRO_REDEFINED:
return "macro redefined"; return "macro redefined";
case MACRO_PREDEFINED_REDEFINED: case PP_MACRO_PREDEFINED_REDEFINED:
return "predefined macro redefined"; return "predefined macro redefined";
case MACRO_PREDEFINED_UNDEFINED: case PP_MACRO_PREDEFINED_UNDEFINED:
return "predefined macro undefined"; return "predefined macro undefined";
case MACRO_UNTERMINATED_INVOCATION: case PP_MACRO_UNTERMINATED_INVOCATION:
return "unterminated macro invocation"; return "unterminated macro invocation";
case MACRO_TOO_FEW_ARGS: case PP_MACRO_UNDEFINED_WHILE_INVOKED:
return "Not enough arguments for macro"; return "macro undefined while being invoked";
case MACRO_TOO_MANY_ARGS: case PP_MACRO_TOO_FEW_ARGS:
return "Too many arguments for macro"; return "Not enough arguments for macro";
case MACRO_DUPLICATE_PARAMETER_NAMES: case PP_MACRO_TOO_MANY_ARGS:
return "duplicate macro parameter name"; return "Too many arguments for macro";
case CONDITIONAL_ENDIF_WITHOUT_IF: case PP_MACRO_DUPLICATE_PARAMETER_NAMES:
return "unexpected #endif found without a matching #if"; return "duplicate macro parameter name";
case CONDITIONAL_ELSE_WITHOUT_IF: case PP_MACRO_INVOCATION_CHAIN_TOO_DEEP:
return "unexpected #else found without a matching #if"; return "macro invocation chain too deep";
case CONDITIONAL_ELSE_AFTER_ELSE: case PP_CONDITIONAL_ENDIF_WITHOUT_IF:
return "unexpected #else found after another #else"; return "unexpected #endif found without a matching #if";
case CONDITIONAL_ELIF_WITHOUT_IF: case PP_CONDITIONAL_ELSE_WITHOUT_IF:
return "unexpected #elif found without a matching #if"; return "unexpected #else found without a matching #if";
case CONDITIONAL_ELIF_AFTER_ELSE: case PP_CONDITIONAL_ELSE_AFTER_ELSE:
return "unexpected #elif found after #else"; return "unexpected #else found after another #else";
case CONDITIONAL_UNTERMINATED: case PP_CONDITIONAL_ELIF_WITHOUT_IF:
return "unexpected end of file found in conditional block"; return "unexpected #elif found without a matching #if";
case INVALID_EXTENSION_NAME: case PP_CONDITIONAL_ELIF_AFTER_ELSE:
return "invalid extension name"; return "unexpected #elif found after #else";
case INVALID_EXTENSION_BEHAVIOR: case PP_CONDITIONAL_UNTERMINATED:
return "invalid extension behavior"; return "unexpected end of file found in conditional block";
case INVALID_EXTENSION_DIRECTIVE: case PP_INVALID_EXTENSION_NAME:
return "invalid extension directive"; return "invalid extension name";
case INVALID_VERSION_NUMBER: case PP_INVALID_EXTENSION_BEHAVIOR:
return "invalid version number"; return "invalid extension behavior";
case INVALID_VERSION_DIRECTIVE: case PP_INVALID_EXTENSION_DIRECTIVE:
return "invalid version directive"; return "invalid extension directive";
case VERSION_NOT_FIRST_STATEMENT: 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, " return "#version directive must occur before anything else, "
"except for comments and white space"; "except for comments and white space";
case INVALID_LINE_NUMBER: case PP_VERSION_NOT_FIRST_LINE_ESSL3:
return "invalid line number"; return "#version directive must occur on the first line of the shader";
case INVALID_FILE_NUMBER: case PP_INVALID_LINE_NUMBER:
return "invalid file number"; return "invalid line number";
case INVALID_LINE_DIRECTIVE: case PP_INVALID_FILE_NUMBER:
return "invalid line directive"; return "invalid file number";
case UNDEFINED_IDENTIFIER: case PP_INVALID_LINE_DIRECTIVE:
return "undefined identifier"; return "invalid line directive";
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. // Errors end.
// Warnings begin. // Warnings begin.
case EOF_IN_DIRECTIVE: case PP_EOF_IN_DIRECTIVE:
return "unexpected end of file found in directive"; return "unexpected end of file found in directive";
case CONDITIONAL_UNEXPECTED_TOKEN: case PP_CONDITIONAL_UNEXPECTED_TOKEN:
return "unexpected token after conditional expression"; return "unexpected token after conditional expression";
case UNRECOGNIZED_PRAGMA: case PP_UNRECOGNIZED_PRAGMA:
return "unrecognized pragma"; return "unrecognized pragma";
case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1:
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. // Warnings end.
default: default:
assert(false); assert(false);
return ""; return "";
} }
} }
......
// Copyright 2017 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
#define COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
#include <string>
namespace pp
{
struct SourceLocation;
// Base class for reporting diagnostic messages.
// Derived classes are responsible for formatting and printing the messages.
class Diagnostics
{
public:
// Severity is used to classify info log messages.
enum Severity
{
PP_WARNING,
PP_ERROR
};
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,
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,
PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
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);
Severity severity(ID id);
virtual void print(ID id, const SourceLocation &loc, const std::string &text) = 0;
};
} // namespace pp
#endif // COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_
// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // Copyright 2017 The SwiftShader Authors. All Rights Reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "DirectiveHandler.h" #include "DirectiveHandlerBase.h"
namespace pp namespace pp
{ {
......
// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // Copyright 2017 The SwiftShader Authors. All Rights Reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ #ifndef COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ #define COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
#include <string> #include <string>
...@@ -28,24 +28,24 @@ struct SourceLocation; ...@@ -28,24 +28,24 @@ struct SourceLocation;
// handling them in an appropriate manner. // handling them in an appropriate manner.
class DirectiveHandler class DirectiveHandler
{ {
public: public:
virtual ~DirectiveHandler(); virtual ~DirectiveHandler();
virtual void handleError(const SourceLocation& loc, virtual void handleError(const SourceLocation &loc, const std::string &msg) = 0;
const std::string& msg) = 0;
// Handle pragma of form: #pragma name[(value)] // Handle pragma of form: #pragma name[(value)]
virtual void handlePragma(const SourceLocation& loc, virtual void handlePragma(const SourceLocation &loc,
const std::string& name, const std::string &name,
const std::string& value) = 0; const std::string &value,
bool stdgl) = 0;
virtual void handleExtension(const SourceLocation& loc, virtual void handleExtension(const SourceLocation &loc,
const std::string& name, const std::string &name,
const std::string& behavior) = 0; const std::string &behavior) = 0;
virtual void handleVersion(const SourceLocation& loc, virtual void handleVersion(const SourceLocation &loc, int version) = 0;
int version) = 0;
}; };
} // namespace pp } // namespace pp
#endif // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
#endif // COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_
...@@ -30,35 +30,37 @@ class Tokenizer; ...@@ -30,35 +30,37 @@ class Tokenizer;
class DirectiveParser : public Lexer class DirectiveParser : public Lexer
{ {
public: public:
DirectiveParser(Tokenizer* tokenizer, DirectiveParser(Tokenizer *tokenizer,
MacroSet* macroSet, MacroSet *macroSet,
Diagnostics* diagnostics, Diagnostics *diagnostics,
DirectiveHandler* directiveHandler); DirectiveHandler *directiveHandler,
int maxMacroExpansionDepth);
~DirectiveParser() override;
virtual void lex(Token* token); void lex(Token *token) override;
private: private:
PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser); PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser);
void parseDirective(Token* token); void parseDirective(Token *token);
void parseDefine(Token* token); void parseDefine(Token *token);
void parseUndef(Token* token); void parseUndef(Token *token);
void parseIf(Token* token); void parseIf(Token *token);
void parseIfdef(Token* token); void parseIfdef(Token *token);
void parseIfndef(Token* token); void parseIfndef(Token *token);
void parseElse(Token* token); void parseElse(Token *token);
void parseElif(Token* token); void parseElif(Token *token);
void parseEndif(Token* token); void parseEndif(Token *token);
void parseError(Token* token); void parseError(Token *token);
void parsePragma(Token* token); void parsePragma(Token *token);
void parseExtension(Token* token); void parseExtension(Token *token);
void parseVersion(Token* token); void parseVersion(Token *token);
void parseLine(Token* token); void parseLine(Token *token);
bool skipping() const; bool skipping() const;
void parseConditionalIf(Token* token); void parseConditionalIf(Token *token);
int parseExpressionIf(Token* token); int parseExpressionIf(Token *token);
int parseExpressionIfdef(Token* token); int parseExpressionIfdef(Token *token);
struct ConditionalBlock struct ConditionalBlock
{ {
...@@ -78,11 +80,16 @@ private: ...@@ -78,11 +80,16 @@ private:
} }
}; };
bool mPastFirstStatement; 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; std::vector<ConditionalBlock> mConditionalStack;
Tokenizer* mTokenizer; Tokenizer *mTokenizer;
MacroSet* mMacroSet; MacroSet *mMacroSet;
Diagnostics* mDiagnostics; Diagnostics *mDiagnostics;
DirectiveHandler* mDirectiveHandler; DirectiveHandler *mDirectiveHandler;
int mShaderVersion;
int mMaxMacroExpansionDepth;
}; };
} // namespace pp } // namespace pp
......
...@@ -15,27 +15,34 @@ ...@@ -15,27 +15,34 @@
#ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ #ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
#define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ #define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
#include "pp_utils.h" #include "DiagnosticsBase.h"
namespace pp namespace pp
{ {
class Diagnostics;
class Lexer; class Lexer;
struct Token; struct Token;
class ExpressionParser class ExpressionParser
{ {
public: public:
ExpressionParser(Lexer* lexer, Diagnostics* diagnostics); struct ErrorSettings
{
Diagnostics::ID unexpectedIdentifier;
bool integerLiteralsMustFit32BitSignedRange;
};
bool parse(Token* token, int* result); ExpressionParser(Lexer *lexer, Diagnostics *diagnostics);
private: bool parse(Token *token,
PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser); int *result,
bool parsePresetToken,
const ErrorSettings &errorSettings,
bool *valid);
Lexer* mLexer; private:
Diagnostics* mDiagnostics; Lexer *mLexer;
Diagnostics *mDiagnostics;
}; };
} // namespace pp } // namespace pp
......
...@@ -25,27 +25,101 @@ Input::Input() : mCount(0), mString(0) ...@@ -25,27 +25,101 @@ Input::Input() : mCount(0), mString(0)
{ {
} }
Input::Input(int count, const char* const string[], const int length[]) : Input::~Input()
mCount(count), {
mString(string) }
Input::Input(size_t count, const char *const string[], const int length[])
: mCount(count), mString(string)
{ {
assert(mCount >= 0);
mLength.reserve(mCount); mLength.reserve(mCount);
for (int i = 0; i < mCount; ++i) for (size_t i = 0; i < mCount; ++i)
{ {
int len = length ? length[i] : -1; int len = length ? length[i] : -1;
mLength.push_back(len < 0 ? strlen(mString[i]) : len); mLength.push_back(len < 0 ? std::strlen(mString[i]) : len);
} }
} }
int Input::read(char* buf, int maxSize) const char *Input::skipChar()
{ {
int nRead = 0; // This function should only be called when there is a character to skip.
while ((nRead < maxSize) && (mReadLoc.sIndex < mCount)) assert(mReadLoc.cIndex < mLength[mReadLoc.sIndex]);
++mReadLoc.cIndex;
if (mReadLoc.cIndex == mLength[mReadLoc.sIndex])
{
++mReadLoc.sIndex;
mReadLoc.cIndex = 0;
}
if (mReadLoc.sIndex >= mCount)
{ {
int size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex; return nullptr;
size = std::min(size, maxSize); }
memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size); 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; nRead += size;
mReadLoc.cIndex += size; mReadLoc.cIndex += size;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#ifndef COMPILER_PREPROCESSOR_INPUT_H_ #ifndef COMPILER_PREPROCESSOR_INPUT_H_
#define COMPILER_PREPROCESSOR_INPUT_H_ #define COMPILER_PREPROCESSOR_INPUT_H_
#include <cstddef>
#include <vector> #include <vector>
namespace pp namespace pp
...@@ -25,28 +26,33 @@ class Input ...@@ -25,28 +26,33 @@ class Input
{ {
public: public:
Input(); Input();
Input(int count, const char* const string[], const int length[]); ~Input();
Input(size_t count, const char *const string[], const int length[]);
int count() const { return mCount; } size_t count() const { return mCount; }
const char* string(int index) const { return mString[index]; } const char *string(size_t index) const { return mString[index]; }
int length(int index) const { return mLength[index]; } size_t length(size_t index) const { return mLength[index]; }
int read(char* buf, int maxSize); size_t read(char *buf, size_t maxSize, int *lineNo);
struct Location struct Location
{ {
int sIndex; // String index; size_t sIndex; // String index;
int cIndex; // Char index. size_t cIndex; // Char index.
Location() : sIndex(0), cIndex(0) { } Location() : sIndex(0), cIndex(0) {}
}; };
const Location& readLoc() const { return mReadLoc; } const Location &readLoc() const { return mReadLoc; }
private: 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. // Input.
int mCount; size_t mCount;
const char* const* mString; const char *const *mString;
std::vector<int> mLength; std::vector<size_t> mLength;
Location mReadLoc; Location mReadLoc;
}; };
......
...@@ -25,7 +25,7 @@ class Lexer ...@@ -25,7 +25,7 @@ class Lexer
public: public:
virtual ~Lexer(); virtual ~Lexer();
virtual void lex(Token* token) = 0; virtual void lex(Token *token) = 0;
}; };
} // namespace pp } // namespace pp
......
...@@ -19,12 +19,33 @@ ...@@ -19,12 +19,33 @@
namespace pp namespace pp
{ {
bool Macro::equals(const Macro& other) const Macro::Macro() : predefined(false), disabled(false), expansionCount(0), type(kTypeObj)
{ {
return (type == other.type) && }
(name == other.name) &&
(parameters == other.parameters) && Macro::~Macro()
(replacements == other.replacements); {
}
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 = std::to_string(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 pp
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define COMPILER_PREPROCESSOR_MACRO_H_ #define COMPILER_PREPROCESSOR_MACRO_H_
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -34,11 +35,13 @@ struct Macro ...@@ -34,11 +35,13 @@ struct Macro
typedef std::vector<std::string> Parameters; typedef std::vector<std::string> Parameters;
typedef std::vector<Token> Replacements; typedef std::vector<Token> Replacements;
Macro() : predefined(false), disabled(false), type(kTypeObj) { } Macro();
bool equals(const Macro& other) const; ~Macro();
bool equals(const Macro &other) const;
bool predefined; bool predefined;
mutable bool disabled; mutable bool disabled;
mutable int expansionCount;
Type type; Type type;
std::string name; std::string name;
...@@ -46,7 +49,9 @@ struct Macro ...@@ -46,7 +49,9 @@ struct Macro
Replacements replacements; Replacements replacements;
}; };
typedef std::map<std::string, Macro> MacroSet; typedef std::map<std::string, std::shared_ptr<Macro>> MacroSet;
void PredefineMacro(MacroSet *macroSet, const char *name, int value);
} // namespace pp } // namespace pp
#endif // COMPILER_PREPROCESSOR_MACRO_H_ #endif // COMPILER_PREPROCESSOR_MACRO_H_
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ #ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ #define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
#include <cassert>
#include <memory> #include <memory>
#include <vector> #include <vector>
...@@ -27,58 +26,67 @@ namespace pp ...@@ -27,58 +26,67 @@ namespace pp
{ {
class Diagnostics; class Diagnostics;
struct SourceLocation;
class MacroExpander : public Lexer class MacroExpander : public Lexer
{ {
public: public:
MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics, bool parseDefined); MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics, bool parseDefined, int allowedMacroExpansionDepth);
virtual ~MacroExpander(); ~MacroExpander() override;
virtual void lex(Token* token); void lex(Token *token) override;
private: private:
PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander); PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
void getToken(Token* token); void getToken(Token *token);
void ungetToken(const Token& token); void ungetToken(const Token &token);
bool isNextTokenLeftParen(); bool isNextTokenLeftParen();
bool pushMacro(const Macro& macro, const Token& identifier); bool pushMacro(std::shared_ptr<Macro> macro, const Token &identifier);
void popMacro(); void popMacro();
bool expandMacro(const Macro& macro, bool expandMacro(const Macro &macro, const Token &identifier, std::vector<Token> *replacements);
const Token& identifier,
std::vector<Token>* replacements);
typedef std::vector<Token> MacroArg; typedef std::vector<Token> MacroArg;
bool collectMacroArgs(const Macro& macro, bool collectMacroArgs(const Macro &macro,
const Token& identifier, const Token &identifier,
std::vector<MacroArg>* args); std::vector<MacroArg> *args,
void replaceMacroParams(const Macro& macro, SourceLocation *closingParenthesisLocation);
const std::vector<MacroArg>& args, void replaceMacroParams(const Macro &macro,
std::vector<Token>* replacements); const std::vector<MacroArg> &args,
std::vector<Token> *replacements);
struct MacroContext struct MacroContext
{ {
const Macro* macro; MacroContext();
size_t index; ~MacroContext();
bool empty() const;
const Token &get();
void unget();
std::shared_ptr<Macro> macro;
std::size_t index;
std::vector<Token> replacements; std::vector<Token> replacements;
MacroContext() : macro(0), index(0) { }
bool empty() const { return index == replacements.size(); }
const Token& get() { return replacements[index++]; }
void unget() { assert(index > 0); --index; }
}; };
Lexer* mLexer; Lexer *mLexer;
MacroSet* mMacroSet; MacroSet *mMacroSet;
Diagnostics* mDiagnostics; Diagnostics *mDiagnostics;
const bool mParseDefined; const bool mParseDefined;
Token* mReserveToken; std::unique_ptr<Token> mReserveToken;
std::vector<MacroContext*> mContextStack; std::vector<MacroContext *> mContextStack;
size_t mTotalTokensInContexts;
int mAllowedMacroExpansionDepth;
bool mDeferReenablingMacros;
std::vector<std::shared_ptr<Macro>> mMacrosToReenable;
class ScopedMacroReenabler;
}; };
} // namespace pp } // namespace pp
#endif // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ #endif // COMPILER_PREPROCESSOR_MACROEXPANDER_H_
...@@ -15,9 +15,8 @@ ...@@ -15,9 +15,8 @@
#include "Preprocessor.h" #include "Preprocessor.h"
#include <cassert> #include <cassert>
#include <sstream>
#include "Diagnostics.h" #include "DiagnosticsBase.h"
#include "DirectiveParser.h" #include "DirectiveParser.h"
#include "Macro.h" #include "Macro.h"
#include "MacroExpander.h" #include "MacroExpander.h"
...@@ -29,25 +28,28 @@ namespace pp ...@@ -29,25 +28,28 @@ namespace pp
struct PreprocessorImpl struct PreprocessorImpl
{ {
Diagnostics* diagnostics; Diagnostics *diagnostics;
MacroSet macroSet; MacroSet macroSet;
Tokenizer tokenizer; Tokenizer tokenizer;
DirectiveParser directiveParser; DirectiveParser directiveParser;
MacroExpander macroExpander; MacroExpander macroExpander;
PreprocessorImpl(Diagnostics* diag, DirectiveHandler* directiveHandler) : PreprocessorImpl(Diagnostics *diag,
diagnostics(diag), DirectiveHandler *directiveHandler,
tokenizer(diag), const PreprocessorSettings &settings)
directiveParser(&tokenizer, &macroSet, diag, directiveHandler), : diagnostics(diag),
macroExpander(&directiveParser, &macroSet, diag, false) tokenizer(diag),
directiveParser(&tokenizer, &macroSet, diag, directiveHandler, settings.maxMacroExpansionDepth),
macroExpander(&directiveParser, &macroSet, diag, false, settings.maxMacroExpansionDepth)
{ {
} }
}; };
Preprocessor::Preprocessor(Diagnostics* diagnostics, Preprocessor::Preprocessor(Diagnostics *diagnostics,
DirectiveHandler* directiveHandler) DirectiveHandler *directiveHandler,
const PreprocessorSettings &settings)
{ {
mImpl = new PreprocessorImpl(diagnostics, directiveHandler); mImpl = new PreprocessorImpl(diagnostics, directiveHandler, settings);
} }
Preprocessor::~Preprocessor() Preprocessor::~Preprocessor()
...@@ -55,40 +57,25 @@ Preprocessor::~Preprocessor() ...@@ -55,40 +57,25 @@ Preprocessor::~Preprocessor()
delete mImpl; delete mImpl;
} }
bool Preprocessor::init(int count, bool Preprocessor::init(size_t count, const char *const string[], const int length[])
const char* const string[],
const int length[])
{ {
static const int kGLSLVersion = 100; static const int kDefaultGLSLVersion = 100;
// Add standard pre-defined macros. // Add standard pre-defined macros.
predefineMacro("__LINE__", 0); predefineMacro("__LINE__", 0);
predefineMacro("__FILE__", 0); predefineMacro("__FILE__", 0);
predefineMacro("__VERSION__", kGLSLVersion); predefineMacro("__VERSION__", kDefaultGLSLVersion);
predefineMacro("GL_ES", 1); predefineMacro("GL_ES", 1);
return mImpl->tokenizer.init(count, string, length); return mImpl->tokenizer.init(count, string, length);
} }
void Preprocessor::predefineMacro(const char* name, int value) void Preprocessor::predefineMacro(const char *name, int value)
{ {
std::ostringstream stream; PredefineMacro(&mImpl->macroSet, name, value);
stream << value;
Token token;
token.type = Token::CONST_INT;
token.text = stream.str();
Macro macro;
macro.predefined = true;
macro.type = Macro::kTypeObj;
macro.name = name;
macro.replacements.push_back(token);
mImpl->macroSet[name] = macro;
} }
void Preprocessor::lex(Token* token) void Preprocessor::lex(Token *token)
{ {
bool validToken = false; bool validToken = false;
while (!validToken) while (!validToken)
...@@ -102,40 +89,12 @@ void Preprocessor::lex(Token* token) ...@@ -102,40 +89,12 @@ void Preprocessor::lex(Token* token)
case Token::PP_HASH: case Token::PP_HASH:
assert(false); assert(false);
break; break;
case Token::CONST_INT:
{
int val = 0;
if (!token->iValue(&val))
{
// Do not mark the token as invalid.
// Just emit the diagnostic and reset value to 0.
mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW,
token->location, token->text);
token->text.assign("0");
}
validToken = true;
break;
}
case Token::CONST_FLOAT:
{
float val = 0;
if (!token->fValue(&val))
{
// Do not mark the token as invalid.
// Just emit the diagnostic and reset value to 0.0.
mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW,
token->location, token->text);
token->text.assign("0.0");
}
validToken = true;
break;
}
case Token::PP_NUMBER: case Token::PP_NUMBER:
mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER, mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER,
token->location, token->text); token->location, token->text);
break; break;
case Token::PP_OTHER: case Token::PP_OTHER:
mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER, mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER,
token->location, token->text); token->location, token->text);
break; break;
default: default:
...@@ -145,5 +104,9 @@ void Preprocessor::lex(Token* token) ...@@ -145,5 +104,9 @@ void Preprocessor::lex(Token* token)
} }
} }
} // namespace pp void Preprocessor::setMaxTokenSize(size_t maxTokenSize)
{
mImpl->tokenizer.setMaxTokenSize(maxTokenSize);
}
} // namespace pp
...@@ -25,10 +25,18 @@ class DirectiveHandler; ...@@ -25,10 +25,18 @@ class DirectiveHandler;
struct PreprocessorImpl; struct PreprocessorImpl;
struct Token; struct Token;
struct PreprocessorSettings
{
PreprocessorSettings() : maxMacroExpansionDepth(1000) {}
int maxMacroExpansionDepth;
};
class Preprocessor class Preprocessor
{ {
public: public:
Preprocessor(Diagnostics* diagnostics, DirectiveHandler* directiveHandler); Preprocessor(Diagnostics *diagnostics,
DirectiveHandler *directiveHandler,
const PreprocessorSettings &settings);
~Preprocessor(); ~Preprocessor();
// count: specifies the number of elements in the string and length arrays. // count: specifies the number of elements in the string and length arrays.
...@@ -40,16 +48,19 @@ public: ...@@ -40,16 +48,19 @@ public:
// Each element in the length array may contain the length of the // 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 // corresponding string or a value less than 0 to indicate that the string
// is null terminated. // is null terminated.
bool init(int count, const char* const string[], const int length[]); bool init(size_t count, const char *const string[], const int length[]);
// Adds a pre-defined macro. // Adds a pre-defined macro.
void predefineMacro(const char* name, int value); void predefineMacro(const char *name, int value);
void lex(Token *token);
void lex(Token* token); // Set maximum preprocessor token size
void setMaxTokenSize(size_t maxTokenSize);
private: private:
PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor); PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor);
PreprocessorImpl* mImpl; PreprocessorImpl *mImpl;
}; };
} // namespace pp } // namespace pp
......
...@@ -20,10 +20,10 @@ namespace pp ...@@ -20,10 +20,10 @@ namespace pp
struct SourceLocation struct SourceLocation
{ {
SourceLocation() : file(0), line(0) { } SourceLocation() : file(0), line(0) {}
SourceLocation(int f, int l) : file(f), line(l) { } SourceLocation(int f, int l) : file(f), line(l) {}
bool equals(const SourceLocation& other) const bool equals(const SourceLocation &other) const
{ {
return (file == other.file) && (line == other.line); return (file == other.file) && (line == other.line);
} }
...@@ -32,12 +32,12 @@ struct SourceLocation ...@@ -32,12 +32,12 @@ struct SourceLocation
int line; int line;
}; };
inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs) inline bool operator==(const SourceLocation &lhs, const SourceLocation &rhs)
{ {
return lhs.equals(rhs); return lhs.equals(rhs);
} }
inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs) inline bool operator!=(const SourceLocation &lhs, const SourceLocation &rhs)
{ {
return !lhs.equals(rhs); return !lhs.equals(rhs);
} }
......
...@@ -29,7 +29,7 @@ void Token::reset() ...@@ -29,7 +29,7 @@ void Token::reset()
text.clear(); text.clear();
} }
bool Token::equals(const Token& other) const bool Token::equals(const Token &other) const
{ {
return (type == other.type) && return (type == other.type) &&
(flags == other.flags) && (flags == other.flags) &&
...@@ -61,25 +61,25 @@ void Token::setExpansionDisabled(bool disable) ...@@ -61,25 +61,25 @@ void Token::setExpansionDisabled(bool disable)
flags &= ~EXPANSION_DISABLED; flags &= ~EXPANSION_DISABLED;
} }
bool Token::iValue(int* value) const bool Token::iValue(int *value) const
{ {
assert(type == CONST_INT); assert(type == CONST_INT);
return numeric_lex_int(text, value); return numeric_lex_int(text, value);
} }
bool Token::uValue(unsigned int* value) const bool Token::uValue(unsigned int *value) const
{ {
assert(type == CONST_INT); assert(type == CONST_INT);
return numeric_lex_int(text, value); return numeric_lex_int(text, value);
} }
bool Token::fValue(float* value) const bool Token::fValue(float *value) const
{ {
assert(type == CONST_FLOAT); assert(type == CONST_FLOAT);
return numeric_lex_float(text, value); return numeric_lex_float(text, value);
} }
std::ostream& operator<<(std::ostream& out, const Token& token) std::ostream &operator<<(std::ostream &out, const Token &token)
{ {
if (token.hasLeadingSpace()) if (token.hasLeadingSpace())
out << " "; out << " ";
......
...@@ -27,6 +27,8 @@ struct Token ...@@ -27,6 +27,8 @@ struct Token
{ {
enum Type enum Type
{ {
// Calling this ERROR causes a conflict with wingdi.h
GOT_ERROR = -1,
LAST = 0, // EOF. LAST = 0, // EOF.
IDENTIFIER = 258, IDENTIFIER = 258,
...@@ -70,10 +72,10 @@ struct Token ...@@ -70,10 +72,10 @@ struct Token
EXPANSION_DISABLED = 1 << 2 EXPANSION_DISABLED = 1 << 2
}; };
Token() : type(0), flags(0) { } Token() : type(0), flags(0) {}
void reset(); void reset();
bool equals(const Token& other) const; bool equals(const Token &other) const;
// Returns true if this is the first token on line. // Returns true if this is the first token on line.
// It disregards any leading whitespace. // It disregards any leading whitespace.
...@@ -88,9 +90,9 @@ struct Token ...@@ -88,9 +90,9 @@ struct Token
// Converts text into numeric value for CONST_INT and CONST_FLOAT token. // 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. // Returns false if the parsed value cannot fit into an int or float.
bool iValue(int* value) const; bool iValue(int *value) const;
bool uValue(unsigned int* value) const; bool uValue(unsigned int *value) const;
bool fValue(float* value) const; bool fValue(float *value) const;
int type; int type;
unsigned int flags; unsigned int flags;
...@@ -98,17 +100,17 @@ struct Token ...@@ -98,17 +100,17 @@ struct Token
std::string text; std::string text;
}; };
inline bool operator==(const Token& lhs, const Token& rhs) inline bool operator==(const Token &lhs, const Token &rhs)
{ {
return lhs.equals(rhs); return lhs.equals(rhs);
} }
inline bool operator!=(const Token& lhs, const Token& rhs) inline bool operator!=(const Token &lhs, const Token &rhs)
{ {
return !lhs.equals(rhs); return !lhs.equals(rhs);
} }
extern std::ostream& operator<<(std::ostream& out, const Token& token); std::ostream &operator<<(std::ostream &out, const Token &token);
} // namepsace pp } // namepsace pp
#endif // COMPILER_PREPROCESSOR_TOKEN_H_ #endif // COMPILER_PREPROCESSOR_TOKEN_H_
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#include "Lexer.h" #include "Lexer.h"
#include "pp_utils.h" #include "pp_utils.h"
#include <algorithm>
namespace pp namespace pp
{ {
...@@ -31,7 +29,7 @@ class Tokenizer : public Lexer ...@@ -31,7 +29,7 @@ class Tokenizer : public Lexer
public: public:
struct Context struct Context
{ {
Diagnostics* diagnostics; Diagnostics *diagnostics;
Input input; Input input;
// The location where yytext points to. Token location should track // The location where yytext points to. Token location should track
...@@ -42,25 +40,26 @@ public: ...@@ -42,25 +40,26 @@ public:
bool leadingSpace; bool leadingSpace;
bool lineStart; bool lineStart;
}; };
static const size_t kMaxTokenLength;
Tokenizer(Diagnostics* diagnostics); Tokenizer(Diagnostics *diagnostics);
~Tokenizer(); ~Tokenizer() override;
bool init(int count, const char* const string[], const int length[]); bool init(size_t count, const char *const string[], const int length[]);
void setFileNumber(int file); void setFileNumber(int file);
void setLineNumber(int line); void setLineNumber(int line);
void setMaxTokenSize(size_t maxTokenSize);
virtual void lex(Token* token); void lex(Token *token) override;
private: private:
PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer); PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer);
bool initScanner(); bool initScanner();
void destroyScanner(); void destroyScanner();
void* mHandle; // Scanner handle. void *mHandle; // Scanner handle.
Context mContext; // Scanner extra. Context mContext; // Scanner extra.
size_t mMaxTokenSize; // Maximum token size
}; };
} // namespace pp } // namespace pp
......
...@@ -39,14 +39,27 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh. ...@@ -39,14 +39,27 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
} }
%{ %{
#if defined(_MSC_VER)
#pragma warning(disable: 4005)
#endif
#include "Tokenizer.h" #include "Tokenizer.h"
#include "Diagnostics.h" #include "DiagnosticsBase.h"
#include "Token.h" #include "Token.h"
#if defined(__GNUC__) #if defined(__GNUC__)
// Triggered by the auto-generated yy_fatal_error function. // Triggered by the auto-generated yy_fatal_error function.
#pragma GCC diagnostic ignored "-Wmissing-noreturn" #pragma GCC diagnostic ignored "-Wmissing-noreturn"
#elif defined(_MSC_VER)
#pragma warning(disable: 4244)
#endif
// Workaround for flex using the register keyword, deprecated in C++11.
#ifdef __cplusplus
#if __cplusplus > 199711L
#define register
#endif
#endif #endif
typedef std::string YYSTYPE; typedef std::string YYSTYPE;
...@@ -80,7 +93,7 @@ typedef pp::SourceLocation YYLTYPE; ...@@ -80,7 +93,7 @@ typedef pp::SourceLocation YYLTYPE;
} while(0); } while(0);
#define YY_INPUT(buf, result, maxSize) \ #define YY_INPUT(buf, result, maxSize) \
result = yyextra->input.read(buf, maxSize); result = yyextra->input.read(buf, maxSize, &yylineno);
%} %}
...@@ -109,11 +122,18 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") ...@@ -109,11 +122,18 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
/* Block comment */ /* Block comment */
/* Line breaks are just counted - not returned. */ /* Line breaks are just counted - not returned. */
/* The comment is replaced by a single space. */ /* The comment is replaced by a single space. */
"/*" { BEGIN(COMMENT); } "/*" { BEGIN(COMMENT); }
<COMMENT>[^*\r\n]+ <COMMENT>[^*\r\n]+
<COMMENT>"*" <COMMENT>"*"
<COMMENT>{NEWLINE} { ++yylineno; } <COMMENT>{NEWLINE} {
if (yylineno == INT_MAX)
{
*yylval = "Integer overflow on line number";
return pp::Token::GOT_ERROR;
}
++yylineno;
}
<COMMENT>"*/" { <COMMENT>"*/" {
yyextra->leadingSpace = true; yyextra->leadingSpace = true;
BEGIN(INITIAL); BEGIN(INITIAL);
...@@ -240,13 +260,16 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") ...@@ -240,13 +260,16 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
[ \t\v\f]+ { yyextra->leadingSpace = true; } [ \t\v\f]+ { yyextra->leadingSpace = true; }
{NEWLINE} { {NEWLINE} {
if (yylineno == INT_MAX)
{
*yylval = "Integer overflow on line number";
return pp::Token::GOT_ERROR;
}
++yylineno; ++yylineno;
yylval->assign(1, '\n'); yylval->assign(1, '\n');
return '\n'; return '\n';
} }
\\{NEWLINE} { ++yylineno; }
. { . {
yylval->assign(1, yytext[0]); yylval->assign(1, yytext[0]);
return pp::Token::PP_OTHER; return pp::Token::PP_OTHER;
...@@ -257,23 +280,30 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") ...@@ -257,23 +280,30 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
// Set the location for EOF token manually. // Set the location for EOF token manually.
pp::Input* input = &yyextra->input; pp::Input* input = &yyextra->input;
pp::Input::Location* scanLoc = &yyextra->scanLoc; pp::Input::Location* scanLoc = &yyextra->scanLoc;
int sIndexMax = std::max(0, input->count() - 1); yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0;
if (scanLoc->sIndex != sIndexMax) if (scanLoc->sIndex != sIndexMax)
{ {
// We can only reach here if there are empty strings at the // We can only reach here if there are empty strings at the
// end of the input. // end of the input.
scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0; scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
yyfileno = sIndexMax; yylineno = 1; // FIXME: this is not 64-bit clean.
yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
} }
yylloc->file = yyfileno; yylloc->file = yyfileno;
yylloc->line = yylineno; yylloc->line = yylineno;
yylval->clear(); yylval->clear();
if (YY_START == COMMENT) // Line number overflows fake EOFs to exit early, check for this case.
if (yylineno == INT_MAX) {
yyextra->diagnostics->report(pp::Diagnostics::PP_TOKENIZER_ERROR,
pp::SourceLocation(yyfileno, yylineno),
"Integer overflow on line number");
}
else if (YY_START == COMMENT)
{ {
yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT, yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT,
pp::SourceLocation(yyfileno, yylineno), pp::SourceLocation(yyfileno, yylineno),
""); "EOF while in a comment");
} }
yyterminate(); yyterminate();
} }
...@@ -282,11 +312,7 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") ...@@ -282,11 +312,7 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
namespace pp { namespace pp {
// TODO(alokp): Maximum token length should ideally be specified by Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(1024)
// the preprocessor client, i.e., the compiler.
const size_t Tokenizer::kMaxTokenLength = 1024;
Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0)
{ {
mContext.diagnostics = diagnostics; mContext.diagnostics = diagnostics;
} }
...@@ -296,10 +322,10 @@ Tokenizer::~Tokenizer() ...@@ -296,10 +322,10 @@ Tokenizer::~Tokenizer()
destroyScanner(); destroyScanner();
} }
bool Tokenizer::init(int count, const char* const string[], const int length[]) bool Tokenizer::init(size_t count, const char * const string[], const int length[])
{ {
if (count < 0) return false; if ((count > 0) && (string == 0))
if ((count > 0) && (string == 0)) return false; return false;
mContext.input = Input(count, string, length); mContext.input = Input(count, string, length);
return initScanner(); return initScanner();
...@@ -317,14 +343,30 @@ void Tokenizer::setLineNumber(int line) ...@@ -317,14 +343,30 @@ void Tokenizer::setLineNumber(int line)
yyset_lineno(line, mHandle); yyset_lineno(line, mHandle);
} }
void Tokenizer::lex(Token* token) void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
{
mMaxTokenSize = maxTokenSize;
}
void Tokenizer::lex(Token *token)
{ {
token->type = yylex(&token->text, &token->location, mHandle); int tokenType = yylex(&token->text, &token->location, mHandle);
if (token->text.size() > kMaxTokenLength)
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::TOKEN_TOO_LONG, mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
token->location, token->text); token->location, token->text);
token->text.erase(kMaxTokenLength); token->text.erase(mMaxTokenSize);
} }
token->flags = 0; token->flags = 0;
...@@ -338,7 +380,7 @@ void Tokenizer::lex(Token* token) ...@@ -338,7 +380,7 @@ void Tokenizer::lex(Token* token)
bool Tokenizer::initScanner() bool Tokenizer::initScanner()
{ {
if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle)) if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
return false; return false;
yyrestart(0, mHandle); yyrestart(0, mHandle);
...@@ -347,11 +389,11 @@ bool Tokenizer::initScanner() ...@@ -347,11 +389,11 @@ bool Tokenizer::initScanner()
void Tokenizer::destroyScanner() void Tokenizer::destroyScanner()
{ {
if (mHandle == NULL) if (mHandle == nullptr)
return; return;
yylex_destroy(mHandle); yylex_destroy(mHandle);
mHandle = NULL; mHandle = nullptr;
} }
} // namespace pp } // namespace pp
......
...@@ -62,7 +62,7 @@ bool numeric_lex_float(const std::string& str, FloatType* value) ...@@ -62,7 +62,7 @@ bool numeric_lex_float(const std::string& str, FloatType* value)
stream.imbue(std::locale::classic()); stream.imbue(std::locale::classic());
stream >> (*value); stream >> (*value);
return !stream.fail(); return !stream.fail() && std::isfinite(*value);
} }
} // namespace pp. } // namespace pp.
......
...@@ -143,8 +143,8 @@ ...@@ -143,8 +143,8 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Diagnostics.h" /> <ClInclude Include="DiagnosticsBase.h" />
<ClInclude Include="DirectiveHandler.h" /> <ClInclude Include="DirectiveHandlerBase.h" />
<ClInclude Include="DirectiveParser.h" /> <ClInclude Include="DirectiveParser.h" />
<ClInclude Include="ExpressionParser.h" /> <ClInclude Include="ExpressionParser.h" />
<ClInclude Include="Input.h" /> <ClInclude Include="Input.h" />
...@@ -160,8 +160,8 @@ ...@@ -160,8 +160,8 @@
<ClInclude Include="Tokenizer.h" /> <ClInclude Include="Tokenizer.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Diagnostics.cpp" /> <ClCompile Include="DiagnosticsBase.cpp" />
<ClCompile Include="DirectiveHandler.cpp" /> <ClCompile Include="DirectiveHandlerBase.cpp" />
<ClCompile Include="DirectiveParser.cpp" /> <ClCompile Include="DirectiveParser.cpp" />
<ClCompile Include="ExpressionParser.cpp" /> <ClCompile Include="ExpressionParser.cpp" />
<ClCompile Include="Input.cpp" /> <ClCompile Include="Input.cpp" />
......
...@@ -15,12 +15,6 @@ ...@@ -15,12 +15,6 @@
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Diagnostics.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DirectiveHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DirectiveParser.h"> <ClInclude Include="DirectiveParser.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
...@@ -60,14 +54,14 @@ ...@@ -60,14 +54,14 @@
<ClInclude Include="Tokenizer.h"> <ClInclude Include="Tokenizer.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="DiagnosticsBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DirectiveHandlerBase.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Diagnostics.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DirectiveHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DirectiveParser.cpp"> <ClCompile Include="DirectiveParser.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
...@@ -95,9 +89,15 @@ ...@@ -95,9 +89,15 @@
<ClCompile Include="Tokenizer.cpp"> <ClCompile Include="Tokenizer.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="DiagnosticsBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DirectiveHandlerBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Tokenizer.l" /> <None Include="Tokenizer.l" />
<None Include="ExpressionParser.y" /> <None Include="ExpressionParser.y" />
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment