Correctly parse function macros
authorLars Knoll <lars.knoll@nokia.com>
Sat, 8 Sep 2012 19:44:12 +0000 (21:44 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Mon, 24 Sep 2012 22:08:16 +0000 (00:08 +0200)
Parse function macros and add it's list of arguments
to the Macro definition.

Change-Id: Id22f5cf4a1c098f7b4f5b72f002900cd40d03e0f
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
src/tools/moc/preprocessor.cpp
src/tools/moc/preprocessor.h
src/tools/moc/utils.h

index 4d4b571..3c43974 100644 (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)
index 70121c2..518ead8 100644 (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();
index bacc908..aaaaaa3 100644 (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');