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 @@
'compiler/preprocessor/new/Input.h',
'compiler/preprocessor/new/Lexer.cpp',
'compiler/preprocessor/new/Lexer.h',
'compiler/preprocessor/new/Macro.cpp',
'compiler/preprocessor/new/Macro.h',
'compiler/preprocessor/new/MacroExpander.cpp',
'compiler/preprocessor/new/MacroExpander.h',
'compiler/preprocessor/new/Preprocessor.cpp',
......
......@@ -26,12 +26,13 @@ class Diagnostics
OUT_OF_MEMORY,
INVALID_CHARACTER,
INVALID_NUMBER,
INVALID_DIRECTIVE,
INVALID_EXPRESSION,
DIVISION_BY_ZERO,
EOF_IN_COMMENT,
EOF_IN_DIRECTIVE,
UNEXPECTED_TOKEN_IN_DIRECTIVE,
MACRO_NAME_RESERVED,
MACRO_REDEFINED,
ERROR_END,
WARNING_BEGIN,
......
......@@ -30,6 +30,19 @@ static const std::string kDirectiveVersion("version");
static const std::string kDirectiveLine("line");
} // 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
{
......@@ -50,8 +63,10 @@ class DefinedParser : public Lexer
};
DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
MacroSet* macroSet,
Diagnostics* diagnostics) :
mTokenizer(tokenizer),
mMacroSet(macroSet),
mDiagnostics(diagnostics)
{
}
......@@ -98,23 +113,19 @@ void DirectiveParser::parseDirective(Token* token)
parseVersion(token);
else if (token->value == kDirectiveLine)
parseLine(token);
else
mDiagnostics->report(Diagnostics::INVALID_DIRECTIVE,
token->location,
token->value.c_str());
}
if ((token->type != '\n') && (token->type != 0))
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN_IN_DIRECTIVE,
token->location,
token->value.c_str());
token->value);
while (token->type != '\n')
{
if (token->type == 0) {
mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
token->location,
token->value.c_str());
token->value);
break;
}
mTokenizer->lex(token);
......@@ -123,15 +134,90 @@ void DirectiveParser::parseDirective(Token* token)
void DirectiveParser::parseDefine(Token* token)
{
// TODO(alokp): Implement me.
assert(token->value == kDirectiveDefine);
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)
{
// TODO(alokp): Implement me.
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);
}
......@@ -141,7 +227,7 @@ void DirectiveParser::parseIf(Token* token)
assert(token->value == kDirectiveIf);
DefinedParser definedParser(mTokenizer);
MacroExpander macroExpander(&definedParser, mDiagnostics);
MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
ExpressionParser expressionParser(&macroExpander, mDiagnostics);
macroExpander.lex(token);
......@@ -223,7 +309,7 @@ void DirectiveParser::parseLine(Token* token)
{
// TODO(alokp): Implement me.
assert(token->value == kDirectiveLine);
MacroExpander macroExpander(mTokenizer, mDiagnostics);
MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
macroExpander.lex(token);
}
......
......@@ -8,6 +8,7 @@
#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
#include "Lexer.h"
#include "Macro.h"
#include "pp_utils.h"
namespace pp
......@@ -19,7 +20,9 @@ class Tokenizer;
class DirectiveParser : public Lexer
{
public:
DirectiveParser(Tokenizer* tokenizer, Diagnostics* diagnostics);
DirectiveParser(Tokenizer* tokenizer,
MacroSet* macroSet,
Diagnostics* diagnostics);
virtual void lex(Token* token);
......@@ -42,6 +45,7 @@ class DirectiveParser : public Lexer
void parseLine(Token* token);
Tokenizer* mTokenizer;
MacroSet* mMacroSet;
Diagnostics* mDiagnostics;
};
......
......@@ -6,39 +6,17 @@
#include "Macro.h"
#include <algorithm>
#include "stl_utils.h"
#include "Token.h"
namespace pp
{
Macro::Macro(Type type,
std::string* name,
TokenVector* parameters,
TokenVector* replacements)
: mType(type),
mName(name),
mParameters(parameters),
mReplacements(replacements)
{
}
Macro::~Macro()
bool Macro::equals(const Macro& other) const
{
delete mName;
if (mParameters)
{
std::for_each(mParameters->begin(), mParameters->end(), Delete());
delete mParameters;
}
if (mReplacements)
{
std::for_each(mReplacements->begin(), mReplacements->end(), Delete());
delete mReplacements;
}
return (type == other.type) &&
(name == other.name) &&
(parameters == other.parameters) &&
(replacements == other.replacements);
}
} // 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
// found in the LICENSE file.
//
......@@ -7,45 +7,32 @@
#ifndef COMPILER_PREPROCESSOR_MACRO_H_
#define COMPILER_PREPROCESSOR_MACRO_H_
#include <map>
#include <string>
#include <vector>
#include "common/angleutils.h"
#include "Token.h"
namespace pp
{
class Macro
struct Token;
struct Macro
{
public:
enum Type
{
kTypeObj,
kTypeFunc
};
// Takes ownership of pointer parameters.
Macro(Type type,
std::string* name,
TokenVector* parameters,
TokenVector* replacements);
~Macro();
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;
bool equals(const Macro& other) const;
Type type;
std::string name;
std::vector<std::string> parameters;
std::vector<Token> replacements;
};
typedef std::map<std::string, Macro> MacroSet;
} // namespace pp
#endif COMPILER_PREPROCESSOR_MACRO_H_
......@@ -9,8 +9,11 @@
namespace pp
{
MacroExpander::MacroExpander(Lexer* lexer, Diagnostics* diagnostics) :
MacroExpander::MacroExpander(Lexer* lexer,
MacroSet* macroSet,
Diagnostics* diagnostics) :
mLexer(lexer),
mMacroSet(macroSet),
mDiagnostics(diagnostics)
{
}
......
......@@ -8,6 +8,7 @@
#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
#include "Lexer.h"
#include "Macro.h"
#include "pp_utils.h"
namespace pp
......@@ -18,7 +19,7 @@ class Diagnostics;
class MacroExpander : public Lexer
{
public:
MacroExpander(Lexer* lexer, Diagnostics* diagnostics);
MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics);
virtual void lex(Token* token);
......@@ -26,6 +27,7 @@ class MacroExpander : public Lexer
PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
Lexer* mLexer;
MacroSet* mMacroSet;
Diagnostics* mDiagnostics;
};
......
......@@ -14,8 +14,8 @@ namespace pp
Preprocessor::Preprocessor(Diagnostics* diagnostics) :
mDiagnostics(diagnostics),
mTokenizer(mDiagnostics),
mDirectiveParser(&mTokenizer, mDiagnostics),
mMacroExpander(&mDirectiveParser, mDiagnostics)
mDirectiveParser(&mTokenizer, &mMacroSet, mDiagnostics),
mMacroExpander(&mDirectiveParser, &mMacroSet, mDiagnostics)
{
}
......
......@@ -8,6 +8,7 @@
#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_
#include "DirectiveParser.h"
#include "Macro.h"
#include "MacroExpander.h"
#include "Tokenizer.h"
......@@ -38,6 +39,8 @@ class Preprocessor
PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor);
Diagnostics* mDiagnostics;
MacroSet mMacroSet;
Tokenizer mTokenizer;
DirectiveParser mDirectiveParser;
MacroExpander mMacroExpander;
......
......@@ -67,7 +67,7 @@ struct Token
{
return (type == other.type) &&
(flags == other.flags) &&
(location.equals(other.location)) &&
(location == other.location) &&
(value == other.value);
}
......@@ -86,6 +86,16 @@ struct Token
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);
} // 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