File indexing completed on 2024-04-21 04:36:20

0001 /* This file is part of kdev-pg-qt
0002    Copyright (C) 2005 Roberto Raggi <roberto@kdevelop.org>
0003    Copyright (C) 2006 Jakob Petsovits <jpetso@gmx.at>
0004    Copyright (C) 2006 Alexander Dymo <adymo@kdevelop.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019    Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #ifndef KDEV_PG_H
0023 #define KDEV_PG_H
0024 
0025 #include "kdev-pg-ast.h"
0026 
0027 #include <QSet>
0028 #include <QMap>
0029 #include <QList>
0030 #include <QFile>
0031 #include <QString>
0032 #include <QStringList>
0033 #include <QMultiMap>
0034 #include <QtGlobal>
0035 #include <QTextStream>
0036 
0037 #include <vector>
0038 #include <algorithm>
0039 
0040 namespace KDevPG
0041 {
0042   class GNFA;
0043   class GDFA;
0044   void deleteNFA(GNFA*);
0045   void deleteDFA(GDFA*);
0046   Model::ZeroItem *zero();
0047   Model::PlusItem *plus(Model::Node *item);
0048   Model::StarItem *star(Model::Node *item);
0049   Model::SymbolItem *symbol(const QString& name);
0050   Model::ActionItem *action(Model::Node *item, const QString& code);
0051   Model::AlternativeItem *alternative(Model::Node *left, Model::Node *right);
0052   Model::ConsItem *cons(Model::Node *left, Model::Node *right);
0053   Model::EvolveItem *evolve(
0054       Model::Node *item, Model::SymbolItem *symbol,
0055       Model::VariableDeclarationItem *declarations, const QString& code
0056   );
0057   Model::TryCatchItem *tryCatch(Model::Node *try_item, Model::Node *catch_item);
0058   Model::AliasItem *alias(const QString& code, Model::SymbolItem *symbol);
0059   Model::TerminalItem *terminal(const QString& name, const QString& description);
0060   Model::NonTerminalItem *nonTerminal(Model::SymbolItem *symbol, const QString& arguments);
0061   Model::InlinedNonTerminalItem *inlinedNonTerminal(Model::SymbolItem *symbol);
0062   Model::ConditionItem *condition(const QString& code, Model::Node *item);
0063   Model::AnnotationItem *annotation(
0064       const QString& name, Model::Node *item, bool isSequence,
0065       Model::VariableDeclarationItem::StorageType storageType
0066   );
0067   Model::VariableDeclarationItem *variableDeclaration(
0068       Model::VariableDeclarationItem::DeclarationType declarationType,
0069       Model::VariableDeclarationItem::StorageType     storageType,
0070       Model::VariableDeclarationItem::VariableType    variableType,
0071       bool isSequence, const QString& name, const QString& type
0072   );
0073   bool isOperatorSymbol(Model::SymbolItem *node);
0074   Settings::MemberItem *member(Settings::MemberItem::MemberKind kind, const QString& code);
0075   
0076   Model::Operator *makeOperator(Model::Node *tok, const QString& cond, const QString& code);
0077   
0078   inline void capitalize(QString& str)
0079   {
0080     if(!str.isEmpty())
0081       str.replace(0, 1, str.at(0).toUpper());
0082   }
0083   
0084   inline QString capitalized(const QString& str)
0085   {
0086     QString ret(str);
0087     capitalize(ret);
0088     return ret;
0089   }
0090   
0091   QString unescaped(const QByteArray& str);
0092   
0093 class World
0094 {
0095 public:
0096   struct MemberCode {
0097     QList<Settings::MemberItem*> declarations;
0098     QList<Settings::MemberItem*> constructorCode;
0099     QList<Settings::MemberItem*> destructorCode;
0100   };
0101   typedef QSet<Model::Node*> NodeSet;
0102   typedef QMap<QString, Model::SymbolItem*> SymbolSet;
0103   typedef QMap<QString, Model::TerminalItem*> TerminalSet;
0104   typedef QMultiMap<Model::SymbolItem*, Model::EvolveItem*> Environment;
0105   typedef QMultiMap<QString, QString> NamespaceSet;
0106 
0107   typedef QMap<QPair<Model::Node*, int>, NodeSet> FirstSet;
0108   typedef QMap<QPair<Model::Node*, int>, NodeSet> FollowSet;
0109 
0110   /**pair: list of rules whose FIRST set is used to calculate FOLLOW,
0111   list of rules whose FOLLOW set is used to calculate FOLLOW*/
0112   typedef QPair<NodeSet, NodeSet> FollowDep;
0113   /**key: rule whose FOLLOW set has a dependency on other rules' FIRST and FOLLOW,
0114   value: follow set dependency*/
0115   typedef QMap<Model::Node*, FollowDep> FollowDeps;
0116 
0117   typedef QMap<QString, QString> AstBaseClasses;
0118 
0119   World()
0120     : tokenStream("KDevPG::TokenStream"), language(), ns(), decl(), bits(),
0121       exportMacro(""), exportMacroHeader(), astCode(""), namespaceCode(""),
0122       inputStream("KDevPG::QUtf16ToUcs4Iterator"),
0123       generateAst(true), hasLexer(false), generateSerializeVisitor(false),
0124       generateDebugVisitor(false), generateTokenText(false),
0125       needStateManagement(false), needOperatorStack(false),
0126       lineNumberPolicy(FullLineNumbers), visitorTable(false),
0127       conflictHandling(Permissive), mZero(nullptr),
0128       lexerBaseClass("KDevPG::TokenStream")
0129   {}
0130   
0131   ~World()
0132   {
0133     for(auto i = regexpById.begin(); i != regexpById.end(); ++i)
0134       deleteNFA(*i);
0135     for(auto i = lexerEnvResults.begin(); i != lexerEnvResults.end(); ++i)
0136       deleteNFA(*i);
0137     for(auto i = dfaForNfa.begin(); i != dfaForNfa.end(); ++i)
0138       deleteDFA(*i);
0139   }
0140 
0141   // options
0142   QString tokenStream;
0143   QString language;
0144   QString ns;
0145   QString decl;
0146   QString bits;
0147   QString lexerBits;
0148   QString exportMacro;
0149   QString exportMacroHeader;
0150   QString astCode;
0151   QString namespaceCode;
0152   QStringList parserDeclarationHeaders;
0153   QStringList parserBitsHeaders;
0154   QStringList astHeaders;
0155   QStringList lexerDeclarationHeaders;
0156   QStringList lexerBitsHeaders;
0157   QString inputStream;
0158   bool generateAst: 1;
0159   bool hasLexer: 1;
0160   bool generateSerializeVisitor: 1;
0161   bool generateDebugVisitor: 1;
0162   bool generateTokenText: 1;
0163   bool needStateManagement: 1;
0164   bool needOperatorStack: 1;
0165   enum { BeautifulCode, CompatibilityLineNumbers, FullLineNumbers } lineNumberPolicy;
0166   bool beautifulCode: 1;
0167   bool visitorTable: 1;
0168   enum { Ignore = 0, Permissive = 1, Strict = 2 } conflictHandling: 2;
0169 
0170   Model::ZeroItem *zero()
0171   {
0172     if (!mZero)
0173       mZero = KDevPG::zero();
0174     return mZero;
0175   }
0176 
0177   Model::TerminalItem *terminal(QString __name)
0178   {
0179     QString name = __name;
0180     TerminalSet::iterator it = terminals.find(name);
0181     if (it == terminals.end())
0182       return KDevPG::terminal(__name, __name);
0183 
0184     return (*it);
0185   }
0186 
0187   void pushRule(Model::Node *rule)
0188   {
0189     Model::EvolveItem *e = nodeCast<Model::EvolveItem*>(rule);
0190     Q_ASSERT(e != nullptr);
0191 
0192     rules.push_back(e);
0193   }
0194 
0195   void pushParserClassMember(Model::Node *member)
0196   {
0197     Settings::MemberItem *m = nodeCast<Settings::MemberItem*>(member);
0198     Q_ASSERT(m != nullptr);
0199 
0200     if (m->mMemberKind == Settings::MemberItem::ConstructorCode)
0201       parserclassMembers.constructorCode.push_back(m);
0202     else if (m->mMemberKind == Settings::MemberItem::DestructorCode)
0203       parserclassMembers.destructorCode.push_back(m);
0204     else // public, protected or private declaration
0205       parserclassMembers.declarations.push_back(m);
0206   }
0207   
0208   void pushLexerClassMember(Model::Node *member)
0209   {
0210     Settings::MemberItem *m = nodeCast<Settings::MemberItem*>(member);
0211     Q_ASSERT(m != nullptr);
0212     
0213     if (m->mMemberKind == Settings::MemberItem::ConstructorCode)
0214       lexerclassMembers.constructorCode.push_back(m);
0215     else if (m->mMemberKind == Settings::MemberItem::DestructorCode)
0216       lexerclassMembers.destructorCode.push_back(m);
0217     else // public, protected or private declaration
0218       lexerclassMembers.declarations.push_back(m);
0219   }
0220   
0221   Model::TerminalItem *pushTerminal(QString __name, QString __description)
0222   {
0223     QString name = __name;
0224     TerminalSet::iterator it = terminals.find(name);
0225     if (it == terminals.end())
0226       it = terminals.insert(name, KDevPG::terminal(__name, __description));
0227 
0228     return (*it);
0229   }
0230 
0231   Model::SymbolItem *pushSymbol(QString __name)
0232   {
0233     QString name = __name;
0234     SymbolSet::iterator it = symbols.find(name);
0235     
0236     if (it == symbols.end())
0237     {
0238       it = symbols.insert(name, KDevPG::symbol(__name));
0239       start.insert(*it);
0240     }
0241     else
0242       start.remove(*it);
0243 
0244     return (*it);
0245   }
0246 
0247   void pushParserDeclarationHeader(QString file)
0248   {
0249     parserDeclarationHeaders << file;
0250   }
0251 
0252   void pushParserBitsHeader(QString file)
0253   {
0254     parserBitsHeaders << file;
0255   }
0256 
0257   void pushAstHeader(QString file)
0258   {
0259     astHeaders << file;
0260   }
0261   
0262   void pushLexerBitsHeader(QString file)
0263   {
0264     lexerBitsHeaders << file;
0265   }
0266   
0267   void pushLexerDeclarationHeader(QString file)
0268   {
0269     lexerDeclarationHeaders << file;
0270   }
0271   
0272   inline static bool ruleComp(Model::Node *a, Model::Node *b)
0273   {
0274     if(a != nullptr && a->kind == Model::NodeKindEvolve)
0275       a = ((Model::EvolveItem*)a)->mSymbol;
0276     if(b != nullptr && b->kind == Model::NodeKindEvolve)
0277       b = ((Model::EvolveItem*)b)->mSymbol;
0278     return a < b;
0279   }
0280   
0281   void finishedParsing()
0282   {
0283     std::sort(rules.begin(), rules.end(), &ruleComp);
0284   }
0285   
0286   Model::EvolveItem *searchRule(Model::SymbolItem *sym)
0287   {
0288     auto i = std::lower_bound(rules.begin(), rules.end(), sym, &ruleComp);
0289     if(i == rules.end() || (*i)->mSymbol != sym)
0290       return nullptr;
0291     return *i;
0292   }
0293 
0294   FirstSet::iterator firstBegin() { return firstSet.begin(); }
0295   FirstSet::iterator firstEnd() { return firstSet.end(); }
0296 
0297   FollowSet::iterator followBegin() { return followSet.begin(); }
0298   FollowSet::iterator followEnd() { return followSet.end(); }
0299 
0300   NodeSet &first(Model::Node *node, int K = 1)
0301   { return firstSet[qMakePair(node, K)]; }
0302 
0303   NodeSet &follow(Model::Node *node, int K = 1)
0304   { return followSet[qMakePair(node, K)]; }
0305 
0306   FollowDep &followDep(Model::Node *node)
0307   { return followDeps[node]; }
0308 
0309   FirstSet::iterator findInFirst(Model::Node *node, int K = 1)
0310   { return firstSet.find(qMakePair(node, K)); }
0311 
0312   FollowSet::iterator findInFollow(Model::Node *node, int K = 1)
0313   { return followSet.find(qMakePair(node, K)); }
0314 
0315   QSet<Model::SymbolItem*> start;
0316   Model::ZeroItem *mZero;
0317 
0318   SymbolSet symbols;
0319   TerminalSet terminals;
0320   QList<Model::EvolveItem*> rules;
0321   MemberCode parserclassMembers, lexerclassMembers;
0322   AstBaseClasses astBaseClasses;
0323   QString parserBaseClass, lexerBaseClass;
0324   QMap<QString, vector<GNFA*> > lexerEnvs;
0325   QMap<QString, GNFA*> lexerEnvResults;
0326   QMap<QString, vector<QString> > lexerActions;
0327   QMap<QString, GNFA*> regexpById;
0328   QMap<QString, QString> enteringCode, leavingCode;
0329   QMap<GNFA*, GDFA*> dfaForNfa;
0330   
0331   Environment env;
0332 
0333 private:
0334   FirstSet firstSet;
0335   FollowSet followSet;
0336   FollowDeps followDeps;
0337 };
0338 
0339 
0340 bool reducesToEpsilon(Model::Node *node);
0341 bool isZero(Model::Node *node);
0342 
0343 extern KDevPG::World globalSystem;
0344 extern QFile file;
0345 
0346 }
0347 QTextStream& operator << (QTextStream& out, KDevPG::Model::Node const *__node);
0348 
0349 
0350 #endif // KDEV_PG_H