00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "pascalimport.h"
00014
00015 #include <stdio.h>
00016
00017 #include <qregexp.h>
00018 #include <kdebug.h>
00019
00020 #include "import_utils.h"
00021 #include "../uml.h"
00022 #include "../umldoc.h"
00023 #include "../package.h"
00024 #include "../classifier.h"
00025 #include "../enum.h"
00026 #include "../operation.h"
00027 #include "../attribute.h"
00028
00029 PascalImport::PascalImport() : NativeImportBase("//") {
00030 setMultiLineComment("(*", "*)");
00031 setMultiLineAltComment("{", "}");
00032 initVars();
00033 }
00034
00035 PascalImport::~PascalImport() {
00036 }
00037
00038 void PascalImport::initVars() {
00039 m_inInterface = false;
00040 m_section = sect_NONE;
00041 NativeImportBase::m_currentAccess = Uml::Visibility::Public;
00042 }
00043
00044 void PascalImport::fillSource(const QString& word) {
00045 QString lexeme;
00046 const uint len = word.length();
00047 for (uint i = 0; i < len; i++) {
00048 QChar c = word[i];
00049 if (c.isLetterOrNumber() || c == '_' || c == '.' || c == '#') {
00050 lexeme += c;
00051 } else {
00052 if (!lexeme.isEmpty()) {
00053 m_source.append(lexeme);
00054 lexeme = QString();
00055 }
00056 if (c == ':' && word[i + 1] == '=') {
00057 m_source.append(":=");
00058 i++;
00059 } else {
00060 m_source.append(QString(c));
00061 }
00062 }
00063 }
00064 if (!lexeme.isEmpty())
00065 m_source.append(lexeme);
00066 }
00067
00068 void PascalImport::checkModifiers(bool& isVirtual, bool& isAbstract) {
00069 const uint srcLength = m_source.count();
00070 while (m_srcIndex < srcLength - 1) {
00071 QString lookAhead = m_source[m_srcIndex + 1].lower();
00072 if (lookAhead != "virtual" && lookAhead != "abstract" &&
00073 lookAhead != "override" &&
00074 lookAhead != "register" && lookAhead != "cdecl" &&
00075 lookAhead != "pascal" && lookAhead != "stdcall" &&
00076 lookAhead != "safecall" && lookAhead != "saveregisters" &&
00077 lookAhead != "popstack")
00078 break;
00079 if (lookAhead == "abstract")
00080 isAbstract = true;
00081 else if (lookAhead == "virtual")
00082 isVirtual = true;
00083 advance();
00084 skipStmt();
00085 }
00086 }
00087
00088 bool PascalImport::parseStmt() {
00089 const uint srcLength = m_source.count();
00090 QString keyword = m_source[m_srcIndex].lower();
00091
00092 if (keyword == "uses") {
00093 while (m_srcIndex < srcLength - 1) {
00094 QString unit = advance();
00095 const QString& prefix = unit.lower();
00096 if (prefix == "sysutils" || prefix == "types" || prefix == "classes" ||
00097 prefix == "graphics" || prefix == "controls" || prefix == "strings" ||
00098 prefix == "forms" || prefix == "windows" || prefix == "messages" ||
00099 prefix == "variants" || prefix == "stdctrls" || prefix == "extctrls" ||
00100 prefix == "activex" || prefix == "comobj" || prefix == "registry" ||
00101 prefix == "classes" || prefix == "dialogs") {
00102 if (advance() != ",")
00103 break;
00104 continue;
00105 }
00106 QString filename = unit + ".pas";
00107 if (! m_parsedFiles.contains(unit)) {
00108
00109 QStringList source(m_source);
00110 uint srcIndex = m_srcIndex;
00111 m_source.clear();
00112 parseFile(filename);
00113
00114 m_source = source;
00115 m_srcIndex = srcIndex;
00116
00117
00118 m_currentAccess = Uml::Visibility::Public;
00119 }
00120 if (advance() != ",")
00121 break;
00122 }
00123 return true;
00124 }
00125 if (keyword == "unit") {
00126 const QString& name = advance();
00127 UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package, name,
00128 m_scope[m_scopeIndex], m_comment);
00129 m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns);
00130 skipStmt();
00131 return true;
00132 }
00133 if (keyword == "interface") {
00134 m_inInterface = true;
00135 return true;
00136 }
00137 if (keyword == "initialization" || keyword == "implementation") {
00138 m_inInterface = false;
00139 return true;
00140 }
00141 if (! m_inInterface) {
00142
00143 return false;
00144 }
00145 if (keyword == "label") {
00146 m_section = sect_LABEL;
00147 return true;
00148 }
00149 if (keyword == "const") {
00150 m_section = sect_CONST;
00151 return true;
00152 }
00153 if (keyword == "resourcestring") {
00154 m_section = sect_RESOURCESTRING;
00155 return true;
00156 }
00157 if (keyword == "type") {
00158 m_section = sect_TYPE;
00159 return true;
00160 }
00161 if (keyword == "var") {
00162 m_section = sect_VAR;
00163 return true;
00164 }
00165 if (keyword == "threadvar") {
00166 m_section = sect_THREADVAR;
00167 return true;
00168 }
00169 if (keyword == "automated" || keyword == "published"
00170 || keyword == "public") {
00171 m_currentAccess = Uml::Visibility::Public;
00172 return true;
00173 }
00174 if (keyword == "protected") {
00175 m_currentAccess = Uml::Visibility::Protected;
00176 return true;
00177 }
00178 if (keyword == "private") {
00179 m_currentAccess = Uml::Visibility::Private;
00180 return true;
00181 }
00182 if (keyword == "packed") {
00183 return true;
00184 }
00185 if (keyword == "[") {
00186 skipStmt("]");
00187 return true;
00188 }
00189 if (keyword == "end") {
00190 if (m_klass) {
00191 m_klass = NULL;
00192 } else if (m_scopeIndex) {
00193 m_scopeIndex--;
00194 m_currentAccess = Uml::Visibility::Public;
00195 } else {
00196 kError() << "importPascal: too many \"end\"" << endl;
00197 }
00198 skipStmt();
00199 return true;
00200 }
00201 if (keyword == "function" || keyword == "procedure" ||
00202 keyword == "constructor" || keyword == "destructor") {
00203 if (m_klass == NULL) {
00204
00205
00206
00207 bool dummyVirtual = false;
00208 bool dummyAbstract = false;
00209 checkModifiers(dummyVirtual, dummyAbstract);
00210 return true;
00211 }
00212 const QString& name = advance();
00213 UMLOperation *op = Import_Utils::makeOperation(m_klass, name);
00214 if (m_source[m_srcIndex + 1] == "(") {
00215 advance();
00216 const uint MAX_PARNAMES = 16;
00217 while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
00218 QString nextToken = m_source[m_srcIndex + 1].lower();
00219 Uml::Parameter_Direction dir = Uml::pd_In;
00220 if (nextToken == "var") {
00221 dir = Uml::pd_InOut;
00222 advance();
00223 } else if (nextToken == "const") {
00224 advance();
00225 } else if (nextToken == "out") {
00226 dir = Uml::pd_Out;
00227 advance();
00228 }
00229 QString parName[MAX_PARNAMES];
00230 uint parNameCount = 0;
00231 do {
00232 if (parNameCount >= MAX_PARNAMES) {
00233 kError() << "MAX_PARNAMES is exceeded at " << name << endl;
00234 break;
00235 }
00236 parName[parNameCount++] = advance();
00237 } while (advance() == ",");
00238 if (m_source[m_srcIndex] != ":") {
00239 kError() << "importPascal: expecting ':' at " << m_source[m_srcIndex] << endl;
00240 skipStmt();
00241 break;
00242 }
00243 nextToken = advance();
00244 if (nextToken.lower() == "array") {
00245 nextToken = advance().lower();
00246 if (nextToken != "of") {
00247 kError() << "importPascal(" << name << "): expecting 'array OF' at "
00248 << nextToken << endl;
00249 skipStmt();
00250 return false;
00251 }
00252 nextToken = advance();
00253 }
00254 for (uint i = 0; i < parNameCount; i++) {
00255 UMLAttribute *att = Import_Utils::addMethodParameter(op, nextToken, parName[i]);
00256 att->setParmKind(dir);
00257 }
00258 if (advance() != ";")
00259 break;
00260 }
00261 }
00262 QString returnType;
00263 if (keyword == "function") {
00264 if (advance() != ":") {
00265 kError() << "importPascal: expecting \":\" at function "
00266 << name << endl;
00267 return false;
00268 }
00269 returnType = advance();
00270 } else if (keyword == "constructor" || keyword == "destructor") {
00271 op->setStereotype(keyword);
00272 }
00273 skipStmt();
00274 bool isVirtual = false;
00275 bool isAbstract = false;
00276 checkModifiers(isVirtual, isAbstract);
00277 Import_Utils::insertMethod(m_klass, op, m_currentAccess, returnType,
00278 !isVirtual, isAbstract, false, false, m_comment);
00279 return true;
00280 }
00281 if (m_section != sect_TYPE) {
00282 skipStmt();
00283 return true;
00284 }
00285 if (m_klass == NULL) {
00286 const QString& name = m_source[m_srcIndex];
00287 QString nextToken = advance();
00288 if (nextToken != "=") {
00289 kDebug() << "PascalImport::parseStmt(" << name << "): "
00290 << "expecting '=' at " << nextToken << endl;
00291 return false;
00292 }
00293 keyword = advance().lower();
00294 if (keyword == "(") {
00295
00296 UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Enum,
00297 name, m_scope[m_scopeIndex], m_comment);
00298 UMLEnum *enumType = static_cast<UMLEnum*>(ns);
00299 while (++m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
00300 Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]);
00301 if (advance() != ",")
00302 break;
00303 }
00304 skipStmt();
00305 return true;
00306 }
00307 if (keyword == "set") {
00308 skipStmt();
00309 return true;
00310 }
00311 if (keyword == "array") {
00312 skipStmt();
00313 return true;
00314 }
00315 if (keyword == "file") {
00316 skipStmt();
00317 return true;
00318 }
00319 if (keyword == "^") {
00320 skipStmt();
00321 return true;
00322 }
00323 if (keyword == "class" || keyword == "interface") {
00324 Uml::Object_Type t = (keyword == "class" ? Uml::ot_Class : Uml::ot_Interface);
00325 UMLObject *ns = Import_Utils::createUMLObject(t, name,
00326 m_scope[m_scopeIndex], m_comment);
00327 UMLClassifier *klass = static_cast<UMLClassifier*>(ns);
00328 m_comment = QString();
00329 QString lookAhead = m_source[m_srcIndex + 1];
00330 if (lookAhead == "(") {
00331 advance();
00332 do {
00333 QString base = advance();
00334 UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class, base, NULL);
00335 UMLClassifier *parent = static_cast<UMLClassifier*>(ns);
00336 m_comment = QString();
00337 Import_Utils::createGeneralization(klass, parent);
00338 } while (advance() == ",");
00339 if (m_source[m_srcIndex] != ")") {
00340 kError() << "PascalImport: expecting \")\" at "
00341 << m_source[m_srcIndex] << endl;
00342 return false;
00343 }
00344 lookAhead = m_source[m_srcIndex + 1];
00345 }
00346 if (lookAhead == ";") {
00347 skipStmt();
00348 return true;
00349 }
00350 if (lookAhead == "of") {
00351
00352 return false;
00353 }
00354 m_klass = klass;
00355 m_currentAccess = Uml::Visibility::Public;
00356 return true;
00357 }
00358 if (keyword == "record") {
00359 UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class, name,
00360 m_scope[m_scopeIndex], m_comment);
00361 ns->setStereotype("record");
00362 m_klass = static_cast<UMLClassifier*>(ns);
00363 return true;
00364 }
00365 if (keyword == "function" || keyword == "procedure") {
00366 UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Datatype, name,
00367 m_scope[m_scopeIndex], m_comment);
00368 if (m_source[m_srcIndex + 1] == "(")
00369 skipToClosing('(');
00370 skipStmt();
00371 return true;
00372 }
00373
00374 return false;
00375 }
00376
00377 if (m_klass == NULL) {
00378 kDebug() << "importPascal: skipping " << m_source[m_srcIndex] << endl;
00379 skipStmt();
00380 return true;
00381 }
00382 QString name, stereotype;
00383 if (keyword == "property") {
00384 stereotype = keyword;
00385 name = advance();
00386 } else {
00387 name = m_source[m_srcIndex];
00388 }
00389 if (advance() != ":") {
00390 kError() << "PascalImport: expecting \":\" at " << name << " "
00391 << m_source[m_srcIndex] << endl;
00392 skipStmt();
00393 return true;
00394 }
00395 QString typeName = advance();
00396 QString initialValue;
00397 if (advance() == "=") {
00398 initialValue = advance();
00399 QString token;
00400 while ((token = advance()) != ";") {
00401 initialValue.append(' ' + token);
00402 }
00403 }
00404 UMLObject *o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name,
00405 typeName, m_comment);
00406 UMLAttribute *attr = static_cast<UMLAttribute*>(o);
00407 attr->setStereotype(stereotype);
00408 attr->setInitialValue(initialValue);
00409 skipStmt();
00410 return true;
00411 }
00412
00413