Commit 98d04ec8 by alokp@chromium.org

Implemented #define and #undef directives.

Review URL: https://codereview.appspot.com/6215072 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1092 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 0eb51ac3
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
'compiler/preprocessor/new/Input.h', 'compiler/preprocessor/new/Input.h',
'compiler/preprocessor/new/Lexer.cpp', 'compiler/preprocessor/new/Lexer.cpp',
'compiler/preprocessor/new/Lexer.h', 'compiler/preprocessor/new/Lexer.h',
'compiler/preprocessor/new/Macro.cpp',
'compiler/preprocessor/new/Macro.h',
'compiler/preprocessor/new/MacroExpander.cpp', 'compiler/preprocessor/new/MacroExpander.cpp',
'compiler/preprocessor/new/MacroExpander.h', 'compiler/preprocessor/new/MacroExpander.h',
'compiler/preprocessor/new/Preprocessor.cpp', 'compiler/preprocessor/new/Preprocessor.cpp',
......
...@@ -26,12 +26,13 @@ class Diagnostics ...@@ -26,12 +26,13 @@ class Diagnostics
OUT_OF_MEMORY, OUT_OF_MEMORY,
INVALID_CHARACTER, INVALID_CHARACTER,
INVALID_NUMBER, INVALID_NUMBER,
INVALID_DIRECTIVE,
INVALID_EXPRESSION, INVALID_EXPRESSION,
DIVISION_BY_ZERO, DIVISION_BY_ZERO,
EOF_IN_COMMENT, EOF_IN_COMMENT,
EOF_IN_DIRECTIVE, EOF_IN_DIRECTIVE,
UNEXPECTED_TOKEN_IN_DIRECTIVE, UNEXPECTED_TOKEN_IN_DIRECTIVE,
MACRO_NAME_RESERVED,
MACRO_REDEFINED,
ERROR_END, ERROR_END,
WARNING_BEGIN, WARNING_BEGIN,
......
...@@ -30,6 +30,19 @@ static const std::string kDirectiveVersion("version"); ...@@ -30,6 +30,19 @@ static const std::string kDirectiveVersion("version");
static const std::string kDirectiveLine("line"); static const std::string kDirectiveLine("line");
} // namespace } // namespace
static bool isMacroNameReserved(const std::string& name)
{
// Names prefixed with "GL_" are reserved.
if (name.substr(0, 3) == "GL_")
return true;
// Names containing two consecutive underscores are reserved.
if (name.find("__") != std::string::npos)
return true;
return false;
}
namespace pp namespace pp
{ {
...@@ -50,8 +63,10 @@ class DefinedParser : public Lexer ...@@ -50,8 +63,10 @@ class DefinedParser : public Lexer
}; };
DirectiveParser::DirectiveParser(Tokenizer* tokenizer, DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
MacroSet* macroSet,
Diagnostics* diagnostics) : Diagnostics* diagnostics) :
mTokenizer(tokenizer), mTokenizer(tokenizer),
mMacroSet(macroSet),
mDiagnostics(diagnostics) mDiagnostics(diagnostics)
{ {
} }
...@@ -98,23 +113,19 @@ void DirectiveParser::parseDirective(Token* token) ...@@ -98,23 +113,19 @@ void DirectiveParser::parseDirective(Token* token)
parseVersion(token); parseVersion(token);
else if (token->value == kDirectiveLine) else if (token->value == kDirectiveLine)
parseLine(token); parseLine(token);
else
mDiagnostics->report(Diagnostics::INVALID_DIRECTIVE,
token->location,
token->value.c_str());
} }
if ((token->type != '\n') && (token->type != 0)) if ((token->type != '\n') && (token->type != 0))
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN_IN_DIRECTIVE, mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN_IN_DIRECTIVE,
token->location, token->location,
token->value.c_str()); token->value);
while (token->type != '\n') while (token->type != '\n')
{ {
if (token->type == 0) { if (token->type == 0) {
mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE, mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
token->location, token->location,
token->value.c_str()); token->value);
break; break;
} }
mTokenizer->lex(token); mTokenizer->lex(token);
...@@ -123,15 +134,90 @@ void DirectiveParser::parseDirective(Token* token) ...@@ -123,15 +134,90 @@ void DirectiveParser::parseDirective(Token* token)
void DirectiveParser::parseDefine(Token* token) void DirectiveParser::parseDefine(Token* token)
{ {
// TODO(alokp): Implement me.
assert(token->value == kDirectiveDefine); assert(token->value == kDirectiveDefine);
mTokenizer->lex(token); mTokenizer->lex(token);
if (token->type != pp::Token::IDENTIFIER)
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN_IN_DIRECTIVE,
token->location,
token->value);
return;
}
if (isMacroNameReserved(token->value))
{
mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
token->location,
token->value);
return;
}
Macro macro;
macro.type = Macro::kTypeObj;
macro.name = token->value;
mTokenizer->lex(token);
if (token->type == '(' && !token->hasLeadingSpace())
{
// Function-like macro. Collect arguments.
macro.type = Macro::kTypeFunc;
do {
mTokenizer->lex(token);
if (token->type != pp::Token::IDENTIFIER)
break;
macro.parameters.push_back(token->value);
mTokenizer->lex(token); // Get comma.
} while (token->type == ',');
if (token->type != ')')
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN_IN_DIRECTIVE,
token->location,
token->value);
return;
}
}
while ((token->type != '\n') && (token->type != pp::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);
}
// Check for macro redefinition.
MacroSet::const_iterator iter = mMacroSet->find(macro.name);
if (iter != mMacroSet->end() && !macro.equals(iter->second))
{
mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
token->location,
macro.name);
return;
}
mMacroSet->insert(std::make_pair(macro.name, macro));
} }
void DirectiveParser::parseUndef(Token* token) void DirectiveParser::parseUndef(Token* token)
{ {
// TODO(alokp): Implement me.
assert(token->value == kDirectiveUndef); assert(token->value == kDirectiveUndef);
mTokenizer->lex(token);
if (token->type != pp::Token::IDENTIFIER)
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN_IN_DIRECTIVE,
token->location,
token->value);
return;
}
MacroSet::const_iterator iter = mMacroSet->find(token->value);
if (iter != mMacroSet->end())
mMacroSet->erase(iter);
mTokenizer->lex(token); mTokenizer->lex(token);
} }
...@@ -141,7 +227,7 @@ void DirectiveParser::parseIf(Token* token) ...@@ -141,7 +227,7 @@ void DirectiveParser::parseIf(Token* token)
assert(token->value == kDirectiveIf); assert(token->value == kDirectiveIf);
DefinedParser definedParser(mTokenizer); DefinedParser definedParser(mTokenizer);
MacroExpander macroExpander(&definedParser, mDiagnostics); MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
ExpressionParser expressionParser(&macroExpander, mDiagnostics); ExpressionParser expressionParser(&macroExpander, mDiagnostics);
macroExpander.lex(token); macroExpander.lex(token);
...@@ -223,7 +309,7 @@ void DirectiveParser::parseLine(Token* token) ...@@ -223,7 +309,7 @@ void DirectiveParser::parseLine(Token* token)
{ {
// TODO(alokp): Implement me. // TODO(alokp): Implement me.
assert(token->value == kDirectiveLine); assert(token->value == kDirectiveLine);
MacroExpander macroExpander(mTokenizer, mDiagnostics); MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
macroExpander.lex(token); macroExpander.lex(token);
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ #define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
#include "Lexer.h" #include "Lexer.h"
#include "Macro.h"
#include "pp_utils.h" #include "pp_utils.h"
namespace pp namespace pp
...@@ -19,7 +20,9 @@ class Tokenizer; ...@@ -19,7 +20,9 @@ class Tokenizer;
class DirectiveParser : public Lexer class DirectiveParser : public Lexer
{ {
public: public:
DirectiveParser(Tokenizer* tokenizer, Diagnostics* diagnostics); DirectiveParser(Tokenizer* tokenizer,
MacroSet* macroSet,
Diagnostics* diagnostics);
virtual void lex(Token* token); virtual void lex(Token* token);
...@@ -42,6 +45,7 @@ class DirectiveParser : public Lexer ...@@ -42,6 +45,7 @@ class DirectiveParser : public Lexer
void parseLine(Token* token); void parseLine(Token* token);
Tokenizer* mTokenizer; Tokenizer* mTokenizer;
MacroSet* mMacroSet;
Diagnostics* mDiagnostics; Diagnostics* mDiagnostics;
}; };
......
...@@ -6,39 +6,17 @@ ...@@ -6,39 +6,17 @@
#include "Macro.h" #include "Macro.h"
#include <algorithm> #include "Token.h"
#include "stl_utils.h"
namespace pp namespace pp
{ {
Macro::Macro(Type type, bool Macro::equals(const Macro& other) const
std::string* name,
TokenVector* parameters,
TokenVector* replacements)
: mType(type),
mName(name),
mParameters(parameters),
mReplacements(replacements)
{
}
Macro::~Macro()
{ {
delete mName; return (type == other.type) &&
(name == other.name) &&
if (mParameters) (parameters == other.parameters) &&
{ (replacements == other.replacements);
std::for_each(mParameters->begin(), mParameters->end(), Delete());
delete mParameters;
}
if (mReplacements)
{
std::for_each(mReplacements->begin(), mReplacements->end(), Delete());
delete mReplacements;
}
} }
} // namespace pp } // namespace pp
......
// //
// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
...@@ -7,45 +7,32 @@ ...@@ -7,45 +7,32 @@
#ifndef COMPILER_PREPROCESSOR_MACRO_H_ #ifndef COMPILER_PREPROCESSOR_MACRO_H_
#define COMPILER_PREPROCESSOR_MACRO_H_ #define COMPILER_PREPROCESSOR_MACRO_H_
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include "common/angleutils.h"
#include "Token.h"
namespace pp namespace pp
{ {
class Macro struct Token;
struct Macro
{ {
public:
enum Type enum Type
{ {
kTypeObj, kTypeObj,
kTypeFunc kTypeFunc
}; };
// Takes ownership of pointer parameters. bool equals(const Macro& other) const;
Macro(Type type,
std::string* name, Type type;
TokenVector* parameters, std::string name;
TokenVector* replacements); std::vector<std::string> parameters;
~Macro(); std::vector<Token> replacements;
Type type() const { return mType; }
const std::string* identifier() const { return mName; }
const TokenVector* parameters() const { return mParameters; }
const TokenVector* replacements() const { return mReplacements; }
private:
DISALLOW_COPY_AND_ASSIGN(Macro);
Type mType;
std::string* mName;
TokenVector* mParameters;
TokenVector* mReplacements;
}; };
typedef std::map<std::string, Macro> MacroSet;
} // namespace pp } // namespace pp
#endif COMPILER_PREPROCESSOR_MACRO_H_ #endif COMPILER_PREPROCESSOR_MACRO_H_
...@@ -9,8 +9,11 @@ ...@@ -9,8 +9,11 @@
namespace pp namespace pp
{ {
MacroExpander::MacroExpander(Lexer* lexer, Diagnostics* diagnostics) : MacroExpander::MacroExpander(Lexer* lexer,
MacroSet* macroSet,
Diagnostics* diagnostics) :
mLexer(lexer), mLexer(lexer),
mMacroSet(macroSet),
mDiagnostics(diagnostics) mDiagnostics(diagnostics)
{ {
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ #define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
#include "Lexer.h" #include "Lexer.h"
#include "Macro.h"
#include "pp_utils.h" #include "pp_utils.h"
namespace pp namespace pp
...@@ -18,7 +19,7 @@ class Diagnostics; ...@@ -18,7 +19,7 @@ class Diagnostics;
class MacroExpander : public Lexer class MacroExpander : public Lexer
{ {
public: public:
MacroExpander(Lexer* lexer, Diagnostics* diagnostics); MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics);
virtual void lex(Token* token); virtual void lex(Token* token);
...@@ -26,6 +27,7 @@ class MacroExpander : public Lexer ...@@ -26,6 +27,7 @@ class MacroExpander : public Lexer
PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander); PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
Lexer* mLexer; Lexer* mLexer;
MacroSet* mMacroSet;
Diagnostics* mDiagnostics; Diagnostics* mDiagnostics;
}; };
......
...@@ -14,8 +14,8 @@ namespace pp ...@@ -14,8 +14,8 @@ namespace pp
Preprocessor::Preprocessor(Diagnostics* diagnostics) : Preprocessor::Preprocessor(Diagnostics* diagnostics) :
mDiagnostics(diagnostics), mDiagnostics(diagnostics),
mTokenizer(mDiagnostics), mTokenizer(mDiagnostics),
mDirectiveParser(&mTokenizer, mDiagnostics), mDirectiveParser(&mTokenizer, &mMacroSet, mDiagnostics),
mMacroExpander(&mDirectiveParser, mDiagnostics) mMacroExpander(&mDirectiveParser, &mMacroSet, mDiagnostics)
{ {
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_ #define COMPILER_PREPROCESSOR_PREPROCESSOR_H_
#include "DirectiveParser.h" #include "DirectiveParser.h"
#include "Macro.h"
#include "MacroExpander.h" #include "MacroExpander.h"
#include "Tokenizer.h" #include "Tokenizer.h"
...@@ -38,6 +39,8 @@ class Preprocessor ...@@ -38,6 +39,8 @@ class Preprocessor
PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor); PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor);
Diagnostics* mDiagnostics; Diagnostics* mDiagnostics;
MacroSet mMacroSet;
Tokenizer mTokenizer; Tokenizer mTokenizer;
DirectiveParser mDirectiveParser; DirectiveParser mDirectiveParser;
MacroExpander mMacroExpander; MacroExpander mMacroExpander;
......
...@@ -67,7 +67,7 @@ struct Token ...@@ -67,7 +67,7 @@ struct Token
{ {
return (type == other.type) && return (type == other.type) &&
(flags == other.flags) && (flags == other.flags) &&
(location.equals(other.location)) && (location == other.location) &&
(value == other.value); (value == other.value);
} }
...@@ -86,6 +86,16 @@ struct Token ...@@ -86,6 +86,16 @@ struct Token
std::string value; std::string value;
}; };
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);
}
extern std::ostream& operator<<(std::ostream& out, const Token& token); extern std::ostream& operator<<(std::ostream& out, const Token& token);
} // namepsace pp } // namepsace pp
......
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