umbrello API Documentation

idlimport.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *  copyright (C) 2005                                                     *
00009  *  Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                   *
00010  ***************************************************************************/
00011 
00012 // own header
00013 #include "idlimport.h"
00014 
00015 #include <stdio.h>
00016 // qt/kde includes
00017 // #include <qprocess.h>  //should use this instead of popen()
00018 #include <qstringlist.h>
00019 #include <qregexp.h>
00020 #include <kdebug.h>
00021 // app includes
00022 #include "import_utils.h"
00023 #include "../uml.h"
00024 #include "../umldoc.h"
00025 #include "../umlpackagelist.h"
00026 #include "../package.h"
00027 #include "../classifier.h"
00028 #include "../enum.h"
00029 #include "../operation.h"
00030 #include "../attribute.h"
00031 
00032 IDLImport::IDLImport() : NativeImportBase("//") {
00033     m_isOneway = m_isReadonly = m_isAttribute = false;
00034     setMultiLineComment("/*", "*/");
00035 }
00036 
00037 IDLImport::~IDLImport() {
00038 }
00039 
00041 QString IDLImport::joinTypename() {
00042     QString typeName = m_source[m_srcIndex];
00043     if (m_source[m_srcIndex] == "unsigned")
00044         typeName += ' ' + advance();
00045     if (m_source[m_srcIndex] == "long" &&
00046             (m_source[m_srcIndex + 1] == "long" || m_source[m_srcIndex + 1] == "double"))
00047         typeName += ' ' + advance();
00048     return typeName;
00049 }
00050 
00051 bool IDLImport::preprocess(QString& line) {
00052     // Ignore C preprocessor generated lines.
00053     if (line.startsWith("#"))
00054         return true;  // done
00055     return NativeImportBase::preprocess(line);
00056 }
00057 
00058 void IDLImport::fillSource(const QString& word) {
00059     QString lexeme;
00060     const uint len = word.length();
00061     for (uint i = 0; i < len; i++) {
00062         QChar c = word[i];
00063         if (c.isLetterOrNumber() || c == '_') {
00064             lexeme += c;
00065         } else if (c == ':' && word[i + 1] == ':') {
00066             // compress scoped name into lexeme
00067             lexeme += "::";
00068             i++;
00069         } else if (c == '<') {
00070             // compress sequence or bounded string into lexeme
00071             do {
00072                 lexeme += word[i];
00073             } while (word[i] != '>' && ++i < len);
00074         } else {
00075             if (!lexeme.isEmpty()) {
00076                 m_source.append(lexeme);
00077                 lexeme = QString();
00078             }
00079             m_source.append(QString(c));
00080         }
00081     }
00082     if (!lexeme.isEmpty())
00083         m_source.append(lexeme);
00084 }
00085 
00086 void IDLImport::parseFile(const QString& filename) {
00087     if (filename.contains('/')) {
00088         QString path = filename;
00089         path.remove( QRegExp("/[^/]+$") );
00090         kDebug() << "IDLImport::parseFile: adding path " << path << endl;
00091         Import_Utils::addIncludePath(path);
00092     }
00093     QStringList includePaths = Import_Utils::includePathList();
00094     //QProcess command("cpp", UMLAp::app());
00095     QString command("cpp -C");   // -C means "preserve comments"
00096     for (QStringList::Iterator pathIt = includePaths.begin();
00097             pathIt != includePaths.end(); ++pathIt) {
00098         QString path = (*pathIt);
00099         //command.addArgument(" -I" + path);
00100         command += " -I" + path;
00101     }
00102     command += ' ' + filename;
00103     kDebug() << "importIDL: " << command << endl;
00104     FILE *fp = popen(command.ascii(), "r");
00105     if (fp == NULL) {
00106         kError() << "IDLImport::parseFile: cannot popen(" << command << ")" << endl;
00107         return;
00108     }
00109     // Scan the input file into the QStringList m_source.
00110     m_source.clear();
00111     char buf[256];
00112     while (fgets(buf, sizeof(buf), fp) != NULL) {
00113         int len = strlen(buf);
00114         if (buf[len - 1] == '\n')
00115             buf[--len] = '\0';
00116         NativeImportBase::scan( QString(buf) );
00117     }
00118     // Parse the QStringList m_source.
00119     m_scopeIndex = 0;
00120     m_scope[0] = NULL;
00121     const uint srcLength = m_source.count();
00122     for (m_srcIndex = 0; m_srcIndex < srcLength; m_srcIndex++) {
00123         const QString& keyword = m_source[m_srcIndex];
00124         //kDebug() << '"' << keyword << '"' << endl;
00125         if (keyword.startsWith(m_singleLineCommentIntro)) {
00126             m_comment = keyword.mid(m_singleLineCommentIntro.length());
00127             continue;
00128         }
00129         if (! parseStmt())
00130             skipStmt();
00131         m_currentAccess = Uml::Visibility::Public;
00132         m_comment = QString();
00133     }
00134     pclose(fp);
00135 }
00136 
00137 bool IDLImport::parseStmt() {
00138     const QString& keyword = m_source[m_srcIndex];
00139     const uint srcLength = m_source.count();
00140     if (keyword == "module") {
00141         const QString& name = advance();
00142         UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package,
00143                         name, m_scope[m_scopeIndex], m_comment);
00144         m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns);
00145         m_scope[m_scopeIndex]->setStereotype("CORBAModule");
00146         if (advance() != "{") {
00147             kError() << "importIDL: unexpected: " << m_source[m_srcIndex] << endl;
00148             skipStmt("{");
00149         }
00150         return true;
00151     }
00152     if (keyword == "interface") {
00153         const QString& name = advance();
00154         UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class,
00155                         name, m_scope[m_scopeIndex], m_comment);
00156         m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
00157         m_klass->setStereotype("CORBAInterface");
00158         m_klass->setAbstract(m_isAbstract);
00159         m_isAbstract = false;
00160         m_comment = QString();
00161         if (advance() == ";")   // forward declaration
00162             return true;
00163         if (m_source[m_srcIndex] == ":") {
00164             while (++m_srcIndex < srcLength && m_source[m_srcIndex] != "{") {
00165                 const QString& baseName = m_source[m_srcIndex];
00166                 Import_Utils::createGeneralization(m_klass, baseName);
00167                 if (advance() != ",")
00168                     break;
00169             }
00170         }
00171         if (m_source[m_srcIndex] != "{") {
00172             kError() << "importIDL: ignoring excess chars at "
00173             << name << endl;
00174             skipStmt("{");
00175         }
00176         return true;
00177     }
00178     if (keyword == "struct" || keyword == "exception") {
00179         const QString& name = advance();
00180         UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class,
00181                         name, m_scope[m_scopeIndex], m_comment);
00182         m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
00183         if (keyword == "struct")
00184             m_klass->setStereotype("CORBAStruct");
00185         else
00186             m_klass->setStereotype("CORBAException");
00187         if (advance() != "{") {
00188             kError() << "importIDL: expecting '{' at " << name << endl;
00189             skipStmt("{");
00190         }
00191         return true;
00192     }
00193     if (keyword == "union") {
00194         // TBD. <gulp>
00195         skipStmt("}");
00196         m_srcIndex++;  // advance to ';'
00197         return true;
00198     }
00199     if (keyword == "enum") {
00200         const QString& name = advance();
00201         UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Enum,
00202                         name, m_scope[m_scopeIndex], m_comment);
00203         UMLEnum *enumType = static_cast<UMLEnum*>(ns);
00204         m_srcIndex++;  // skip name
00205         while (++m_srcIndex < srcLength && m_source[m_srcIndex] != "}") {
00206             Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]);
00207             if (advance() != ",")
00208                 break;
00209         }
00210         skipStmt();
00211         return true;
00212     }
00213     if (keyword == "typedef") {
00214         const QString& existingType = advance();
00215         const QString& newType = advance();
00216         Import_Utils::createUMLObject(Uml::ot_Class, newType, m_scope[m_scopeIndex],
00217                                      m_comment, "CORBATypedef" /* stereotype */);
00218         // @todo How do we convey the existingType ?
00219         skipStmt();
00220         return true;
00221     }
00222     if (keyword == "const") {
00223         skipStmt();
00224         return true;
00225     }
00226     if (keyword == "custom") {
00227         return true;
00228     }
00229     if (keyword == "abstract") {
00230         m_isAbstract = true;
00231         return true;
00232     }
00233     if (keyword == "valuetype") {
00234         const QString& name = advance();
00235         UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class,
00236                         name, m_scope[m_scopeIndex], m_comment);
00237         m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
00238         m_klass->setAbstract(m_isAbstract);
00239         m_isAbstract = false;
00240         if (advance() == ";")   // forward declaration
00241             return true;
00242         if (m_source[m_srcIndex] == ":") {
00243             if (advance() == "truncatable")
00244                 m_srcIndex++;
00245             while (m_srcIndex < srcLength && m_source[m_srcIndex] != "{") {
00246                 const QString& baseName = m_source[m_srcIndex];
00247                 Import_Utils::createGeneralization(m_klass, baseName);
00248                 if (advance() != ",")
00249                     break;
00250                 m_srcIndex++;
00251             }
00252         }
00253         if (m_source[m_srcIndex] != "{") {
00254             kError() << "importIDL: ignoring excess chars at "
00255             << name << endl;
00256             skipStmt("{");
00257         }
00258         return true;
00259     }
00260     if (keyword == "public") {
00261         return true;
00262     }
00263     if (keyword == "private") {
00264         m_currentAccess = Uml::Visibility::Private;
00265         return true;
00266     }
00267     if (keyword == "readonly") {
00268         m_isReadonly = true;
00269         return true;
00270     }
00271     if (keyword == "attribute") {
00272         m_isAttribute = true;
00273         return true;
00274     }
00275     if (keyword == "oneway") {
00276         m_isOneway = true;
00277         return true;
00278     }
00279     if (keyword == "}") {
00280         if (m_scopeIndex)
00281             m_klass = dynamic_cast<UMLClassifier*>(m_scope[--m_scopeIndex]);
00282         else
00283             kError() << "importIDL: too many }" << endl;
00284         m_srcIndex++;  // skip ';'
00285         return true;
00286     }
00287     if (keyword == ";")
00288         return true;
00289     // At this point, we expect `keyword' to be a type name
00290     // (of a member of struct or valuetype, or return type
00291     // of an operation.) Up next is the name of the attribute
00292     // or operation.
00293     if (! keyword.contains( QRegExp("^\\w") )) {
00294         kError() << "importIDL: ignoring " << keyword << endl;
00295         return false;
00296     }
00297     QString typeName = joinTypename();
00298     QString name = advance();
00299     if (name.contains( QRegExp("\\W") )) {
00300         kError() << "importIDL: expecting name in " << name << endl;
00301         return false;
00302     }
00303     // At this point we most definitely need a class.
00304     if (m_klass == NULL) {
00305         kError() << "importIDL: no class set for " << name << endl;
00306         return false;
00307     }
00308     QString nextToken = advance();
00309     if (nextToken == "(") {
00310         // operation
00311         UMLOperation *op = Import_Utils::makeOperation(m_klass, name);
00312         m_srcIndex++;
00313         while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
00314             const QString &direction = m_source[m_srcIndex++];
00315             QString typeName = joinTypename();
00316             const QString &parName = advance();
00317             UMLAttribute *att = Import_Utils::addMethodParameter(op, typeName, parName);
00318             Uml::Parameter_Direction dir;
00319             if (Model_Utils::stringToDirection(direction, dir))
00320                 att->setParmKind(dir);
00321             else
00322                 kError() << "importIDL: expecting parameter direction at "
00323                 << direction << endl;
00324             if (advance() != ",")
00325                 break;
00326             m_srcIndex++;
00327         }
00328         Import_Utils::insertMethod(m_klass, op, Uml::Visibility::Public, typeName,
00329                                   false, false, false, false, m_comment);
00330         if (m_isOneway) {
00331             op->setStereotype("oneway");
00332             m_isOneway = false;
00333         }
00334         skipStmt();  // skip possible "raises" clause
00335         return true;
00336     }
00337     // At this point we know it's some kind of attribute declaration.
00338     while (1) {
00339         while (nextToken != "," && nextToken != ";") {
00340             name += nextToken;  // add possible array dimensions to `name'
00341             nextToken = advance();
00342         }
00343         UMLObject *o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, typeName, m_comment);
00344         UMLAttribute *attr = static_cast<UMLAttribute*>(o);
00345         if (m_isReadonly) {
00346             attr->setStereotype("readonly");
00347             m_isReadonly = false;
00348         }
00349         if (nextToken != ",")
00350             break;
00351         name = advance();
00352         nextToken = advance();
00353     }
00354     return true;
00355 }
00356 
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:57 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003