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

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    Copyright (C) 2010 Jonathan Schmidt-Dominé <devel@the-user.org>
0006 
0007    This library is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This library is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this library; see the file COPYING.LIB.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020    Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include "kdev-pg-follow.h"
0024 #include "kdev-pg-pretty-printer.h"
0025 
0026 #include <QTextStream>
0027 
0028 //uncomment this to see debug output for follow dependency calculation
0029 // #define followDepsEP_DEBUG
0030 
0031 /*
0032  * Computing LL(k)-follow-sets
0033  */
0034 
0035 namespace KDevPG
0036 {
0037 
0038 extern QTextStream checkOut;
0039 
0040 #ifdef FOLLOWDEP_DEBUG
0041 void DebugFollowDep(Model::Node *dest, Model::Node *dep, const QString &message)
0042 {
0043   checkOut << "=============================" << Qt::endl;
0044   PrettyPrinter p(QTextStream( stderr ));
0045   checkOut << "adding " << message << " ";
0046   p(dep);
0047   checkOut << " (" << (uint*)dep << ")";
0048   checkOut << " to follow ";
0049   p(dest);
0050   checkOut << " (" << (uint*)dest << ")";
0051   checkOut << "{" << dest->kind << "}";
0052   if (dest->kind == Model::Node_kind_nonTerminal)
0053   {
0054     Model::SymbolItem *s = ((Model::NonTerminalItem*)dest)->mSymbol;
0055     if (s)
0056       checkOut << "__"; p(s); checkOut << "__";
0057   }
0058   checkOut << Qt::endl;
0059 }
0060 
0061 void debugFirstToFollowDep(Model::Node *dest, Model::Node *dep)
0062 {
0063   DebugFollowDep(dest, dep, "first");
0064 }
0065 
0066 void debugFollowToFollowDep(Model::Node *dest, Model::Node *dep)
0067 {
0068   DebugFollowDep(dest, dep, "follow");
0069 }
0070 #endif
0071 
0072 //
0073 // Calculating the FOLLOW set depends on the first set being already available
0074 // and is in principle quite easy. There are only a few simple rules:
0075 //
0076 // 1. Put EOF at the end of the start rule
0077 // 2. For every rule "items -> rulename", put FOLLOW(rulename) into FOLLOW(items)
0078 // 3. For every item sequence "item1 item2", put first(item2) into FOLLOW(item1)
0079 // 4. For every rule "item1 item2 -> rulename", put FOLLOW(rulename)
0080 //    into FOLLOW(item1) if item2 can derive to epsilon ("0").
0081 // 5. Propagate the FOLLOW sets down to the symbols where appropriate.
0082 // 6. Loop for all rules until there are no changes in any FOLLOW set anymore.
0083 //
0084 
0085 NextFollow::NextFollow(bool &changed)
0086   : mChanged(changed)
0087 {
0088   Model::TerminalItem *teof = globalSystem.pushTerminal("EOF", "end of file");
0089   for(auto i = globalSystem.rules.begin(); i != globalSystem.rules.end(); ++i)
0090   {
0091     if(globalSystem.start.contains((*i)->mSymbol))
0092     {
0093       globalSystem.follow(*i).insert(teof);
0094       globalSystem.follow((*i)->mSymbol).insert(teof);
0095       globalSystem.follow((*i)->mItem).insert(teof);
0096     }
0097   }
0098 }
0099 
0100 void NextFollow::operator()(Model::Node *node)
0101 {
0102   Model::EvolveItem *e = nodeCast<Model::EvolveItem*>(node);
0103   Q_ASSERT(e != nullptr);
0104   mSymbol = e->mSymbol;
0105   visitNode(node);
0106 }
0107 
0108 void NextFollow::merge(Model::Node*__dest, World::NodeSet const &source)
0109 {
0110   if (nodeCast<Model::ZeroItem*>(__dest) != nullptr
0111       || nodeCast<Model::TerminalItem*>(__dest) != nullptr)
0112     {
0113       return;
0114     }
0115 
0116   World::NodeSet &dest = globalSystem.follow(__dest);
0117 
0118   for (World::NodeSet::const_iterator it = source.begin(); it != source.end(); ++it)
0119     {
0120       if (Model::TerminalItem *t = nodeCast<Model::TerminalItem*>(*it))
0121       {
0122           if( !dest.contains(t) )
0123           {
0124             mChanged = true;
0125             dest.insert(t);
0126           }
0127       }
0128     }
0129 }
0130 
0131 void NextFollow::visitCons(Model::ConsItem *node)
0132 {
0133   merge(node->mRight, globalSystem.follow(node));
0134   addFollowToFollowDep(node->mRight, node);
0135 
0136   merge(node->mLeft, globalSystem.first(node->mRight));
0137   addFirstToFollowDep(node->mLeft, node->mRight);
0138 
0139   if (reducesToEpsilon(node->mRight))
0140   {
0141     merge(node->mLeft, globalSystem.follow(node));
0142     addFollowToFollowDep(node->mLeft, node);
0143   }
0144 
0145   DefaultVisitor::visitCons(node);
0146 }
0147 
0148 void NextFollow::visitAlternative(Model::AlternativeItem *node)
0149 {
0150   merge(node->mLeft, globalSystem.follow(node));
0151   addFollowToFollowDep(node->mLeft, node);
0152   merge(node->mRight, globalSystem.follow(node));
0153   addFollowToFollowDep(node->mRight, node);
0154 
0155   DefaultVisitor::visitAlternative(node);
0156 }
0157 
0158 void NextFollow::visitNode(Model::Node* node)
0159 {
0160     if(node == nullptr)
0161       return;
0162   
0163     if(mVisited.contains(node))
0164       return;
0165     
0166     mVisited.insert(node);
0167     
0168     KDevPG::Visitor::visitNode(node);
0169     
0170     mVisited.remove(node);
0171 }
0172 
0173 void NextFollow::preCopy(Model::Node* from, Model::Node* to)
0174 {
0175   if(from != nullptr && to != nullptr)
0176   {
0177     merge(from, globalSystem.follow(to));
0178     addFollowToFollowDep(from, to);
0179   }
0180 }
0181 
0182 void NextFollow::copy(Model::Node* from, Model::Node* to)
0183 {
0184     Q_UNUSED(from);
0185     Q_UNUSED(to);
0186 }
0187 
0188 void NextFollow::addFirstToFollowDep(Model::Node *dest, Model::Node *dep)
0189 {
0190   if (dest->kind == Model::NodeKindNonTerminal)
0191   {
0192     Model::SymbolItem *s = nodeCast<Model::NonTerminalItem*>(dest)->mSymbol;
0193     if (s)
0194       globalSystem.followDep(s).first.insert(dep);
0195   }
0196   else
0197     globalSystem.followDep(dest).first.insert(dep);
0198 #ifdef FOLLOWDEP_DEBUG
0199   debugFirstToFollowDep(dest, dep);
0200 #endif
0201 }
0202 
0203 void NextFollow::addFollowToFollowDep(Model::Node *dest, Model::Node *dep)
0204 {
0205   if (dest->kind == Model::NodeKindNonTerminal)
0206   {
0207     Model::SymbolItem *s = nodeCast<Model::NonTerminalItem*>(dest)->mSymbol;
0208     if (s)
0209       globalSystem.followDep(s).second.insert(dep);
0210   }
0211   else
0212     globalSystem.followDep(dest).second.insert(dep);
0213 #ifdef FOLLOWDEP_DEBUG
0214   debugFollowToFollowDep(dest, dep);
0215 #endif
0216 }
0217 
0218 void computeFollow()
0219 {
0220   bool changed = true;
0221   NextFollow next(changed);
0222   while (true)
0223     {
0224       for(QList<Model::EvolveItem*>::iterator it = globalSystem.rules.begin(); it != globalSystem.rules.end(); ++it)
0225       {
0226         next(*it);
0227       }
0228       if(!changed) // for the eof in the first iteration
0229         break;
0230       changed = false;
0231     }
0232 }
0233 
0234 }
0235 
0236 // kate: space-indent on; indent-width 2; tab-width 2; show-tabs on;