Implemented multi-file input.
This commit is contained in:
parent
64190ba55a
commit
4228ca01dc
apps/plasp-app
include/plasp
src/plasp
@ -16,7 +16,7 @@ int main(int argc, char **argv)
|
||||
description.add_options()
|
||||
("help,h", "Display this help message.")
|
||||
("version,v", "Display version information.")
|
||||
("input,i", po::value<std::string>(), "Specify the SAS input file.")
|
||||
("input,i", po::value<std::vector<std::string>>(), "Specify the SAS input file.")
|
||||
("format,f", po::value<std::string>()->default_value("SAS"), "Specify the file format (SAS or PDDL).");
|
||||
|
||||
po::positional_options_description positionalOptionsDescription;
|
||||
@ -66,10 +66,19 @@ int main(int argc, char **argv)
|
||||
auto format = variablesMap["format"].as<std::string>();
|
||||
std::transform(format.begin(), format.end(), format.begin(), ::tolower);
|
||||
|
||||
const auto &inputFiles = variablesMap["input"].as<std::vector<std::string>>();
|
||||
|
||||
if (format == "sas")
|
||||
{
|
||||
if (inputFiles.size() > 0)
|
||||
{
|
||||
std::cerr << "Error: Only one input file allowed for SAS translation" << std::endl;
|
||||
printHelp();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const auto sasDescription = variablesMap.count("input")
|
||||
? plasp::sas::Description::fromFile(variablesMap["input"].as<std::string>())
|
||||
? plasp::sas::Description::fromFile(inputFiles.front())
|
||||
: plasp::sas::Description::fromStream(std::cin);
|
||||
const auto sasTranslator = plasp::sas::TranslatorASP(sasDescription);
|
||||
sasTranslator.translate(std::cout);
|
||||
@ -77,7 +86,7 @@ int main(int argc, char **argv)
|
||||
else if (format == "pddl")
|
||||
{
|
||||
const auto pddlDescription = variablesMap.count("input")
|
||||
? plasp::pddl::Description::fromFile(variablesMap["input"].as<std::string>())
|
||||
? plasp::pddl::Description::fromFiles(inputFiles)
|
||||
: plasp::pddl::Description::fromStream(std::cin);
|
||||
//std::cout << pddlDescription << std::endl;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class Description
|
||||
{
|
||||
public:
|
||||
static Description fromStream(std::istream &istream);
|
||||
static Description fromFile(const boost::filesystem::path &path);
|
||||
static Description fromFiles(const std::vector<std::string> &paths);
|
||||
|
||||
public:
|
||||
const Domain &domain() const;
|
||||
|
@ -30,9 +30,11 @@ class Domain
|
||||
|
||||
bool isDeclared() const;
|
||||
|
||||
void setName(std::string name);
|
||||
const std::string &name() const;
|
||||
|
||||
const Requirements &requirements() const;
|
||||
bool hasRequirement(Requirement::Type requirementType) const;
|
||||
|
||||
expressions::PrimitiveTypes &types();
|
||||
const expressions::PrimitiveTypes &types() const;
|
||||
@ -52,7 +54,6 @@ class Domain
|
||||
void parseSection();
|
||||
|
||||
void parseRequirementSection();
|
||||
bool hasRequirement(Requirement::Type requirementType) const;
|
||||
void computeDerivedRequirements();
|
||||
|
||||
void parseTypeSection();
|
||||
|
@ -44,6 +44,8 @@ class Problem
|
||||
bool hasRequirement(Requirement::Type requirementType) const;
|
||||
void computeDerivedRequirements();
|
||||
|
||||
void parseDomainSection();
|
||||
|
||||
void parseObjectSection();
|
||||
|
||||
Context &m_context;
|
||||
|
@ -21,6 +21,11 @@ class Parser
|
||||
public:
|
||||
explicit Parser(std::istream &istream);
|
||||
|
||||
void setFileName(std::string fileName);
|
||||
const std::string &fileName() const;
|
||||
|
||||
void resetPosition();
|
||||
|
||||
size_t row() const;
|
||||
size_t column() const;
|
||||
|
||||
@ -60,6 +65,7 @@ class Parser
|
||||
uint64_t parseIntegerBody();
|
||||
|
||||
std::istream &m_istream;
|
||||
std::string m_fileName;
|
||||
std::istreambuf_iterator<char> m_position;
|
||||
|
||||
size_t m_row;
|
||||
@ -67,7 +73,7 @@ class Parser
|
||||
|
||||
bool m_isCaseSensitive;
|
||||
|
||||
bool m_endOfFile;
|
||||
bool m_atEndOfFile;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -31,7 +31,7 @@ class ParserException: public std::exception
|
||||
}
|
||||
|
||||
explicit ParserException(const utils::Parser &parser, const std::string &message)
|
||||
: m_message{std::to_string(parser.row()) + ":" + std::to_string(parser.column()) + "\t" + message}
|
||||
: m_message{parser.fileName() + ":" + std::to_string(parser.row()) + ":" + std::to_string(parser.column()) + " " + message}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ class ParserWarning: public std::exception
|
||||
}
|
||||
|
||||
explicit ParserWarning(const utils::Parser &parser, const std::string &message)
|
||||
: m_message{std::to_string(parser.row()) + ":" + std::to_string(parser.column()) + "\t" + message}
|
||||
: m_message{parser.fileName() + ":" + std::to_string(parser.row()) + ":" + std::to_string(parser.column()) + " " + message}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,9 @@ namespace pddl
|
||||
|
||||
Description::Description(std::istream &istream)
|
||||
: m_parser(istream),
|
||||
m_context(m_parser)
|
||||
m_context(m_parser),
|
||||
m_domain{std::make_unique<Domain>(Domain(m_context))},
|
||||
m_problem{std::make_unique<Problem>(Problem(m_context, *m_domain))}
|
||||
{
|
||||
m_parser.setCaseSensitive(false);
|
||||
}
|
||||
@ -31,19 +33,9 @@ Description Description::fromStream(std::istream &istream)
|
||||
{
|
||||
Description description(istream);
|
||||
|
||||
description.m_domain = std::make_unique<Domain>(Domain(description.m_context));
|
||||
description.m_problem = std::make_unique<Problem>(Problem(description.m_context, *description.m_domain));
|
||||
|
||||
while (true)
|
||||
{
|
||||
description.m_context.parser.skipWhiteSpace();
|
||||
|
||||
if (description.m_context.parser.atEndOfFile())
|
||||
break;
|
||||
|
||||
description.parseContent();
|
||||
}
|
||||
description.m_parser.setFileName("std::cin");
|
||||
|
||||
description.parseContent();
|
||||
description.checkConsistency();
|
||||
|
||||
return description;
|
||||
@ -51,14 +43,36 @@ Description Description::fromStream(std::istream &istream)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Description Description::fromFile(const boost::filesystem::path &path)
|
||||
Description Description::fromFiles(const std::vector<std::string> &paths)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
throw std::runtime_error("File does not exist: \"" + path.string() + "\"");
|
||||
BOOST_ASSERT(!paths.empty());
|
||||
|
||||
std::ifstream fileStream(path.string(), std::ios::in);
|
||||
std::for_each(paths.cbegin(), paths.cend(),
|
||||
[&](const auto &path)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
throw std::runtime_error("File does not exist: \"" + path + "\"");
|
||||
});
|
||||
|
||||
return Description::fromStream(fileStream);
|
||||
std::ifstream fileStream;
|
||||
Description description(fileStream);
|
||||
|
||||
std::for_each(paths.cbegin(), paths.cend(),
|
||||
[&](const auto &path)
|
||||
{
|
||||
fileStream.close();
|
||||
fileStream.clear();
|
||||
fileStream.open(path, std::ios::in);
|
||||
|
||||
description.m_parser.setFileName(path);
|
||||
description.m_parser.resetPosition();
|
||||
|
||||
description.parseContent();
|
||||
});
|
||||
|
||||
description.checkConsistency();
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -74,12 +88,18 @@ const Domain &Description::domain() const
|
||||
|
||||
void Description::parseContent()
|
||||
{
|
||||
std::cout << "Parsing file content" << std::endl;
|
||||
while (true)
|
||||
{
|
||||
m_context.parser.skipWhiteSpace();
|
||||
|
||||
m_context.parser.expect<std::string>("(");
|
||||
m_context.parser.expect<std::string>("define");
|
||||
parseSection();
|
||||
m_context.parser.expect<std::string>(")");
|
||||
if (m_context.parser.atEndOfFile())
|
||||
return;
|
||||
|
||||
m_context.parser.expect<std::string>("(");
|
||||
m_context.parser.expect<std::string>("define");
|
||||
parseSection();
|
||||
m_context.parser.expect<std::string>(")");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -91,8 +111,6 @@ void Description::parseSection()
|
||||
|
||||
const auto sectionIdentifier = m_context.parser.parse<std::string>();
|
||||
|
||||
std::cout << "Parsing section " << sectionIdentifier << std::endl;
|
||||
|
||||
if (sectionIdentifier == "domain")
|
||||
{
|
||||
BOOST_ASSERT(m_domain);
|
||||
@ -119,6 +137,9 @@ void Description::parseSection()
|
||||
|
||||
void Description::checkConsistency()
|
||||
{
|
||||
if (!m_domain->isDeclared())
|
||||
throw ConsistencyException("No PDDL domain specified");
|
||||
|
||||
m_domain->checkConsistency();
|
||||
m_problem->checkConsistency();
|
||||
}
|
||||
|
@ -32,7 +32,13 @@ Domain::Domain(Context &context)
|
||||
|
||||
void Domain::readPDDL()
|
||||
{
|
||||
m_name = m_context.parser.parseIdentifier(isIdentifier);
|
||||
const auto domainName = m_context.parser.parseIdentifier(isIdentifier);
|
||||
|
||||
if (m_name.empty())
|
||||
m_name = domainName;
|
||||
// If the domain has previously been referenced, check that the name matches
|
||||
else if (m_name != domainName)
|
||||
throw utils::ParserException(m_context.parser, "Domains do not match (\"" + domainName + "\" and \"" + m_name + "\")");
|
||||
|
||||
std::cout << "Parsing domain " << m_name << std::endl;
|
||||
|
||||
@ -62,6 +68,13 @@ bool Domain::isDeclared() const
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Domain::setName(std::string name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const std::string &Domain::name() const
|
||||
{
|
||||
return m_name;
|
||||
@ -334,11 +347,22 @@ void Domain::checkConsistency()
|
||||
// Verify that typing requirement is correctly declared if used
|
||||
if (!m_primitiveTypes.empty() && !hasRequirement(Requirement::Type::Typing))
|
||||
{
|
||||
throw ConsistencyException("Domain contains typing information but does not declare typing requirement");
|
||||
m_context.logger.parserWarning(m_context.parser, "Domain contains typing information but does not declare typing requirement");
|
||||
|
||||
m_requirements.push_back(Requirement(Requirement::Type::Typing));
|
||||
}
|
||||
|
||||
// Verify that all variables and constants have types
|
||||
if (hasRequirement(Requirement::Type::Typing))
|
||||
{
|
||||
std::for_each(m_constants.cbegin(), m_constants.cend(),
|
||||
[&](const auto &constant)
|
||||
{
|
||||
if (constant->type() == nullptr)
|
||||
throw ConsistencyException("Constant \"" + constant->name() + "\" has no type");
|
||||
});
|
||||
}
|
||||
|
||||
// Verify that all used types have been declared
|
||||
std::for_each(m_primitiveTypes.cbegin(), m_primitiveTypes.cend(),
|
||||
[&](const auto &type)
|
||||
@ -366,7 +390,6 @@ void Domain::checkConsistency()
|
||||
throw ConsistencyException("Predicate \"" + predicate->name() + "\" used but never declared");
|
||||
});
|
||||
|
||||
// Verify that all variables have types
|
||||
// Verify that constants are unique
|
||||
// Verify that all primitive types are unique
|
||||
// Check for case-sensitivity issues
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <plasp/pddl/Domain.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/expressions/Constant.h>
|
||||
#include <plasp/utils/IO.h>
|
||||
@ -134,7 +135,7 @@ void Problem::parseSection()
|
||||
|
||||
// TODO: check order of the sections
|
||||
if (sectionIdentifier == "domain")
|
||||
skipSection();
|
||||
parseDomainSection();
|
||||
else if (sectionIdentifier == "requirements")
|
||||
parseRequirementSection();
|
||||
else if (sectionIdentifier == "objects")
|
||||
@ -155,6 +156,23 @@ void Problem::parseSection()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Problem::parseDomainSection()
|
||||
{
|
||||
m_context.parser.skipWhiteSpace();
|
||||
|
||||
const auto domainName = m_context.parser.parseIdentifier(isIdentifier);
|
||||
|
||||
if (m_domain.isDeclared() && m_domain.name() != domainName)
|
||||
throw utils::ParserException(m_context.parser, "Domains do not match (\"" + m_domain.name() + "\" and \"" + domainName + "\")");
|
||||
|
||||
if (!m_domain.isDeclared())
|
||||
m_domain.setName(domainName);
|
||||
|
||||
m_context.parser.expect<std::string>(")");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Problem::parseRequirementSection()
|
||||
{
|
||||
m_context.parser.skipWhiteSpace();
|
||||
@ -238,7 +256,7 @@ void Problem::parseObjectSection()
|
||||
// Store constants
|
||||
while (m_context.parser.currentCharacter() != ')')
|
||||
{
|
||||
//expressions::Constant::parseTypedDeclaration(m_context);
|
||||
expressions::Constant::parseTypedDeclaration(m_context, *this);
|
||||
|
||||
m_context.parser.skipWhiteSpace();
|
||||
}
|
||||
@ -250,6 +268,14 @@ void Problem::parseObjectSection()
|
||||
|
||||
void Problem::checkConsistency()
|
||||
{
|
||||
// Verify that all objects have types
|
||||
if (hasRequirement(Requirement::Type::Typing) || m_domain.hasRequirement(Requirement::Type::Typing))
|
||||
std::for_each(m_objects.cbegin(), m_objects.cend(),
|
||||
[&](const auto &constant)
|
||||
{
|
||||
if (constant->type() == nullptr)
|
||||
throw ConsistencyException("Object \"" + constant->name() + "\" has no type");
|
||||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -61,11 +61,13 @@ void PrimitiveType::parseDeclaration(Context &context, Domain &domain)
|
||||
auto *type = match->get();
|
||||
|
||||
type->setDirty();
|
||||
type->setDeclared();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
types.emplace_back(std::make_unique<PrimitiveType>(typeName));
|
||||
types.back()->setDeclared();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -77,11 +79,6 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
|
||||
// Parse and store type
|
||||
parseDeclaration(context, domain);
|
||||
|
||||
auto *type = types.back().get();
|
||||
|
||||
// Flag type as correctly declared in the types section
|
||||
type->setDeclared();
|
||||
|
||||
context.parser.skipWhiteSpace();
|
||||
|
||||
// Check for type inheritance
|
||||
@ -129,12 +126,8 @@ PrimitiveType *PrimitiveType::parseAndFindOrCreate(Context &context, Domain &dom
|
||||
|
||||
if (match == types.cend())
|
||||
{
|
||||
// Primitive type "object" is implicitly declared
|
||||
if (typeName != "object")
|
||||
context.logger.parserWarning(context.parser, "Primitive type \"" + typeName + "\" used but never declared");
|
||||
|
||||
// If necessary, insert new primitive type but don't declare it
|
||||
types.emplace_back(std::make_unique<expressions::PrimitiveType>(typeName));
|
||||
types.back()->setDeclared();
|
||||
|
||||
return types.back().get();
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ void Logger::parserWarning(const Parser &parser, const std::string &text)
|
||||
if (m_isPedantic)
|
||||
throw ParserWarning(parser, text);
|
||||
|
||||
std::cerr << "Warning: " << parser.row() << ":" << parser.column() << "\t" << text << std::endl;
|
||||
std::cerr << "Warning: " << parser.fileName() << ":" << parser.row() << ":" << parser.column() << " " << text << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -27,14 +27,36 @@ Parser::Parser(std::istream &istream)
|
||||
m_row{1},
|
||||
m_column{1},
|
||||
m_isCaseSensitive{true},
|
||||
m_endOfFile{false}
|
||||
m_atEndOfFile{false}
|
||||
{
|
||||
std::setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// Don’t skip whitespace
|
||||
istream.exceptions(std::istream::badbit);
|
||||
}
|
||||
|
||||
checkStream();
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::setFileName(std::string fileName)
|
||||
{
|
||||
m_fileName = fileName;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const std::string &Parser::fileName() const
|
||||
{
|
||||
return m_fileName;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::resetPosition()
|
||||
{
|
||||
m_row = 1;
|
||||
m_column = 1;
|
||||
m_atEndOfFile = false;
|
||||
m_position = std::istreambuf_iterator<char>(m_istream);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
Reference in New Issue
Block a user