Commit f3cdb460 by alokp@chromium.org

Added support for pre-defined macros.

Review URL: https://codereview.appspot.com/6301084 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1157 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 4f677306
......@@ -38,6 +38,8 @@ class Diagnostics
UNEXPECTED_TOKEN,
MACRO_NAME_RESERVED,
MACRO_REDEFINED,
MACRO_PREDEFINED_REDEFINED,
MACRO_PREDEFINED_UNDEFINED,
MACRO_UNTERMINATED_INVOCATION,
MACRO_TOO_FEW_ARGS,
MACRO_TOO_MANY_ARGS,
......
......@@ -46,6 +46,13 @@ static bool isMacroNameReserved(const std::string& name)
return false;
}
static bool isMacroPredefined(const std::string& name,
const pp::MacroSet& macroSet)
{
pp::MacroSet::const_iterator iter = macroSet.find(name);
return iter != macroSet.end() ? iter->second.predefined : false;
}
namespace pp
{
......@@ -140,15 +147,19 @@ void DirectiveParser::parseDefine(Token* token)
if (token->type != Token::IDENTIFIER)
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
token->location,
token->value);
token->location, token->value);
return;
}
if (isMacroPredefined(token->value, *mMacroSet))
{
mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
token->location, token->value);
return;
}
if (isMacroNameReserved(token->value))
{
mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
token->location,
token->value);
token->location, token->value);
return;
}
......@@ -216,14 +227,23 @@ void DirectiveParser::parseUndef(Token* token)
if (token->type != Token::IDENTIFIER)
{
mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
token->location,
token->value);
token->location, token->value);
return;
}
MacroSet::iterator iter = mMacroSet->find(token->value);
if (iter != mMacroSet->end())
mMacroSet->erase(iter);
{
if (iter->second.predefined)
{
mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
token->location, token->value);
}
else
{
mMacroSet->erase(iter);
}
}
mTokenizer->lex(token);
}
......
......@@ -26,10 +26,12 @@ struct Macro
typedef std::vector<std::string> Parameters;
typedef std::vector<Token> Replacements;
Macro() : disabled(false), type(kTypeObj) { }
Macro() : predefined(false), disabled(false), type(kTypeObj) { }
bool equals(const Macro& other) const;
bool predefined;
mutable bool disabled;
Type type;
std::string name;
Parameters parameters;
......
......@@ -8,6 +8,7 @@
#include <algorithm>
#include <cassert>
#include <sstream>
#include "Diagnostics.h"
#include "Token.h"
......@@ -57,8 +58,7 @@ MacroExpander::MacroExpander(Lexer* lexer,
MacroExpander::~MacroExpander()
{
assert(!mReserveToken.get());
assert(mContextStack.empty());
while (!mContextStack.empty()) popMacro();
}
void MacroExpander::lex(Token* token)
......@@ -185,10 +185,32 @@ bool MacroExpander::expandMacro(const Macro& macro,
const Token& identifier,
std::vector<Token>* replacements)
{
replacements->clear();
if (macro.type == Macro::kTypeObj)
{
replacements->assign(macro.replacements.begin(),
macro.replacements.end());
if (macro.predefined)
{
static const std::string kLine = "__LINE__";
static const std::string kFile = "__FILE__";
assert(replacements->size() == 1);
Token& repl = replacements->front();
if (macro.name == kLine)
{
std::stringstream stream;
stream << identifier.location.line;
repl.value = stream.str();
}
else if (macro.name == kFile)
{
std::stringstream stream;
stream << identifier.location.file;
repl.value = stream.str();
}
}
}
else
{
......
......@@ -6,6 +6,8 @@
#include "Preprocessor.h"
#include <sstream>
#include "Token.h"
namespace pp
......@@ -23,9 +25,35 @@ bool Preprocessor::init(int count,
const char* const string[],
const int length[])
{
static const int kGLSLVersion = 100;
// Add standard pre-defined macros.
predefineMacro("__LINE__", 0);
predefineMacro("__FILE__", 0);
predefineMacro("__VERSION__", kGLSLVersion);
predefineMacro("GL_ES", 1);
return mTokenizer.init(count, string, length);
}
void Preprocessor::predefineMacro(const std::string& name, int value)
{
std::stringstream stream;
stream << value;
Token token;
token.type = Token::CONST_INT;
token.value = stream.str();
Macro macro;
macro.predefined = true;
macro.type = Macro::kTypeObj;
macro.name = name;
macro.replacements.push_back(token);
mMacroSet[name] = macro;
}
void Preprocessor::lex(Token* token)
{
mMacroExpander.lex(token);
......
......@@ -33,6 +33,8 @@ class Preprocessor
// corresponding string or a value less than 0 to indicate that the string
// is null terminated.
bool init(int count, const char* const string[], const int length[]);
// Adds a pre-defined macro.
void predefineMacro(const std::string& name, int value);
void lex(Token* token);
......
......@@ -26,6 +26,45 @@ TEST_F(DefineTest, NonIdentifier)
preprocess(input, expected);
};
TEST_F(DefineTest, RedefinePredefined)
{
const char* input = "#define __LINE__ 10\n"
"__LINE__\n"
"#define __FILE__ 20\n"
"__FILE__\n"
"#define __VERSION__ 200\n"
"__VERSION__\n"
"#define GL_ES 0\n"
"GL_ES\n";
const char* expected = "\n"
"2\n"
"\n"
"0\n"
"\n"
"100\n"
"\n"
"1\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::MACRO_PREDEFINED_REDEFINED,
pp::SourceLocation(0, 1),
"__LINE__"));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::MACRO_PREDEFINED_REDEFINED,
pp::SourceLocation(0, 3),
"__FILE__"));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::MACRO_PREDEFINED_REDEFINED,
pp::SourceLocation(0, 5),
"__VERSION__"));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::MACRO_PREDEFINED_REDEFINED,
pp::SourceLocation(0, 7),
"GL_ES"));
preprocess(input, expected);
}
TEST_F(DefineTest, ReservedUnderScore1)
{
const char* input = "#define __foo bar\n"
......@@ -693,6 +732,45 @@ TEST_F(DefineTest, Undef)
preprocess(input, expected);
}
TEST_F(DefineTest, UndefPredefined)
{
const char* input = "#undef __LINE__\n"
"__LINE__\n"
"#undef __FILE__\n"
"__FILE__\n"
"#undef __VERSION__\n"
"__VERSION__\n"
"#undef GL_ES\n"
"GL_ES\n";
const char* expected = "\n"
"2\n"
"\n"
"0\n"
"\n"
"100\n"
"\n"
"1\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::MACRO_PREDEFINED_UNDEFINED,
pp::SourceLocation(0, 1),
"__LINE__"));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::MACRO_PREDEFINED_UNDEFINED,
pp::SourceLocation(0, 3),
"__FILE__"));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::MACRO_PREDEFINED_UNDEFINED,
pp::SourceLocation(0, 5),
"__VERSION__"));
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::MACRO_PREDEFINED_UNDEFINED,
pp::SourceLocation(0, 7),
"GL_ES"));
preprocess(input, expected);
}
TEST_F(DefineTest, UndefRedefine)
{
const char* input = "#define foo 1\n"
......@@ -753,3 +831,63 @@ TEST_F(DefineTest, C99Example)
preprocess(input, expected);
}
TEST_F(DefineTest, Predefined_GL_ES)
{
const char* input = "GL_ES\n";
const char* expected = "1\n";
preprocess(input, expected);
}
TEST_F(DefineTest, Predefined_VERSION)
{
const char* input = "__VERSION__\n";
const char* expected = "100\n";
preprocess(input, expected);
}
TEST_F(DefineTest, Predefined_LINE1)
{
const char* str = "\n\n__LINE__";
ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
pp::Token token;
mPreprocessor.lex(&token);
EXPECT_EQ(pp::Token::CONST_INT, token.type);
EXPECT_EQ("3", token.value);
}
TEST_F(DefineTest, Predefined_LINE2)
{
const char* str = "#line 10\n"
"__LINE__\n";
ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
pp::Token token;
mPreprocessor.lex(&token);
EXPECT_EQ(pp::Token::CONST_INT, token.type);
EXPECT_EQ("10", token.value);
}
TEST_F(DefineTest, Predefined_FILE1)
{
const char* const str[] = {"", "", "__FILE__"};
ASSERT_TRUE(mPreprocessor.init(3, str, NULL));
pp::Token token;
mPreprocessor.lex(&token);
EXPECT_EQ(pp::Token::CONST_INT, token.type);
EXPECT_EQ("2", token.value);
}
TEST_F(DefineTest, Predefined_FILE2)
{
const char* const str[] = {"#line 10 20\n", "__FILE__"};
ASSERT_TRUE(mPreprocessor.init(2, str, NULL));
pp::Token token;
mPreprocessor.lex(&token);
EXPECT_EQ(pp::Token::CONST_INT, token.type);
EXPECT_EQ("21", token.value);
}
......@@ -200,7 +200,7 @@ TEST_F(LocationTest, LineDirectiveCommentsIgnored)
expectLocation(1, &str, NULL, loc);
}
TEST_F(LocationTest, LineDirectiveWithMacro)
TEST_F(LocationTest, LineDirectiveWithMacro1)
{
const char* str = "#define L 10\n"
"#define F(x) x\n"
......@@ -208,6 +208,27 @@ TEST_F(LocationTest, LineDirectiveWithMacro)
"foo";
pp::SourceLocation loc(20, 10);
SCOPED_TRACE("LineDirectiveWithMacro1");
expectLocation(1, &str, NULL, loc);
}
TEST_F(LocationTest, LineDirectiveWithMacro2)
{
const char* str = "#define LOC 10 20\n"
"#line LOC\n"
"foo";
pp::SourceLocation loc(20, 10);
SCOPED_TRACE("LineDirectiveWithMacro2");
expectLocation(1, &str, NULL, loc);
}
TEST_F(LocationTest, LineDirectiveWithPredefinedMacro)
{
const char* str = "#line __LINE__ __FILE__\n"
"foo";
pp::SourceLocation loc(0, 1);
SCOPED_TRACE("LineDirectiveWithMacro");
expectLocation(1, &str, NULL, loc);
}
......
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