1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the tools applications of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
30
#include "generator.h"
31
#include "qdatetime.h"
33
#include "outputrevision.h"
37
// WARNING: a copy of this function is in qmetaobject.cpp
38
static QByteArray normalizeTypeInternal(const char *t, const char *e, bool fixScope = true, bool adjustConst = true)
41
if (strncmp("void", t, len) == 0)
44
Convert 'char const *' into 'const char *'. Start at index 1,
45
not 0, because 'const char *' is already OK.
48
for (int i = 1; i < len; i++) {
50
&& strncmp(t + i + 1, "onst", 4) == 0
51
&& (i + 5 >= len || !is_ident_char(t[i + 5]))
52
&& !is_ident_char(t[i-1])
54
constbuf = QByteArray(t, len);
56
constbuf.remove(i-1, 6);
58
constbuf.remove(i, 5);
59
constbuf.prepend("const ");
61
e = constbuf.data() + constbuf.length();
65
We musn't convert 'char * const *' into 'const char **'
66
and we must beware of 'Bar<const Bla>'.
68
if (t[i] == '&' || t[i] == '*' ||t[i] == '<')
71
if (adjustConst && e > t + 6 && strncmp("const ", t, 6) == 0) {
72
if (*(e-1) == '&') { // treat const reference as value
75
} else if (is_ident_char(*(e-1))) { // treat const value as value
82
// some type substitutions for 'unsigned x'
83
if (strncmp("unsigned ", t, 9) == 0) {
84
if (strncmp("int", t+9, 3) == 0) {
87
} else if (strncmp("long", t+9, 4) == 0) {
95
if (fixScope && c == ':' && *t == ':' ) {
98
int i = result.size() - 1;
99
while (i >= 0 && is_ident_char(result.at(i)))
101
result.resize(i + 1);
114
if (templdepth == 0) {
115
result += normalizeTypeInternal(tt, t-1, fixScope, false);
118
result += ' '; // avoid >>
128
// only moc needs this function
129
QByteArray normalizeType(const char *s, bool fixScope)
131
int len = qstrlen(s);
133
char *buf = (len >= 64 ? new char[len] : stackbuf);
136
while(*s && is_space(*s))
139
while (*s && !is_space(*s))
141
while (*s && is_space(*s))
143
if (*s && is_ident_char(*s) && is_ident_char(last))
147
QByteArray result = normalizeTypeInternal(buf, d, fixScope);
153
static const char *error_msg = 0;
156
#define ErrorFormatString "%s(%d): "
158
#define ErrorFormatString "%s:%d: "
161
void Moc::error(int rollback) {
165
void Moc::error(const char *msg) {
166
if (msg || error_msg)
167
qWarning(ErrorFormatString "Error: %s",
168
currentFilenames.top().constData(), symbol().lineNum, msg?msg:error_msg);
170
qWarning(ErrorFormatString "Parse error at \"%s\"",
171
currentFilenames.top().constData(), symbol().lineNum, symbol().lexem().data());
175
void Moc::warning(const char *msg) {
176
if (displayWarnings && msg)
177
fprintf(stderr, ErrorFormatString "Warning: %s\n",
178
filename.constData(), qMax(0, symbol().lineNum), msg);
181
bool Moc::until(Token target) {
187
switch(symbols.at(index-1).token) {
188
case LBRACE: ++braceCount; break;
189
case LBRACK: ++brackCount; break;
190
case LPAREN: ++parenCount; break;
191
case LANGLE: ++angleCount; break;
195
while (index < symbols.size()) {
196
Token t = symbols.at(index++).token;
198
case LBRACE: ++braceCount; break;
199
case RBRACE: --braceCount; break;
200
case LBRACK: ++brackCount; break;
201
case RBRACK: --brackCount; break;
202
case LPAREN: ++parenCount; break;
203
case RPAREN: --parenCount; break;
204
case LANGLE: ++angleCount; break;
205
case RANGLE: --angleCount; break;
212
&& (target != RANGLE || angleCount <= 0))
215
if (braceCount < 0 || brackCount < 0 || parenCount < 0
216
|| (target == RANGLE && angleCount < 0)) {
224
QByteArray Moc::lexemUntil(Token target)
229
while (from <= index) {
230
QByteArray n = symbols.at(from++-1).lexem();
231
if (s.size() && n.size()
232
&& is_ident_char(s.at(s.size()-1))
233
&& is_ident_char(n.at(0)))
240
bool Moc::parseClassHead(ClassDef *def)
242
// figure out whether this is a class declaration, or only a
243
// forward or variable declaration.
248
if (token == COLON || token == LBRACE)
250
if (token == SEMIC || token == RANGLE)
255
QByteArray name = lexem();
257
// support "class IDENT name" and "class IDENT(IDENT) name"
262
} else if (test(IDENTIFIER)) {
266
def->qualified += name;
267
while (test(SCOPE)) {
268
def->qualified += lexem();
269
if (test(IDENTIFIER)) {
271
def->qualified += name;
274
def->classname = name;
278
FunctionDef::Access access = FunctionDef::Public;
280
access = FunctionDef::Private;
281
else if (test(PROTECTED))
282
access = FunctionDef::Protected;
286
def->superclassList += qMakePair(parseType(), access);
287
} while (test(COMMA));
290
def->begin = index - 1;
293
index = def->begin + 1;
297
QByteArray Moc::parseType()
300
while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)) {
304
test(ENUM) || test(CLASS) || test(STRUCT);
323
QByteArray templ = lexemUntil(RANGLE);
324
for (int i = 0; i < templ.size(); ++i) {
326
if (templ.at(i) == '>' && i < templ.size()-1 && templ.at(i+1) == '>')
335
while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
336
|| test(STAR) || test(AND)) {
343
bool Moc::parseEnum(EnumDef *def)
345
if (!test(IDENTIFIER))
346
return false; // anonymous enum
351
if (lookup() == RBRACE) // accept trailing comma
354
def->values += lexem();
355
} while (test(EQ) ? until(COMMA) : test(COMMA));
360
void Moc::parseFunctionArguments(FunctionDef *def)
365
arg.type = parseType();
366
if (arg.type == "void")
368
if (test(IDENTIFIER))
371
arg.rightType += lexemUntil(RBRACK);
372
if (test(CONST) || test(VOLATILE)) {
373
arg.rightType += ' ';
374
arg.rightType += lexem();
376
arg.normalizedType = normalizeType(arg.type + ' ' + arg.rightType);
378
arg.isDefault = true;
379
def->arguments += arg;
385
void Moc::parseFunction(FunctionDef *def, bool inMacro)
387
def->isVirtual = test(VIRTUAL);
388
while (test(INLINE) || test(STATIC))
390
bool templateFunction = (lookup() == TEMPLATE);
391
def->type = parseType();
392
if (def->type.isEmpty()) {
393
if (templateFunction)
394
error("Template function as signal or slot");
399
def->name = def->type;
402
def->name = parseType();
403
while (!def->name.isEmpty() && lookup() != LPAREN) {
404
if (def->type == "QT_MOC_COMPAT" || def->type == "QT3_SUPPORT")
405
def->isCompat = true;
406
else if (def->type == "Q_INVOKABLE")
407
def->isInvokable = true;
408
else if (def->type == "Q_SCRIPTABLE")
409
def->isInvokable = def->isScriptable = true;
411
if (!def->tag.isEmpty())
413
def->tag += def->type;
415
def->type = def->name;
416
def->name = parseType();
418
next(LPAREN, "Not a signal or slot declaration");
421
def->normalizedType = normalizeType(def->type);
424
parseFunctionArguments(def);
427
def->isConst = test(CONST);
433
else if ((def->inlineCode = test(LBRACE)))
442
// like parseFunction, but never aborts with an error
443
bool Moc::parseMaybeFunction(FunctionDef *def)
445
def->type = parseType();
446
if (def->type.isEmpty())
449
def->name = def->type;
452
def->name = parseType();
453
while (!def->name.isEmpty() && lookup() != LPAREN) {
454
if (def->type == "QT_MOC_COMPAT" || def->type == "QT3_SUPPORT")
455
def->isCompat = true;
456
else if (def->type == "Q_INVOKABLE")
457
def->isInvokable = true;
458
else if (def->type == "Q_SCRIPTABLE")
459
def->isInvokable = def->isScriptable = true;
461
if (!def->tag.isEmpty())
463
def->tag += def->type;
465
def->type = def->name;
466
def->name = parseType();
472
def->normalizedType = normalizeType(def->type);
475
parseFunctionArguments(def);
479
def->isConst = test(CONST);
486
currentFilenames.push(filename);
488
QList<NamespaceDef> namespaceList;
489
bool templateClass = false;
492
if (t == NAMESPACE) {
494
if (test(IDENTIFIER) && !test(SEMIC)) {
498
def.begin = index - 1;
501
index = def.begin + 1;
502
namespaceList += def;
505
} else if (t == SEMIC || t == RBRACE) {
506
templateClass = false;
507
} else if (t == TEMPLATE) {
508
templateClass = true;
509
} else if (t == MOC_INCLUDE_BEGIN) {
510
next(STRING_LITERAL);
511
currentFilenames.push(symbol().unquotedLexem());
512
} else if (t == MOC_INCLUDE_END) {
513
currentFilenames.pop();
514
} else if (t == Q_DECLARE_INTERFACE_TOKEN) {
515
parseDeclareInterface();
516
} else if (t == USING && test(NAMESPACE)) {
517
while (test(SCOPE) || test(IDENTIFIER))
521
if (t != CLASS || currentFilenames.size() > 1)
524
FunctionDef::Access access = FunctionDef::Private;
525
if (parseClassHead(&def)) {
526
for (int i = namespaceList.size() - 1; i >= 0; --i)
527
if (inNamespace(&namespaceList.at(i)))
528
def.qualified.prepend(namespaceList.at(i).name + "::");
529
while (inClass(&def) && hasNext()) {
530
switch ((t = next())) {
532
access = FunctionDef::Private;
534
error("Signals cannot have access specifier");
537
access = FunctionDef::Protected;
539
error("Signals cannot have access specifier");
542
access = FunctionDef::Public;
544
error("Signals cannot have access specifier");
548
if (parseClassHead(&nestedDef)) {
549
while (inClass(&nestedDef) && inClass(&def)) {
551
if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
552
error("Meta object features not supported for nested classes");
560
switch (lookup(-1)) {
564
parseSlots(&def, access);
567
error("Missing access specifier for slots");
571
def.hasQObject = true;
573
error("Template classes not supported by Q_OBJECT");
574
if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
575
error("Class contains Q_OBJECT macro but does not inherit from QObject");
578
def.hasQGadget = true;
580
error("Template classes not supported by Q_GADGET");
582
case Q_PROPERTY_TOKEN:
586
parseEnumOrFlag(&def, false);
589
parseEnumOrFlag(&def, true);
591
case Q_DECLARE_FLAGS_TOKEN:
594
case Q_CLASSINFO_TOKEN:
595
parseClassInfo(&def);
597
case Q_INTERFACES_TOKEN:
598
parseInterfaces(&def);
600
case Q_PRIVATE_SLOT_TOKEN:
601
parseSlotInPrivate(&def, access);
605
if (parseEnum(&enumDef))
606
def.enumList += enumDef;
610
funcDef.access = access;
612
if (parseMaybeFunction(&funcDef)) {
613
if (access == FunctionDef::Public)
614
def.publicList += funcDef;
615
if (funcDef.isInvokable) {
616
def.methodList += funcDef;
617
while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
618
funcDef.wasCloned = true;
619
funcDef.arguments.removeLast();
620
def.methodList += funcDef;
631
if (!def.hasQObject && def.signalList.isEmpty() && def.slotList.isEmpty()
632
&& def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
633
continue; // no meta object code required
636
if (!def.hasQObject && !def.hasQGadget)
637
error("Class declarations lacks Q_OBJECT macro.");
645
void Moc::generate(FILE *out)
648
QDateTime dt = QDateTime::currentDateTime();
649
QByteArray dstr = dt.toString().toLatin1();
650
QByteArray fn = filename;
651
int i = filename.length()-1;
652
while (i>0 && filename[i-1] != '/' && filename[i-1] != '\\')
655
fn = filename.mid(i);
656
fprintf(out, "/****************************************************************************\n"
657
"** Meta object code from reading C++ file '%s'\n**\n" , (const char*)fn);
658
fprintf(out, "** Created: %s\n"
659
"** by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , dstr.data(), mocOutputRevision, QT_VERSION_STR);
660
fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
661
"*****************************************************************************/\n\n");
665
if (includePath.size() && includePath.right(1) != "/")
667
for (int i = 0; i < includeFiles.size(); ++i) {
668
QByteArray inc = includeFiles.at(i);
669
if (inc[0] != '<' && inc[0] != '"') {
670
if (includePath.size() && includePath != "./")
671
inc.prepend(includePath);
672
inc = "\"" + inc + "\"";
674
fprintf(out, "#include %s\n", inc.constData());
677
if (classList.size() && classList.first().classname == "Qt")
678
fprintf(out, "#include <QtCore/qobject.h>\n");
680
fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
681
"#error \"The header file '%s' doesn't include <QObject>.\"\n", (const char *)fn);
682
fprintf(out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
683
fprintf(out, "#error \"This file was generated using the moc from %s."
684
" It\"\n#error \"cannot be used with the include files from"
685
" this version of Qt.\"\n#error \"(The moc has changed too"
686
" much.)\"\n", QT_VERSION_STR);
687
fprintf(out, "#endif\n\n");
690
for (i = 0; i < classList.size(); ++i) {
691
Generator generator(out, &classList[i]);
692
generator.generateCode();
698
void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
701
while (inClass(def) && hasNext()) {
717
funcDef.access = access;
718
parseFunction(&funcDef);
719
def->slotList += funcDef;
720
while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
721
funcDef.wasCloned = true;
722
funcDef.arguments.removeLast();
723
def->slotList += funcDef;
728
void Moc::parseSignals(ClassDef *def)
731
while (inClass(def) && hasNext()) {
746
funcDef.access = FunctionDef::Protected;
747
parseFunction(&funcDef);
748
if (funcDef.isVirtual)
749
error("Signals cannot be declared virtual");
751
error("Signals cannot have const qualifier");
752
if (funcDef.inlineCode)
753
error("Not a signal declaration");
754
def->signalList += funcDef;
755
while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
756
funcDef.wasCloned = true;
757
funcDef.arguments.removeLast();
758
def->signalList += funcDef;
764
void Moc::parseProperty(ClassDef *def)
768
QByteArray type = parseType();
771
propDef.designable = propDef.scriptable = propDef.stored = "true";
773
The Q_PROPERTY construct cannot contain any commas, since
774
commas separate macro arguments. We therefore expect users
775
to type "QMap" instead of "QMap<QString, QVariant>". For
776
coherence, we also expect the same for
777
QValueList<QVariant>, the other template class supported by
780
type = normalizeType(type);
782
type = "QMap<QString,QVariant>";
783
else if (type == "QValueList")
784
type = "QValueList<QVariant>";
785
else if (type == "LongLong")
787
else if (type == "ULongLong")
792
propDef.name = lexem();
793
while (test(IDENTIFIER)) {
794
QByteArray l = lexem();
797
v = lexemUntil(RPAREN);
802
v2 = lexemUntil(RPAREN);
803
else if (v != "true" && v != "false")
810
else if (l == "RESET")
811
propDef.reset = v + v2;
816
if (l == "SCRIPTABLE")
817
propDef.scriptable = v + v2;
818
else if (l == "STORED")
819
propDef.stored = v + v2;
823
case 'W': if (l != "WRITE") error(2);
826
case 'D': if (l != "DESIGNABLE") error(2);
827
propDef.designable = v + v2;
829
case 'E': if (l != "EDITABLE") error(2);
830
propDef.editable = v + v2;
832
case 'N': if (l != "NOTIFY") error(2);
839
def->propertyList += propDef;
842
void Moc::parseEnumOrFlag(ClassDef *def, bool isFlag)
845
QByteArray identifier;
846
while (test(IDENTIFIER)) {
847
identifier = lexem();
848
while (test(SCOPE) && test(IDENTIFIER)) {
850
identifier += lexem();
852
def->enumDeclarations[identifier] = isFlag;
857
void Moc::parseFlag(ClassDef *def)
860
QByteArray flagName, enumName;
861
while (test(IDENTIFIER)) {
863
while (test(SCOPE) && test(IDENTIFIER)) {
869
while (test(IDENTIFIER)) {
871
while (test(SCOPE) && test(IDENTIFIER)) {
877
def->flagAliases.insert(enumName, flagName);
881
void Moc::parseClassInfo(ClassDef *def)
884
ClassInfoDef infoDef;
885
next(STRING_LITERAL);
886
infoDef.name = symbol().unquotedLexem();
888
next(STRING_LITERAL);
889
infoDef.value = symbol().unquotedLexem();
890
def->classInfoList += infoDef;
893
void Moc::parseInterfaces(ClassDef *def)
896
while (test(IDENTIFIER)) {
897
QList<ClassDef::Interface> iface;
898
iface += ClassDef::Interface(lexem());
899
while (test(SCOPE)) {
900
iface.last().className += lexem();
902
iface.last().className += lexem();
904
while (test(COLON)) {
906
iface += ClassDef::Interface(lexem());
907
while (test(SCOPE)) {
908
iface.last().className += lexem();
910
iface.last().className += lexem();
913
// resolve from classnames to interface ids
914
for (int i = 0; i < iface.count(); ++i) {
915
const QByteArray iid = interface2IdMap.value(iface.at(i).className);
917
error("Undefined interface");
919
iface[i].interfaceId = iid;
921
def->interfaceList += iface;
926
void Moc::parseDeclareInterface()
929
QByteArray interface;
931
interface += lexem();
932
while (test(SCOPE)) {
933
interface += lexem();
935
interface += lexem();
939
if (test(STRING_LITERAL)) {
940
iid = symbol().lexem();
945
interface2IdMap.insert(interface, iid);
949
void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
954
funcDef.inPrivateClass = lexem();
955
// also allow void functions
958
funcDef.inPrivateClass += "()";
961
funcDef.access = access;
962
parseFunction(&funcDef, true);
963
def->slotList += funcDef;
964
while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
965
funcDef.wasCloned = true;
966
funcDef.arguments.removeLast();
967
def->slotList += funcDef;