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;