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/ConditionalLiteralPlugin.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/PredicateMask.h" 00047 #include "dlvhex2/Logger.h" 00048 #include "dlvhex2/HexParser.h" 00049 #include "dlvhex2/HexParserModule.h" 00050 #include "dlvhex2/HexGrammar.h" 00051 #include "dlvhex2/LiberalSafetyChecker.h" 00052 00053 #include <boost/algorithm/string/predicate.hpp> 00054 #include <boost/lexical_cast.hpp> 00055 00056 DLVHEX_NAMESPACE_BEGIN 00057 00058 namespace spirit = boost::spirit; 00059 namespace qi = boost::spirit::qi; 00060 00061 ConditionalLiteralPlugin::CtxData::CtxData(): 00062 enabled(false) 00063 { 00064 } 00065 00066 00067 ConditionalLiteralPlugin::ConditionalLiteralPlugin(): 00068 PluginInterface() 00069 { 00070 setNameVersion("dlvhex-conditionalLiteralPlugin[internal]", 2, 0, 0); 00071 } 00072 00073 00074 ConditionalLiteralPlugin::~ConditionalLiteralPlugin() 00075 { 00076 } 00077 00078 00079 // output help message for this plugin 00080 void ConditionalLiteralPlugin::printUsage(std::ostream& o) const 00081 { 00082 // 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789- 00083 o << " --conditinal-enable[=true,false]" << std::endl 00084 << " Enable conditional literals (default is enabled)." << std::endl; 00085 } 00086 00087 00088 // accepted options: --choice-enable 00089 // 00090 // processes options for this plugin, and removes recognized options from pluginOptions 00091 // (do not free the pointers, the const char* directly come from argv) 00092 void ConditionalLiteralPlugin::processOptions( 00093 std::list<const char*>& pluginOptions, 00094 ProgramCtx& ctx) 00095 { 00096 ConditionalLiteralPlugin::CtxData& ctxdata = ctx.getPluginData<ConditionalLiteralPlugin>(); 00097 ctxdata.enabled = true; 00098 00099 typedef std::list<const char*>::iterator Iterator; 00100 Iterator it; 00101 WARNING("create (or reuse, maybe from potassco?) cmdline option processing facility") 00102 it = pluginOptions.begin(); 00103 while( it != pluginOptions.end() ) { 00104 bool processed = false; 00105 const std::string str(*it); 00106 if( boost::starts_with(str, "--conditional-enable" ) ) { 00107 std::string m = str.substr(std::string("--conditional-enable").length()); 00108 if (m == "" || m == "=true") { 00109 ctxdata.enabled = true; 00110 } 00111 else if (m == "=false") { 00112 ctxdata.enabled = false; 00113 } 00114 else { 00115 std::stringstream ss; 00116 ss << "Unknown --conditional-enable option: " << m; 00117 throw PluginError(ss.str()); 00118 } 00119 processed = true; 00120 } 00121 00122 if( processed ) { 00123 // return value of erase: element after it, maybe end() 00124 DBGLOG(DBG,"ConditionalLiteralPlugin successfully processed option " << str); 00125 it = pluginOptions.erase(it); 00126 } 00127 else { 00128 it++; 00129 } 00130 } 00131 } 00132 00133 00134 class ConditionalParserModuleSemantics: 00135 public HexGrammarSemantics 00136 { 00137 public: 00138 int varnr; 00139 ConditionalLiteralPlugin::CtxData& ctxdata; 00140 00141 public: 00142 ConditionalParserModuleSemantics(ProgramCtx& ctx): 00143 HexGrammarSemantics(ctx), 00144 varnr(0), 00145 ctxdata(ctx.getPluginData<ConditionalLiteralPlugin>()) { 00146 } 00147 00148 // use SemanticActionBase to redirect semantic action call into globally 00149 // specializable sem<T> struct space 00150 struct conditionalLieral: 00151 SemanticActionBase<ConditionalParserModuleSemantics, ID, conditionalLieral> 00152 { 00153 conditionalLieral(ConditionalParserModuleSemantics& mgr): 00154 conditionalLieral::base_type(mgr) { 00155 } 00156 }; 00157 }; 00158 00159 template<> 00160 struct sem<ConditionalParserModuleSemantics::conditionalLieral> 00161 { 00162 void operator()( 00163 ConditionalParserModuleSemantics& mgr, 00164 const boost::fusion::vector2< 00165 dlvhex::ID, 00166 boost::optional<std::vector<dlvhex::ID> > 00167 >& source, 00168 ID& target) { 00169 RegistryPtr reg = mgr.ctx.registry(); 00170 00171 ID derivedAtomID = boost::fusion::at_c<0>(source); 00172 00173 Rule condRule(ID::MAINKIND_RULE | ID::SUBKIND_RULE_REGULAR); 00174 00175 // count instances of the conditional part which do not fulfill the derived part; this number must be 0 00176 DBGLOG(DBG, "Creating aggregate #count{ ... : naf derived(...), condition(...) }"); 00177 AggregateAtom cnt(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_AGGREGATE); 00178 cnt.tuple[0] = ID::termFromInteger(0); 00179 cnt.tuple[1] = ID::termFromBuiltin(ID::TERM_BUILTIN_EQ); 00180 cnt.tuple[2] = ID::termFromBuiltin(ID::TERM_BUILTIN_AGGCOUNT); 00181 cnt.tuple[3] = ID_FAIL; 00182 cnt.tuple[4] = ID_FAIL; 00183 ID cntID; 00184 std::set<ID> vars; 00185 reg->getVariablesInID(derivedAtomID, vars); 00186 cnt.variables.insert(cnt.variables.end(), vars.begin(), vars.end()); 00187 if (!!boost::fusion::at_c<1>(source)) cnt.literals = boost::fusion::at_c<1>(source).get(); 00188 cnt.literals.push_back(ID::nafLiteralFromAtom(derivedAtomID)); 00189 cntID = reg->aatoms.storeAndGetID(cnt); 00190 DBGLOG(DBG, "Result: " << printToString<RawPrinter>(cntID, reg)); 00191 00192 target = cntID; 00193 } 00194 }; 00195 00196 namespace 00197 { 00198 00199 template<typename Iterator, typename Skipper> 00200 struct ConditionalParserModuleGrammarBase: 00201 // we derive from the original hex grammar 00202 // -> we can reuse its rules 00203 public HexGrammarBase<Iterator, Skipper> 00204 { 00205 typedef HexGrammarBase<Iterator, Skipper> Base; 00206 00207 ConditionalParserModuleSemantics& sem; 00208 00209 ConditionalParserModuleGrammarBase(ConditionalParserModuleSemantics& sem): 00210 Base(sem), 00211 sem(sem) { 00212 typedef ConditionalParserModuleSemantics Sem; 00213 00214 conditionalLieral 00215 // The gringo syntax for conditional literals is as follows: 00216 // p(X1, ..., Xn) : l1(...), ..., ln(...) 00217 // where l1, ..., ln are possibly default-negated literals. 00218 // Note that the literals in the condition are comma-separated, i.e., all l1(...), ..., ln(...) belong to the condition. 00219 // There overall conditional literal is terminated by semicolon. 00220 // Therefore, the HEX-syntax was extended such that body literals can be separated either by comma or by semicolon, 00221 // where the parser of conditional literals should greedily process literals until a semicolon appears. 00222 // Examples: 00223 // 1. x :- y : u, w; t. 00224 // is interpreted such that the head contains the atom x, and the body contains the conditional literal y:u,w (derived atom y, conditions u and w) and the ordinary literal t. 00225 // 2. x :- r, s; t. 00226 // is interpreted such that the head contains the atom x, and the body contains literals r, s and t. 00227 // Since there is no conditional literal in the body, comma and semicolon have the same semantics and separate the literals of the body. 00228 = ( 00229 Base::classicalAtom >> qi::lit(':') >> (Base::bodyLiteral % qi::lit(',')) > qi::eps 00230 ) [ Sem::conditionalLieral(sem) ]; 00231 00232 #ifdef BOOST_SPIRIT_DEBUG 00233 BOOST_SPIRIT_DEBUG_NODE(conditionalLieral); 00234 #endif 00235 } 00236 00237 qi::rule<Iterator, ID(), Skipper> conditionalLieral; 00238 }; 00239 00240 struct ConditionalParserModuleGrammar: 00241 ConditionalParserModuleGrammarBase<HexParserIterator, HexParserSkipper>, 00242 // required for interface 00243 // note: HexParserModuleGrammar = 00244 // boost::spirit::qi::grammar<HexParserIterator, HexParserSkipper> 00245 HexParserModuleGrammar 00246 { 00247 typedef ConditionalParserModuleGrammarBase<HexParserIterator, HexParserSkipper> GrammarBase; 00248 typedef HexParserModuleGrammar QiBase; 00249 00250 ConditionalParserModuleGrammar(ConditionalParserModuleSemantics& sem): 00251 GrammarBase(sem), 00252 QiBase(GrammarBase::conditionalLieral) { 00253 } 00254 }; 00255 typedef boost::shared_ptr<ConditionalParserModuleGrammar> 00256 ConditionalParserModuleGrammarPtr; 00257 00258 // moduletype = HexParserModule::BODYATOM 00259 template<enum HexParserModule::Type moduletype> 00260 class ConditionalParserModule: 00261 public HexParserModule 00262 { 00263 public: 00264 // the semantics manager is stored/owned by this module! 00265 ConditionalParserModuleSemantics sem; 00266 // we also keep a shared ptr to the grammar module here 00267 ConditionalParserModuleGrammarPtr grammarModule; 00268 00269 ConditionalParserModule(ProgramCtx& ctx): 00270 HexParserModule(moduletype), 00271 sem(ctx) { 00272 LOG(INFO,"constructed ConditionalParserModule"); 00273 } 00274 00275 virtual HexParserModuleGrammarPtr createGrammarModule() { 00276 assert(!grammarModule && "for simplicity (storing only one grammarModule pointer) we currently assume this will be called only once .. should be no problem to extend"); 00277 grammarModule.reset(new ConditionalParserModuleGrammar(sem)); 00278 LOG(INFO,"created ConditionalParserModuleGrammar"); 00279 return grammarModule; 00280 } 00281 }; 00282 00283 } // anonymous namespace 00284 00285 00286 // create parser modules that extend and the basic hex grammar 00287 // this parser also stores the query information into the plugin 00288 std::vector<HexParserModulePtr> 00289 ConditionalLiteralPlugin::createParserModules(ProgramCtx& ctx) 00290 { 00291 DBGLOG(DBG,"ConditionalLiteralPlugin::createParserModules()"); 00292 std::vector<HexParserModulePtr> ret; 00293 00294 ConditionalLiteralPlugin::CtxData& ctxdata = ctx.getPluginData<ConditionalLiteralPlugin>(); 00295 if( ctxdata.enabled ) { 00296 ret.push_back(HexParserModulePtr( 00297 new ConditionalParserModule<HexParserModule::BODYATOM>(ctx))); 00298 } 00299 00300 return ret; 00301 } 00302 00303 00304 std::vector<PluginAtomPtr> ConditionalLiteralPlugin::createAtoms(ProgramCtx& ctx) const 00305 { 00306 std::vector<PluginAtomPtr> ret; 00307 // we don't have external atoms, only a parer plugin and a rewriter 00308 return ret; 00309 } 00310 00311 00312 void ConditionalLiteralPlugin::setupProgramCtx(ProgramCtx& ctx) 00313 { 00314 ConditionalLiteralPlugin::CtxData& ctxdata = ctx.getPluginData<ConditionalLiteralPlugin>(); 00315 if( !ctxdata.enabled ) 00316 return; 00317 00318 RegistryPtr reg = ctx.registry(); 00319 } 00320 00321 00322 DLVHEX_NAMESPACE_END 00323 00324 // this would be the code to use this plugin as a "real" plugin in a .so file 00325 // but we directly use it in dlvhex.cpp 00326 #if 0 00327 ConditionalLiteralPlugin theConditionalLiteralPlugin; 00328 00329 // return plain C type s.t. all compilers and linkers will like this code 00330 extern "C" 00331 void * PLUGINIMPORTFUNCTION() 00332 { 00333 return reinterpret_cast<void*>(& DLVHEX_NAMESPACE theConditionalLiteralPlugin); 00334 } 00335 #endif 00336 00337 00338 // vim:expandtab:ts=4:sw=4: 00339 // mode: C++ 00340 // End: