dlvhex  2.5.0
src/ManualEvalHeuristicsPlugin.cpp
Go to the documentation of this file.
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: