Correctly parse function macros

Parse function macros and add it's list of arguments
to the Macro definition.

Change-Id: Id22f5cf4a1c098f7b4f5b72f002900cd40d03e0f
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
Lars Knoll 2012-09-08 21:44:12 +02:00 committed by The Qt Project
parent 34a3b63dc7
commit 38f1b4eeae
3 changed files with 75 additions and 8 deletions

View File

@ -452,9 +452,10 @@ static Symbols tokenize(const QByteArray &input, int lineNum = 1, TokenizeMode m
if (mode == PrepareDefine) {
symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
// make sure we explicitly add the whitespace here, so we can distinguish
// correctly between regular and function macros
if (is_space(*data))
// make sure we explicitly add the whitespace here if the next char
// is not an opening brace, so we can distinguish correctly between
// regular and function macros
if (*data != '(')
symbols += Symbol(lineNum, WHITESPACE);
mode = TokenizeDefine;
continue;
@ -536,14 +537,13 @@ void Preprocessor::macroExpandIdentifier(const Symbol &s, Symbols &preprocessed,
return;
}
Symbols expanded = macros.value(s).symbols;
const Macro &macro = macros.value(s);
// don't expand macros with arguments for now
if (expanded.size() && expanded.at(0).token == PP_LPAREN) {
preprocessed += s;
if (macro.isFunction)
return;
}
Symbols expanded = macro.symbols;
for (int i = 0; i < expanded.size(); ++i) {
expanded[i].lineNum = s.lineNum;
if (expanded.at(i).token == PP_IDENTIFIER)
@ -906,9 +906,20 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
{
next(IDENTIFIER);
QByteArray name = lexem();
Macro macro;
macro.isVariadic = false;
Token t = next();
if (t == LPAREN) {
// we have a function macro
macro.isFunction = true;
parseDefineArguments(&macro);
} else if (t == PP_WHITESPACE){
macro.isFunction = false;
} else {
error("Moc: internal error");
}
int start = index;
until(PP_NEWLINE);
Macro macro;
macro.symbols.reserve(index - start - 1);
for (int i = start; i < index - 1; ++i)
macro.symbols += symbols.at(i);
@ -1012,6 +1023,46 @@ Symbols Preprocessor::preprocessed(const QByteArray &filename, QIODevice *file)
return result;
}
void Preprocessor::parseDefineArguments(Macro *m)
{
Symbols arguments;
while (hasNext()) {
Token t = next();
if (t == PP_WHITESPACE)
t = next();
if (t == PP_RPAREN)
break;
if (t != PP_IDENTIFIER) {
QByteArray l = lexem();
if (l == "...") {
m->isVariadic = true;
arguments += symbol();
while (test(PP_WHITESPACE));
if (!test(PP_RPAREN))
error("missing ')' in macro argument list");
break;
} else if (!is_identifier(l.constData(), l.length())) {
qDebug() << l;
error("Unexpected character in macro argument list.");
}
}
Symbol arg = symbol();
if (arguments.contains(arg))
error("Duplicate macro parameter.");
arguments += symbol();
t = next();
while (t == PP_WHITESPACE)
t = next();
if (t == PP_RPAREN)
break;
if (t != PP_COMMA)
error("Unexpected character in macro argument list.");
}
m->arguments = arguments;
}
void Preprocessor::until(Token t)
{
while(hasNext() && next() != t)

View File

@ -51,6 +51,9 @@ QT_BEGIN_NAMESPACE
struct Macro
{
bool isFunction;
bool isVariadic;
Symbols arguments;
Symbols symbols;
};
@ -75,6 +78,7 @@ public:
Symbols preprocessed(const QByteArray &filename, FILE *file);
Symbols preprocessed(const QByteArray &filename, QIODevice *device);
void parseDefineArguments(Macro *m);
void skipUntilEndif();
bool skipBranch();

View File

@ -73,6 +73,18 @@ inline bool is_ident_char(char s)
);
}
inline bool is_identifier(const char *s, int len)
{
if (len < 1)
return false;
if (!is_ident_start(*s))
return false;
for (int i = 1; i < len; ++i)
if (!is_ident_char(s[i]))
return false;
return true;
}
inline bool is_digit_char(char s)
{
return (s >= '0' && s <= '9');