File indexing completed on 2024-05-19 05:46:25

0001 #include <cmath>
0002 #include <iostream>
0003 
0004 #include <QFile>
0005 #include <QRegExp>
0006 #include <QString>
0007 #include <QStringList>
0008 
0009 using namespace std;
0010 
0011 const int minPrefixExp = -24;
0012 const int maxPrefixExp = 24;
0013 const int numPrefix = int((maxPrefixExp - minPrefixExp) / 3) + 1;
0014 const QString SIprefix[] = {"y", "z", "a", "f", "p", "n", QChar(0xB5), "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"};
0015 
0016 /**
0017  * Converts a number string (including an optional SI suffix) to a real number.
0018  */
0019 double toReal(QString text);
0020 
0021 const QString inputFile = "spicemodels_bipolar_transistors.txt";
0022 const QString outputFile = "output.lib";
0023 
0024 #define setProperty(property, value) outputStream << QString("%1=%2\n").arg(property).arg(value)
0025 
0026 int main()
0027 {
0028     QFile input(inputFile);
0029     if (!input.open(QIODevice::ReadOnly)) {
0030         cerr << "Could not open input file \"" << inputFile << "\" for reading.\n";
0031         return 1;
0032     }
0033 
0034     QFile output(outputFile);
0035     if (!output.open(QIODevice::WriteOnly)) {
0036         cerr << "Could not open output file \"" << outputFile << "\" for writing.\n";
0037         return 1;
0038     }
0039 
0040     QTextStream inputStream(&input);
0041     QTextStream outputStream(&output);
0042 
0043     QStringList IDs;
0044 
0045     // Set true inside the while loop so when we come across a new model
0046     // in the input file, we can close the previous one in the output file.
0047     bool modelOpen = false;
0048 
0049     while (!inputStream.atEnd()) {
0050         QString line = inputStream.readLine();
0051 
0052         // Make life easier
0053         line.replace(QRegExp("\\.MODEL[^(]*\\("), "+ ");
0054         line.remove(")");
0055 
0056         if (line.isEmpty())
0057             continue;
0058 
0059         if (line.startsWith("*SRC=")) {
0060             if (modelOpen)
0061                 outputStream << "[/]\n\n";
0062             modelOpen = true;
0063 
0064             line.remove(0, 5); // remove "*SRC="
0065 
0066             QStringList segments = line.split(';'); // QStringList::split( ';', line ); // 2018.12.01
0067             if (segments.size() != 5) {
0068                 cerr << "Wrong number of \";\" for line \"" << line.latin1() << "\".\n";
0069                 continue;
0070             }
0071 
0072             QStringList::iterator segmentsEnd = segments.end();
0073             for (QStringList::iterator it = segments.begin(); it != segmentsEnd; ++it)
0074                 *it = (*it).trimmed();
0075 
0076             QString ID = segments[0];
0077             outputStream << QString("[%1]\n").arg(ID);
0078             if (IDs.contains(ID)) {
0079                 cerr << "Already have ID \"" << ID << "\".\n";
0080                 continue;
0081             } else
0082                 IDs.append(ID);
0083 
0084             if (segments[2] == "BJTs PNP")
0085                 setProperty("Type", "PNP");
0086             else if (segments[2] == "BJTs NPN")
0087                 setProperty("Type", "NPN");
0088             else
0089                 cerr << "Unknown type \"" << segments[2] << "\".\n";
0090 
0091             setProperty("Description", segments[4]);
0092         }
0093 
0094         else if (line.startsWith("+ ")) {
0095             line.remove(0, 2); // remove "+ ":
0096             QRegExp rx("([^\\s=]*)=([^\\s]*)");
0097 
0098             int pos = 0;
0099             while ((pos = rx.search(line, pos)) >= 0) {
0100                 QString property = rx.cap(1);
0101                 QString value = rx.cap(2);
0102 
0103                 setProperty(property, toReal(value));
0104 
0105                 pos += 4; // avoid the string we just found
0106             }
0107         }
0108 
0109         else
0110             cerr << "Unknown line for line \"" << line.latin1() << "\".\n";
0111     }
0112 
0113     // And the final closing brace
0114     if (modelOpen)
0115         outputStream << "[/]\n\n";
0116 
0117     input.close();
0118     output.close();
0119 
0120     return 0;
0121 }
0122 
0123 double getMultiplier(QString mag)
0124 {
0125     if (mag.isEmpty())
0126         return 1.0;
0127 
0128     // Allow the user to enter in "u" instead of mu
0129     if (mag == "u")
0130         mag = QChar(0xB5);
0131 
0132     for (int i = 0; i < numPrefix; ++i) {
0133         if (mag == SIprefix[i])
0134             return pow(10., (i * 3) + minPrefixExp);
0135     }
0136 
0137     // default
0138     return 1.0;
0139 }
0140 
0141 double toReal(QString text)
0142 {
0143     if (text.isEmpty()) {
0144         cerr << "Attempted to convert empty text to number.\n";
0145         return 0.0;
0146     }
0147 
0148     // Extract the possible SI suffix
0149     QChar suffix = text[text.length() - 1];
0150     double multiplier = 1.0;
0151     if (suffix.isLetter()) {
0152         multiplier = getMultiplier(QString(suffix));
0153         text.remove(text.length() - 1, 1);
0154     }
0155 
0156     bool ok;
0157     double val = text.toDouble(&ok);
0158 
0159     if (!ok) {
0160         cerr << "Could not convert number string \"" << text << "\" to real.\n";
0161         return 0.0;
0162     }
0163 
0164     return val * multiplier;
0165 }