dlvhex
2.5.0
|
00001 /* dlvhex -- Answer-Set Programming with external interfaces. 00002 * Copyright (C) 2005-2007 Roman Schindlauer 00003 * Copyright (C) 2006-2015 Thomas Krennwallner 00004 * Copyright (C) 2009-2016 Peter Schüller 00005 * Copyright (C) 2011-2016 Christoph Redl 00006 * Copyright (C) 2015-2016 Tobias Kaminski 00007 * Copyright (C) 2015-2016 Antonius Weinzierl 00008 * 00009 * This file is part of dlvhex. 00010 * 00011 * dlvhex is free software; you can redistribute it and/or modify it 00012 * under the terms of the GNU Lesser General Public License as 00013 * published by the Free Software Foundation; either version 2.1 of 00014 * the License, or (at your option) any later version. 00015 * 00016 * dlvhex is distributed in the hope that it will be useful, but 00017 * WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with dlvhex; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00024 * 02110-1301 USA. 00025 */ 00026 00034 #ifdef HAVE_CONFIG_H 00035 #include "config.h" 00036 #endif // HAVE_CONFIG_H 00037 00038 //#define BOOST_SPIRIT_DEBUG 00039 00040 #include "dlvhex2/ManualEvalHeuristicsPlugin.h" 00041 #include "dlvhex2/PlatformDefinitions.h" 00042 #include "dlvhex2/ProgramCtx.h" 00043 #include "dlvhex2/Registry.h" 00044 #include "dlvhex2/Printer.h" 00045 #include "dlvhex2/Printhelpers.h" 00046 #include "dlvhex2/Logger.h" 00047 #include "dlvhex2/HexParser.h" 00048 #include "dlvhex2/HexParserModule.h" 00049 #include "dlvhex2/HexGrammar.h" 00050 00051 #include "dlvhex2/EvalHeuristicBase.h" 00052 #include "dlvhex2/EvalHeuristicShared.h" 00053 #include "dlvhex2/EvalGraphBuilder.h" 00054 00055 DLVHEX_NAMESPACE_BEGIN 00056 00057 namespace spirit = boost::spirit; 00058 namespace qi = boost::spirit::qi; 00059 00060 namespace 00061 { 00062 00063 typedef ComponentGraph::Component Component; 00064 typedef ComponentGraph::ComponentSet ComponentSet; 00065 typedef ComponentGraph::ComponentInfo ComponentInfo; 00066 typedef ComponentGraph::ComponentIterator ComponentIterator; 00067 typedef evalheur::ComponentContainer ComponentContainer; 00068 typedef ManualEvalHeuristicsPlugin::CtxData::InstructionList InstructionList; 00069 typedef std::map<unsigned, std::list<Component> > UnitMap; 00070 typedef std::map<Component, unsigned > UnitBackMap; 00071 00072 class EvalHeuristicFromHEXSourcecode: 00073 public EvalHeuristicBase<EvalGraphBuilder> 00074 { 00075 // types 00076 public: 00077 typedef EvalHeuristicBase<EvalGraphBuilder> Base; 00078 00079 // methods 00080 public: 00081 EvalHeuristicFromHEXSourcecode() { } 00082 virtual ~EvalHeuristicFromHEXSourcecode() { } 00083 00084 virtual void build(EvalGraphBuilder& builder); 00085 00086 protected: 00087 virtual void preprocessComponents(EvalGraphBuilder& builder); 00088 }; 00089 00090 // collapse certain combinations of rules that belong to one unit: 00091 // components that consist of one external atom 00092 void EvalHeuristicFromHEXSourcecode::preprocessComponents(EvalGraphBuilder& builder) { 00093 RegistryPtr reg = builder.registry(); 00094 ComponentGraph& compgraph = builder.getComponentGraph(); 00095 00096 // for all components with only outer external atoms: 00097 // merge with components that depend on them 00098 00099 // do not use boost::tie here! the container is modified in the loop! 00100 for(ComponentIterator cit = compgraph.getComponents().first; 00101 cit != compgraph.getComponents().second; ++cit) { 00102 Component comp = *cit; 00103 const ComponentInfo& ci = compgraph.propsOf(comp); 00104 if( !ci.innerRules.empty() || !ci.innerConstraints.empty() ) 00105 continue; 00106 00107 DBGLOG(DBG,"preprocessing non-rule component " << comp << " " << ci); 00108 00109 ComponentSet collapse; 00110 ComponentGraph::SuccessorIterator sit, sit_end; 00111 for(boost::tie(sit, sit_end) = compgraph.getProvides(comp); 00112 sit != sit_end; ++sit) { 00113 Component succ = compgraph.sourceOf(*sit); 00114 const ComponentInfo& sci = compgraph.propsOf(succ); 00115 DBGLOG(DBG," collapsing with " << succ << " " << sci); 00116 collapse.insert(succ); 00117 } 00118 // put into the set this very component 00119 collapse.insert(comp); 00120 assert(!collapse.empty()); 00121 00122 Component c = compgraph.collapseComponents(collapse); 00123 LOG(DBG,"collapse of " << printrange(collapse) << " yielded new component " << c); 00124 00125 // restart loop after collapse 00126 cit = compgraph.getComponents().first; 00127 } 00128 } 00129 00130 #if 0 00131 // collapse certain combinations of rules that belong to one unit: 00132 // components that consist of one auxiliary external atom input rule 00133 void EvalHeuristicFromHEXSourcecode::postprocessComponents(EvalGraphBuilder& builder) { 00134 RegistryPtr reg = builder.registry(); 00135 ComponentGraph& compgraph = builder.getComponentGraph(); 00136 00137 // for all components with auxiliary input atom in their head: 00138 // merge with topologically last component that they depend on 00139 00141 // do not use boost::tie here! the container is modified in the loop! 00142 for(ComponentIterator cit = compgraph.getComponents().first; 00143 cit != compgraph.getComponents().second; ++cit) { 00150 00151 Component comp = *cit; 00152 const ComponentInfo& ci = compgraph.propsOf(comp); 00153 // the components we are looking for always contain just one rule 00154 if( ci.innerRules.size() != 1 ) 00155 continue; 00156 ID ruleid = ci.innerRules.front(); 00157 const Rule& rule = reg->rules.getByID(ruleid); 00158 // the rules we are looking for always contain just one head which is a nonground atom 00159 if( rule.head.size() != 1 ) 00160 continue; 00161 ID ruleheadid = rule.head.front(); 00162 if( !ruleheadid.isOrdinaryNongroundAtom() ) 00163 continue; 00164 const OrdinaryAtom& rulehead = reg->onatoms.getByID(ruleheadid); 00165 ID headpredicate = rulehead.tuple.front(); 00166 if( !headpredicate.isExternalInputAuxiliary() ) 00167 continue; 00168 00169 DBGLOG(DBG,"preprocessing component with external input auxilary rule " << comp << " " << printToString<RawPrinter>(ruleid, reg)); 00170 00171 // gather list of predecessors 00172 ComponentSet collapse; 00173 ComponentGraph::PredecessorIterator sit, sit_end; 00174 for(boost::tie(sit, sit_end) = compgraph.getDependencies(comp); sit != sit_end; ++sit) { 00175 Component pred = compgraph.targetOf(*sit); 00176 collapse.insert(pred); 00177 } 00178 00179 // put into the set this very component 00180 collapse.insert(comp); 00181 Component c = compgraph.collapseComponents(collapse); 00182 LOG(DBG,"collapse of " << printrange(collapse) << " yielded new component " << c); 00183 00184 // restart loop after collapse 00185 cit = compgraph.getComponents().first; 00186 } 00187 } 00188 #endif 00189 00190 void EvalHeuristicFromHEXSourcecode::build(EvalGraphBuilder& builder) { 00191 RegistryPtr reg = builder.registry(); 00192 ManualEvalHeuristicsPlugin::CtxData& ctxdata = builder.getProgramCtx().getPluginData<ManualEvalHeuristicsPlugin>(); 00193 00194 // preprocess ctxdata.instructions: make sure first element is ID_FAIL 00195 // (defaults to eval unit 0 if not given) 00196 if( ctxdata.instructions.empty() || ctxdata.instructions.begin()->first != ID_FAIL ) { 00197 ctxdata.instructions.push_front(std::make_pair(ID_FAIL,0)); 00198 } 00199 00200 // first build up each unit's list of components 00201 UnitMap unitmap; 00202 UnitBackMap unitbackmap; 00203 00204 ComponentGraph& cg = builder.getComponentGraph(); 00205 00206 preprocessComponents(builder); 00207 00208 ComponentContainer auxiliaryComponents; 00209 ComponentGraph::ComponentIterator cit, cit_end; 00210 for(boost::tie(cit, cit_end) = cg.getComponents(); 00211 cit != cit_end; ++cit) { 00212 Component c = *cit; 00213 const ComponentInfo& ci = cg.getComponentInfo(c); 00214 00215 // rules plus constraints (XXX this could be made more efficient) 00216 Tuple rc(ci.innerRules); 00217 rc.insert(rc.end(),ci.innerConstraints.begin(), ci.innerConstraints.end()); 00218 00219 DBGLOG(DBG,"component " << static_cast<void*>(c) << " " << ci); 00220 00221 // look through all rules and gather unit assignments 00222 std::set<unsigned> assignments; 00223 00224 // XXX if we have many items in "instructions" the following search will be very inefficient and should be solved using a map with an intelligent wrapper around 00225 for(Tuple::const_iterator itr = rc.begin(); 00226 itr != rc.end(); ++itr) { 00227 // rule id 00228 ID rid = *itr; 00229 if( rid.address > ctxdata.lastUserRuleID.address) { 00230 // we do not get assignments for auxiliary rules 00231 DBGLOG(DBG," skipping unit assignment for auxiliary rule " << printToString<RawPrinter>(rid, reg)); 00232 continue; 00233 } 00234 00235 // find instruction for this rule id 00236 InstructionList::const_iterator iti = ctxdata.instructions.begin(); 00237 assert(!ctxdata.instructions.empty()); 00238 assert(iti->first == ID_FAIL); 00239 // start search at second 00240 iti++; 00241 for(;iti != ctxdata.instructions.end(); ++iti) { 00242 assert(iti->first != ID_FAIL); 00243 if( rid.address <= iti->first.address ) { 00244 // this means: rule with ID rid was parsed after last and before this instruction 00245 break; 00246 } 00247 } 00248 // we go back to find the right instruction for this id 00249 iti--; 00250 assert(iti != ctxdata.instructions.end()); 00251 unsigned intoUnit = iti->second; 00252 DBGLOG(DBG," unit " << intoUnit << " for rule " << printToString<RawPrinter>(rid, reg)); 00253 assignments.insert(intoUnit); 00254 } 00255 DBGLOG(DBG," got assingments to units " << printset(assignments)); 00256 00257 if( assignments.size() > 1 ) { 00258 std::stringstream s; 00259 s << "Error: manual evaluation unit instructions put the following rules into distinct units " << printset(assignments) << 00260 " which is not possible due to these rules being a strongly connected component: \n"; 00261 for(Tuple::const_iterator itr = rc.begin(); 00262 itr != rc.end(); ++itr) { 00263 s << printToString<RawPrinter>(*itr, reg) << "\n"; 00264 } 00265 throw std::runtime_error(s.str()); 00266 } 00267 00268 if( !assignments.empty() ) { 00269 assert(assignments.size() == 1); 00270 unsigned assignedUnit = *assignments.begin(); 00271 unitmap[assignedUnit].push_back(c); 00272 unitbackmap[c] = assignedUnit; 00273 } 00274 else { 00275 LOG(DBG,"component " << c << " is currently not assigned to any unit"); 00276 auxiliaryComponents.push_back(c); 00277 } 00278 } 00279 00280 // try to fix some auxiliary components: 00281 // if component depends on assigned component, and assigned component depends on it, and they are the same id, put into that component 00282 ComponentContainer::iterator pit; 00283 while( !auxiliaryComponents.empty() ) { 00284 pit = auxiliaryComponents.begin(); 00285 Component c = *pit; 00286 const ComponentInfo& ci = cg.getComponentInfo(c); 00287 00288 typedef std::set<unsigned> UISet; 00289 00290 // gather list of predecessors 00291 ComponentSet predecessors; 00292 UISet predui; 00293 ComponentGraph::PredecessorIterator ppit, ppit_end; 00294 for(boost::tie(ppit, ppit_end) = cg.getDependencies(c); ppit != ppit_end; ++ppit) { 00295 Component pred = cg.targetOf(*ppit); 00296 predecessors.insert(pred); 00297 if( unitbackmap.find(pred) != unitbackmap.end() ) 00298 predui.insert(unitbackmap.find(pred)->second); 00299 } 00300 00301 // gather list of successors 00302 ComponentSet successors; 00303 UISet succui; 00304 ComponentGraph::SuccessorIterator sit, sit_end; 00305 for(boost::tie(sit, sit_end) = cg.getProvides(c); sit != sit_end; ++sit) { 00306 Component succ = cg.sourceOf(*sit); 00307 successors.insert(succ); 00308 if( unitbackmap.find(succ) != unitbackmap.end() ) 00309 succui.insert(unitbackmap.find(succ)->second); 00310 } 00311 00312 // intersect 00313 ComponentSet intersection; 00314 UISet uintersection; 00315 std::set_intersection( 00316 predecessors.begin(), predecessors.end(), 00317 successors.begin(), successors.end(), 00318 std::inserter(intersection, intersection.begin())); 00319 std::set_intersection( 00320 predui.begin(), predui.end(), 00321 succui.begin(), succui.end(), 00322 std::inserter(uintersection, uintersection.begin())); 00323 00324 LOG(DBG,"trying to fix auxiliary component " << c << " " << ci << " which is " 00325 "depending on " << printset(predecessors) << "/" << printset(predui) << ", " 00326 "providing for " << printset(successors) << "/" << printset(succui) << ", " 00327 "intersection is " << printset(intersection) << "/" << printset(uintersection)); 00328 00329 if( uintersection.size() == 1 ) { 00330 // if component is depending on and providing for same (single) component, put together 00331 unsigned assignedUnit = *uintersection.begin(); 00332 unitmap[assignedUnit].push_back(c); 00333 unitbackmap[c] = assignedUnit; 00334 auxiliaryComponents.erase(pit); 00335 } 00336 else if( uintersection.empty() && predui.size() == 1 ) { 00337 // if component is not in cycle, depends on just one unit and provides for other units, push into first unit 00338 unsigned assignedUnit = *predui.begin(); 00339 unitmap[assignedUnit].push_back(c); 00340 unitbackmap[c] = assignedUnit; 00341 auxiliaryComponents.erase(pit); 00342 } 00343 else { 00344 // TODO more cases? 00345 throw std::runtime_error("could not resolve auxiliary unit, perhaps more code is needed here"); 00346 //++pit; 00347 } 00348 } 00349 00350 // collapse all these units 00351 LOG(INFO,"collapsing according to '#evalunit(...).' instructions in source code"); 00352 for(UnitMap::const_iterator it = unitmap.begin(); 00353 it != unitmap.end(); ++it) { 00354 cg.collapseComponents(ComponentSet(it->second.begin(), it->second.end())); 00355 } 00356 00357 #if 0 00358 // now try to assign units that have not been assigned so far (auxiliary input rules) 00359 ComponentContainer::const_iterator pit; 00360 for(pit = auxiliaryComponents.begin(); 00361 pit != auxiliaryComponents.end(); ++pit) { 00362 Component c = *pit; 00363 const ComponentInfo& ci = cg.getComponentInfo(c); 00364 00365 bool processed = false; 00366 do { 00367 // the auxiliary input rule components we are looking for always contain just one rule 00368 if( ci.innerRules.size() != 1 ) 00369 break; 00370 ID ruleid = ci.innerRules.front(); 00371 const Rule& rule = reg->rules.getByID(ruleid); 00372 // the rules we are looking for always contain just one head which is a nonground atom 00373 if( rule.head.size() != 1 ) 00374 break; 00375 ID ruleheadid = rule.head.front(); 00376 if( !ruleheadid.isOrdinaryNongroundAtom() ) 00377 break; 00378 const OrdinaryAtom& rulehead = reg->onatoms.getByID(ruleheadid); 00379 ID headpredicate = rulehead.tuple.front(); 00380 if( !headpredicate.isExternalInputAuxiliary() ) 00381 break; 00382 00383 DBGLOG(DBG,"trying to assign component with external input auxilary rule " << c << " " << printToString<RawPrinter>(ruleid, reg)); 00384 00385 // gather list of predecessors 00386 ComponentGraph::PredecessorIterator sit, sit_end; 00387 for(boost::tie(sit, sit_end) = cg.getDependencies(c); sit != sit_end; ++sit) { 00388 Component pred = cg.targetOf(*sit); 00389 collapse.insert(pred); 00390 } 00391 00392 // if this component depends only on one component, push it inside there (into its single predecessor) 00393 if( preds.size() == 1 ) { 00394 LOG(INFO,"putting external input auxilary rule " << printToString<RawPrinter>(ruleid, reg) << " to predecessor " << printset(preds)); 00395 } 00396 else { 00397 // otherwise push it into its external atom (into its single successor) 00398 collapse.clear(); 00399 ComponentGraph::SuccessorIterator sit, sit_end; 00400 for(boost::tie(sit, sit_end) = cg.getProvides(c); 00401 sit != sit_end; ++sit) { 00402 Component succ = cg.sourceOf(*sit); 00403 collapse.insert(succ); 00404 } 00405 LOG(INFO,"putting external input auxilary rule " << printToString<RawPrinter>(ruleid, reg) << " to successor " << printset(collapse)); 00406 // if this is not true, more than one external atom depends on this external atom auxiliary input 00407 assert(collapse.size() == 1); 00408 } 00409 // we will collapse with a unit that we create later 00410 Component collapsedOne = *collapse.begin(); 00411 unsigned resultUnitToUpdate = unitbackmap(collapsedOne); 00412 00413 collapse.insert(c); 00414 Component newc = cg.collapseComponents(collapse); 00415 LOG(DBG,"collapse of " << printrange(collapse) << " yielded new component " << newc); 00416 00417 // replace collapsed component by new one 00418 unitmap[resultUnitToUpdate].erase(collapsedOne); 00419 unitmap[resultUnitToUpdate].push_back(newc); 00420 00421 processed = true; 00422 } while(false); 00423 00424 if( !processed ) { 00425 Tuple rc(ci.innerRules); 00426 rc.insert(rc.end(),ci.innerConstraints.begin(), ci.innerConstraints.end()); 00427 // (auxiliary) rules do not belong to unit 00428 std::stringstream s; 00429 s << "Error: got rule(s) " << printManyToString<RawPrinter>(rc, ". ", reg) << "." 00430 << " which is(are) not assigned any unit!" 00431 << " perhaps you need to add code to EvalHeuristicFromHEXSourcecode::preprocessComponents(...)"; 00432 throw std::runtime_error(s.str()); 00433 } 00434 } 00435 #endif 00436 00437 // sort components topologically 00438 ComponentContainer sortedcomps; 00439 evalheur::topologicalSortComponents(cg.getInternalGraph(), sortedcomps); 00440 00441 // create units from components 00442 for(ComponentContainer::const_iterator it = sortedcomps.begin(); 00443 it != sortedcomps.end(); ++it) { 00444 std::list<Component> comp; 00445 comp.push_back(*it); 00446 std::list<Component> empty; 00447 builder.createEvalUnit(comp, empty); 00448 } 00449 } 00450 00451 } 00452 00453 00454 ManualEvalHeuristicsPlugin::CtxData::CtxData(): 00455 enabled(false), 00456 lastUserRuleID(ID_FAIL), 00457 currentUnit(0) 00458 { 00459 } 00460 00461 00462 ManualEvalHeuristicsPlugin::ManualEvalHeuristicsPlugin(): 00463 PluginInterface() 00464 { 00465 setNameVersion("dlvhex-manualevalheuristicsplugin[internal]", 2, 0, 0); 00466 } 00467 00468 00469 ManualEvalHeuristicsPlugin::~ManualEvalHeuristicsPlugin() 00470 { 00471 } 00472 00473 00474 // output help message for this plugin 00475 void ManualEvalHeuristicsPlugin::printUsage(std::ostream& o) const 00476 { 00477 // 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789- 00478 o << " --manualevalheuristics-enable" << std::endl << 00479 " Enable parsing and processing of '#evalunit(...).' instructions." << std::endl; 00480 } 00481 00482 00483 // accepted options: --manualevalheuristics-enable 00484 // 00485 // processes options for this plugin, and removes recognized options from pluginOptions 00486 // (do not free the pointers, the const char* directly come from argv) 00487 // 00488 // configures custom evaluation heuristics 00489 void ManualEvalHeuristicsPlugin::processOptions( 00490 std::list<const char*>& pluginOptions, 00491 ProgramCtx& ctx) 00492 { 00493 ManualEvalHeuristicsPlugin::CtxData& ctxdata = ctx.getPluginData<ManualEvalHeuristicsPlugin>(); 00494 00495 typedef std::list<const char*>::iterator Iterator; 00496 Iterator it; 00497 WARNING("create (or reuse, maybe from potassco?) cmdline option processing facility") 00498 it = pluginOptions.begin(); 00499 while( it != pluginOptions.end() ) { 00500 bool processed = false; 00501 const std::string str(*it); 00502 if( str == "--manualevalheuristics-enable" ) { 00503 ctxdata.enabled = true; 00504 processed = true; 00505 } 00506 00507 if( processed ) { 00508 // return value of erase: element after it, maybe end() 00509 DBGLOG(DBG,"ManualEvalHeuristicsPlugin successfully processed option " << str); 00510 it = pluginOptions.erase(it); 00511 } 00512 else { 00513 it++; 00514 } 00515 } 00516 00517 // register eval heuristics 00518 if( ctxdata.enabled ) { 00519 // directly uses data from ctxdata 00520 ctx.evalHeuristic.reset(new EvalHeuristicFromHEXSourcecode); 00521 } 00522 } 00523 00524 00525 class ManualEvalHeuristicsParserModuleSemantics: 00526 public HexGrammarSemantics 00527 { 00528 public: 00529 ManualEvalHeuristicsPlugin::CtxData& ctxdata; 00530 00531 public: 00532 ManualEvalHeuristicsParserModuleSemantics(ProgramCtx& ctx): 00533 HexGrammarSemantics(ctx), 00534 ctxdata(ctx.getPluginData<ManualEvalHeuristicsPlugin>()) { 00535 } 00536 00537 // use SemanticActionBase to redirect semantic action call into globally 00538 // specializable sem<T> struct space 00539 struct evalUnit: 00540 SemanticActionBase<ManualEvalHeuristicsParserModuleSemantics, ID, evalUnit> 00541 { 00542 evalUnit(ManualEvalHeuristicsParserModuleSemantics& mgr): 00543 evalUnit::base_type(mgr) { 00544 } 00545 }; 00546 }; 00547 00548 // create semantic handler for above semantic action 00549 // (needs to be in globally specializable struct space) 00550 template<> 00551 struct sem<ManualEvalHeuristicsParserModuleSemantics::evalUnit> 00552 { 00553 void operator()( 00554 ManualEvalHeuristicsParserModuleSemantics& mgr, 00555 const uint32_t& unit, // source is not used 00556 ID&) { // the target is not used 00557 // get largest rule id from registry 00558 RuleTable::AddressIterator it, it_end; 00559 boost::tie(it, it_end) = mgr.ctx.registry()->rules.getAllByAddress(); 00560 ID maxruleid; 00561 if( it != it_end ) { 00562 it_end--; 00563 maxruleid = ID(it->kind, it_end-it); 00564 LOG(INFO,"when encountering #evalunit(...). found largest rule id " << maxruleid << 00565 " corresponding to rule '" << printToString<RawPrinter>(maxruleid, mgr.ctx.registry())); 00566 } 00567 else { 00568 // otherwise maxruleid stays ID_FAIL 00569 LOG(INFO,"when encountering #evalunit(...). saw no previous rules"); 00570 } 00571 mgr.ctxdata.instructions.push_back(std::make_pair(maxruleid, unit)); 00572 mgr.ctxdata.currentUnit = unit; 00573 } 00574 }; 00575 00576 namespace 00577 { 00578 00579 template<typename Iterator, typename Skipper> 00580 struct ManualEvalHeuristicsParserModuleGrammarBase: 00581 // we derive from the original hex grammar 00582 // -> we can reuse its rules 00583 public HexGrammarBase<Iterator, Skipper> 00584 { 00585 typedef HexGrammarBase<Iterator, Skipper> Base; 00586 00587 ManualEvalHeuristicsParserModuleSemantics& sem; 00588 00589 ManualEvalHeuristicsParserModuleGrammarBase(ManualEvalHeuristicsParserModuleSemantics& sem): 00590 Base(sem), 00591 sem(sem) { 00592 typedef ManualEvalHeuristicsParserModuleSemantics Sem; 00593 evalUnit = 00594 ( 00595 qi::lit("#evalunit") >> qi::lit("(") >> qi::ulong_ >> qi::lit(")") >> qi::lit(".") > qi::eps 00596 ) [ Sem::evalUnit(sem) ]; 00597 00598 #ifdef BOOST_SPIRIT_DEBUG 00599 BOOST_SPIRIT_DEBUG_NODE(evalUnit); 00600 #endif 00601 } 00602 00603 qi::rule<Iterator, ID(), Skipper> evalUnit; 00604 }; 00605 00606 struct ManualEvalHeuristicsParserModuleGrammar: 00607 ManualEvalHeuristicsParserModuleGrammarBase<HexParserIterator, HexParserSkipper>, 00608 // required for interface 00609 // note: HexParserModuleGrammar = 00610 // boost::spirit::qi::grammar<HexParserIterator, HexParserSkipper> 00611 HexParserModuleGrammar 00612 { 00613 typedef ManualEvalHeuristicsParserModuleGrammarBase<HexParserIterator, HexParserSkipper> GrammarBase; 00614 typedef HexParserModuleGrammar QiBase; 00615 00616 ManualEvalHeuristicsParserModuleGrammar(ManualEvalHeuristicsParserModuleSemantics& sem): 00617 GrammarBase(sem), 00618 QiBase(GrammarBase::evalUnit) { 00619 } 00620 }; 00621 typedef boost::shared_ptr<ManualEvalHeuristicsParserModuleGrammar> 00622 ManualEvalHeuristicsParserModuleGrammarPtr; 00623 00624 class ManualEvalHeuristicsParserModule: 00625 public HexParserModule 00626 { 00627 public: 00628 // the semantics manager is stored/owned by this module! 00629 ManualEvalHeuristicsParserModuleSemantics sem; 00630 // we also keep a shared ptr to the grammar module here 00631 ManualEvalHeuristicsParserModuleGrammarPtr grammarModule; 00632 00633 ManualEvalHeuristicsParserModule(ProgramCtx& ctx): 00634 HexParserModule(TOPLEVEL), 00635 sem(ctx) { 00636 LOG(INFO,"constructed ManualEvalHeuristicsParserModule"); 00637 } 00638 00639 virtual HexParserModuleGrammarPtr createGrammarModule() { 00640 assert(!grammarModule && "for simplicity (storing only one grammarModule pointer) we currently assume this will be called only once .. should be no problem to extend"); 00641 grammarModule.reset(new ManualEvalHeuristicsParserModuleGrammar(sem)); 00642 LOG(INFO,"created ManualEvalHeuristicsParserModuleGrammar"); 00643 return grammarModule; 00644 } 00645 }; 00646 00647 } // anonymous namespace 00648 00649 00650 // create parser modules that extend and the basic hex grammar 00651 // this parser also stores the query information into the plugin 00652 std::vector<HexParserModulePtr> 00653 ManualEvalHeuristicsPlugin::createParserModules(ProgramCtx& ctx) 00654 { 00655 DBGLOG(DBG,"ManualEvalHeuristicsPlugin::createParserModules()"); 00656 std::vector<HexParserModulePtr> ret; 00657 00658 ManualEvalHeuristicsPlugin::CtxData& ctxdata = ctx.getPluginData<ManualEvalHeuristicsPlugin>(); 00659 if( ctxdata.enabled ) { 00660 ret.push_back(HexParserModulePtr( 00661 new ManualEvalHeuristicsParserModule(ctx))); 00662 } 00663 00664 return ret; 00665 } 00666 00667 00668 namespace 00669 { 00670 class ManualEvalHeuristicsPluginRewriter: 00671 public PluginRewriter 00672 { 00673 public: 00674 ManualEvalHeuristicsPlugin::CtxData& ctxdata; 00675 00676 public: 00677 ManualEvalHeuristicsPluginRewriter(ProgramCtx& ctx): 00678 ctxdata(ctx.getPluginData<ManualEvalHeuristicsPlugin>()) { 00679 } 00680 00681 virtual ~ManualEvalHeuristicsPluginRewriter() {} 00682 00683 virtual void rewrite(ProgramCtx& ctx) { 00684 // we do not rewrite, but we gather information from the parsed program 00685 00686 RuleTable::AddressIterator it, it_end; 00687 boost::tie(it, it_end) = ctx.registry()->rules.getAllByAddress(); 00688 if( it != it_end ) { 00689 it_end--; 00690 ctxdata.lastUserRuleID = ID(it_end->kind, it_end-it); 00691 } 00692 else 00693 ctxdata.lastUserRuleID = ID_FAIL; 00694 LOG(INFO,"ManualEvalHeuristicsPluginRewriter got lastUserRuleID=" << ctxdata.lastUserRuleID); 00695 } 00696 }; 00697 } 00698 00699 00700 PluginRewriterPtr 00701 ManualEvalHeuristicsPlugin::createRewriter(ProgramCtx& ctx) 00702 { 00703 ManualEvalHeuristicsPlugin::CtxData& ctxdata = ctx.getPluginData<ManualEvalHeuristicsPlugin>(); 00704 if( ctxdata.enabled ) 00705 return PluginRewriterPtr(new ManualEvalHeuristicsPluginRewriter(ctx)); 00706 else 00707 return PluginRewriterPtr(); 00708 } 00709 00710 00711 DLVHEX_NAMESPACE_END 00712 00713 // this would be the code to use this plugin as a "real" plugin in a .so file 00714 // but we directly use it in dlvhex.cpp 00715 #if 0 00716 ManualEvalHeuristicsPlugin theManualEvalHeuristicsPlugin; 00717 00718 // return plain C type s.t. all compilers and linkers will like this code 00719 extern "C" 00720 void * PLUGINIMPORTFUNCTION() 00721 { 00722 return reinterpret_cast<void*>(& DLVHEX_NAMESPACE theManualEvalHeuristicsPlugin); 00723 } 00724 #endif 00725 00726 00727 // vim:expandtab:ts=4:sw=4: 00728 // mode: C++ 00729 // End: