00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "idlimport.h"
00014
00015 #include <stdio.h>
00016
00017
00018 #include <qstringlist.h>
00019 #include <qregexp.h>
00020 #include <kdebug.h>
00021
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
00053 if (line.startsWith("#"))
00054 return true;
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
00067 lexeme += "::";
00068 i++;
00069 } else if (c == '<') {
00070
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
00095 QString command("cpp -C");
00096 for (QStringList::Iterator pathIt = includePaths.begin();
00097 pathIt != includePaths.end(); ++pathIt) {
00098 QString path = (*pathIt);
00099
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
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
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
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() == ";")
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
00195 skipStmt("}");
00196 m_srcIndex++;
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++;
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" );
00218
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() == ";")
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++;
00285 return true;
00286 }
00287 if (keyword == ";")
00288 return true;
00289
00290
00291
00292
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
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
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();
00335 return true;
00336 }
00337
00338 while (1) {
00339 while (nextToken != "," && nextToken != ";") {
00340 name += nextToken;
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