dlvhex  2.5.0
src/HexParser.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 #include "dlvhex2/HexParser.h"
00039 #include "dlvhex2/ProgramCtx.h"
00040 #include "dlvhex2/HexGrammar.h"
00041 #include "dlvhex2/HexParserModule.h"
00042 #include "dlvhex2/fwd.h"
00043 
00044 #include <boost/spirit/include/qi_parse.hpp>
00045 
00046 #include <boost/scope_exit.hpp>
00047 #include <fstream>
00048 
00049 //#include <unistd.h>
00050 
00051 DLVHEX_NAMESPACE_BEGIN
00052 
00053 HexParser::~HexParser()
00054 {
00055 }
00056 
00057 
00058 void ModuleHexParser::registerModule(HexParserModulePtr module)
00059 {
00060     modules.push_back(module);
00061 }
00062 
00063 
00064 void ModuleHexParser::parse(InputProviderPtr in, ProgramCtx& ctx)
00065 {
00066     assert(!!in);
00067     assert(!!ctx.registry());
00068 
00069     if( ctx.edb == 0 ) {
00070         // create empty interpretation using this context's registry
00071         ctx.edb.reset(new Interpretation(ctx.registry()));
00072         DBGLOG(DBG, " reset edb ");
00073     }
00074     else {
00075         DBGLOG(DBG, " not reset edb ");
00076     }
00077 
00078     // put whole input from stream into a string
00079     // (an alternative would be the boost::spirit::multi_pass iterator
00080     // but this can be done later when the parser is updated to Spirit V2)
00081     WARNING("TODO incrementally read and parse this stream")
00082         std::ostringstream buf;
00083     buf << in->getAsStream().rdbuf();
00084     std::string input = buf.str();
00085 
00086     // create grammar
00087     HexGrammarSemantics semanticsMgr(ctx);
00088     HexGrammar<HexParserIterator, HexParserSkipper> grammar(semanticsMgr);
00089 
00090     // configure grammar with modules
00091     BOOST_FOREACH(HexParserModulePtr module, modules) {
00092         switch(module->getType()) {
00093             case HexParserModule::TOPLEVEL:
00094                 grammar.registerToplevelModule(module->createGrammarModule());
00095                 break;
00096             case HexParserModule::BODYATOM:
00097                 grammar.registerBodyAtomModule(module->createGrammarModule());
00098                 break;
00099             case HexParserModule::HEADATOM:
00100                 grammar.registerHeadAtomModule(module->createGrammarModule());
00101                 break;
00102             case HexParserModule::TERM:
00103                 grammar.registerTermModule(module->createGrammarModule());
00104                 break;
00105             default:
00106                 LOG(ERROR,"unknown parser module type " << module->getType() << "!");
00107                 assert(false);
00108                 break;
00109         }
00110     }
00111 
00112     // prepare iterators
00113     HexParserIterator it_begin = input.begin();
00114     HexParserIterator it_end = input.end();
00115 
00116     // parse
00117     HexParserSkipper skipper;
00118     DBGLOG(DBG,"starting to parse");
00119     bool success = false;
00120     try
00121     {
00122         success = boost::spirit::qi::phrase_parse(
00123             it_begin, it_end, grammar, skipper);
00124         DBGLOG(DBG,"parsing returned with success=" << success);
00125     }
00126     catch(const boost::spirit::qi::expectation_failure<HexParserIterator>& e) {
00127         LOG(ERROR,"parsing returned with failure: expected '" << e.what_ << "'");
00128         it_begin = e.first;
00129     }
00130     if( !success || it_begin != it_end ) {
00131         if( it_begin != it_end )
00132             LOG(ERROR,"iterators not the same!");
00133 
00134         HexParserIterator it_displaybegin = it_begin;
00135         HexParserIterator it_displayend = it_begin;
00136         unsigned usedLeft = 0;
00137         while( usedLeft++ < 50 &&
00138             it_displaybegin != input.begin() &&
00139             *it_displaybegin != '\n' )
00140             it_displaybegin--;
00141         if( *it_displaybegin == '\n' ) {
00142             it_displaybegin++;
00143             usedLeft--;
00144         }
00145         unsigned limitRight = 50;
00146         while( limitRight-- > 0 &&
00147             it_displayend != it_end &&
00148             *it_displayend != '\n' )
00149             it_displayend++;
00150         LOG(ERROR,"unparsed '" << std::string(it_displaybegin, it_displayend) << "'");
00151         LOG(ERROR,"---------" << std::string(usedLeft, '-') << "^");
00152         throw SyntaxError("Could not parse complete input!");
00153     }
00154 
00155     // workaround: making IDs in idb unique
00156     WARNING("we should probably also do this for MLP, at the same time we should probably generalize MLP better")
00157         WARNING("we should use std::set<ID> for IDB")
00158         std::set<ID> uniqueidb(ctx.idb.begin(), ctx.idb.end());
00159     ctx.idb.clear();
00160     ctx.idb.insert(ctx.idb.end(), uniqueidb.begin(), uniqueidb.end());
00161 }
00162 
00163 
00164 DLVHEX_NAMESPACE_END
00165 
00166 #if 0
00167 void
00168 HexParserDriver::parse(std::istream& is,
00169 Program& program,
00170 AtomSet& EDB) throw (SyntaxError)
00171 {
00172     // put whole input from stream into a string
00173     // (an alternative would be the boost::spirit::multi_pass iterator
00174     // but it was not possible to setup/simply did not compile)
00175     std::ostringstream buf;
00176     buf << is.rdbuf();
00177     std::string input = buf.str();
00178 
00179     HexGrammar grammar;
00180     typedef HexGrammarPTToASTConverter Converter;
00181 
00182     Converter::iterator_t it_begin(input.c_str(), input.c_str()+input.size());
00183     Converter::iterator_t it_end;
00184 
00185     // parse ast
00186     boost::spirit::tree_parse_info<Converter::iterator_t, Converter::factory_t> info =
00187         boost::spirit::pt_parse<Converter::factory_t>(
00188         it_begin, it_end, grammar, boost::spirit::space_p);
00189 
00190     // successful parse?
00191     if( !info.full )
00192         throw SyntaxError("Could not parse complete input!",
00193             info.stop.get_position().line, this->source);
00194 
00195     // if this is not ok, there is some bug and the following code will be incomplete
00196     assert(info.trees.size() == 1);
00197 
00198     // create dlvhex AST from spirit parser tree
00199     Converter converter;
00200     converter.convertPTToAST(*info.trees.begin(), program, EDB);
00201 }
00202 
00203 
00204 void
00205 HexParserDriver::parse(const std::string& file,
00206 Program &program,
00207 AtomSet& EDB) throw (SyntaxError)
00208 {
00209     this->source = file;
00210 
00211     std::ifstream ifs;
00212 
00213     ifs.open(this->source.c_str());
00214 
00215     if (!ifs.is_open()) {
00216         throw SyntaxError("File " + this->source + " not found");
00217     }
00218 
00219     parse(ifs, program, EDB);
00220 
00221     ifs.close();
00222 }
00223 #endif
00224 
00225 
00226 // vim:expandtab:ts=4:sw=4:
00227 // mode: C++
00228 // End: