From 87889f5efe304d191c7a3949cac7d853c095daac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Thu, 9 Jun 2016 14:39:03 +0200 Subject: [PATCH] Implemented two-pass parsing for PDDL problems. --- apps/plasp-app/main.cpp | 65 +++++------ include/plasp/pddl/Problem.h | 12 +- src/plasp/pddl/Description.cpp | 4 +- src/plasp/pddl/Domain.cpp | 12 +- src/plasp/pddl/Problem.cpp | 194 ++++++++++++++++++++++----------- 5 files changed, 175 insertions(+), 112 deletions(-) diff --git a/apps/plasp-app/main.cpp b/apps/plasp-app/main.cpp index cdcc707..f40fc60 100644 --- a/apps/plasp-app/main.cpp +++ b/apps/plasp-app/main.cpp @@ -61,53 +61,44 @@ int main(int argc, char **argv) return EXIT_SUCCESS; } - try + auto format = variablesMap["format"].as(); + std::transform(format.begin(), format.end(), format.begin(), ::tolower); + + if (format == "sas") { - auto format = variablesMap["format"].as(); - std::transform(format.begin(), format.end(), format.begin(), ::tolower); - - if (format == "sas") + if (variablesMap.count("input")) { - if (variablesMap.count("input")) - { - const auto &inputFiles = variablesMap["input"].as>(); + const auto &inputFiles = variablesMap["input"].as>(); - if (inputFiles.size() > 1) - { - std::cerr << "Error: Only one input file allowed for SAS translation" << std::endl; - printHelp(); - return EXIT_FAILURE; - } - - const auto sasDescription = plasp::sas::Description::fromFile(inputFiles.front()); - const auto sasTranslator = plasp::sas::TranslatorASP(sasDescription); - sasTranslator.translate(std::cout); - } - else + if (inputFiles.size() > 1) { - const auto sasDescription = plasp::sas::Description::fromStream(std::cin); - const auto sasTranslator = plasp::sas::TranslatorASP(sasDescription); - sasTranslator.translate(std::cout); + std::cerr << "Error: Only one input file allowed for SAS translation" << std::endl; + printHelp(); + return EXIT_FAILURE; } + + const auto sasDescription = plasp::sas::Description::fromFile(inputFiles.front()); + const auto sasTranslator = plasp::sas::TranslatorASP(sasDescription); + sasTranslator.translate(std::cout); } - else if (format == "pddl") + else { - if (variablesMap.count("input")) - { - const auto &inputFiles = variablesMap["input"].as>(); - const auto pddlDescription = plasp::pddl::Description::fromFiles(inputFiles); - } - else - const auto pddlDescription = plasp::pddl::Description::fromStream(std::cin); - - //std::cout << pddlDescription << std::endl; + const auto sasDescription = plasp::sas::Description::fromStream(std::cin); + const auto sasTranslator = plasp::sas::TranslatorASP(sasDescription); + sasTranslator.translate(std::cout); } } - catch (const std::exception &e) + else if (format == "pddl") { - std::cerr << "Error: " << e.what() << std::endl << std::endl; - printHelp(); - return EXIT_FAILURE; + if (variablesMap.count("input")) + { + const auto &inputFiles = variablesMap["input"].as>(); + const auto pddlDescription = plasp::pddl::Description::fromFiles(inputFiles); + } + else + const auto pddlDescription = plasp::pddl::Description::fromStream(std::cin); + + //std::cout << pddlDescription << std::endl; } return EXIT_SUCCESS; diff --git a/include/plasp/pddl/Problem.h b/include/plasp/pddl/Problem.h index 37bae97..945eed0 100644 --- a/include/plasp/pddl/Problem.h +++ b/include/plasp/pddl/Problem.h @@ -22,10 +22,9 @@ class Problem public: Problem(Context &context, Domain &domain); + void findSections(); void parse(); - bool isDeclared() const; - Domain &domain(); const Domain &domain() const; @@ -44,8 +43,6 @@ class Problem void checkConsistency(); private: - void parseSection(); - void parseRequirementSection(); void computeDerivedRequirements(); @@ -57,13 +54,18 @@ class Problem Context &m_context; Domain &m_domain; - bool m_isDeclared; std::string m_name; + + utils::Parser::Position m_domainPosition; + + utils::Parser::Position m_requirementsPosition; Requirements m_requirements; + utils::Parser::Position m_objectsPosition; expressions::Constants m_objects; + utils::Parser::Position m_initialStatePosition; std::unique_ptr m_initialState; }; diff --git a/src/plasp/pddl/Description.cpp b/src/plasp/pddl/Description.cpp index 8566402..deb2984 100644 --- a/src/plasp/pddl/Description.cpp +++ b/src/plasp/pddl/Description.cpp @@ -148,8 +148,8 @@ void Description::findSections() m_problemPosition = position; - skipSection(parser); - skipSection(parser); + parser.seek(position); + m_problem->findSections(); } else { diff --git a/src/plasp/pddl/Domain.cpp b/src/plasp/pddl/Domain.cpp index c0332ea..fb3c70d 100644 --- a/src/plasp/pddl/Domain.cpp +++ b/src/plasp/pddl/Domain.cpp @@ -69,6 +69,8 @@ void Domain::findSections() parser.expect("("); parser.expect(":"); + const auto sectionIdentifierPosition = parser.position(); + // Save the parser position of the individual sections for later parsing if (parser.probe("requirements")) setSectionPosition("requirements", m_requirementsPosition, position, true); @@ -88,9 +90,13 @@ void Domain::findSections() || parser.probe("durative-action") || parser.probe("derived")) { - parser.seek(position); - m_context.logger.parserWarning(parser, "Section type currently unsupported"); - parser.advance(); + parser.seek(sectionIdentifierPosition); + + const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); + + m_context.logger.parserWarning(parser, "Section type \"" + sectionIdentifier + "\" currently unsupported"); + + parser.seek(sectionIdentifierPosition); } else { diff --git a/src/plasp/pddl/Problem.cpp b/src/plasp/pddl/Problem.cpp index 35f7c14..0b63633 100644 --- a/src/plasp/pddl/Problem.cpp +++ b/src/plasp/pddl/Problem.cpp @@ -23,45 +23,118 @@ namespace pddl Problem::Problem(Context &context, Domain &domain) : m_context(context), m_domain(domain), - m_isDeclared{false} + m_domainPosition{-1}, + m_requirementsPosition{-1}, + m_objectsPosition{-1}, + m_initialStatePosition{-1} { } //////////////////////////////////////////////////////////////////////////////////////////////////// +void Problem::findSections() +{ + auto &parser = m_context.parser; + + parser.expect("("); + parser.expect("define"); + parser.expect("("); + parser.expect("problem"); + + m_name = parser.parseIdentifier(isIdentifier); + + std::cout << "Found problem " << m_name << std::endl; + + parser.expect(")"); + + const auto setSectionPosition = + [&](const std::string §ionName, auto §ionPosition, const auto value, bool unique = false) + { + if (unique && sectionPosition != -1) + throw utils::ParserException(parser, "Only one \":" + sectionName + "\" section allowed"); + + sectionPosition = value; + }; + + parser.skipWhiteSpace(); + + while (parser.currentCharacter() != ')') + { + const auto position = parser.position(); + + parser.expect("("); + parser.expect(":"); + + const auto sectionIdentifierPosition = parser.position(); + + // TODO: check order of the sections + if (parser.probe("domain")) + setSectionPosition("domain", m_domainPosition, position, true); + else if (parser.probe("requirements")) + setSectionPosition("requirements", m_requirementsPosition, position, true); + else if (parser.probe("objects")) + setSectionPosition("objects", m_objectsPosition, position, true); + else if (parser.probe("init")) + setSectionPosition("init", m_initialStatePosition, position, true); + else if (parser.probe("goal") + || parser.probe("constraints") + || parser.probe("metric") + || parser.probe("length")) + { + parser.seek(sectionIdentifierPosition); + + const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); + + m_context.logger.parserWarning(parser, "Section type \"" + sectionIdentifier + "\" currently unsupported"); + + parser.seek(sectionIdentifierPosition); + } + else + { + const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); + + parser.seek(position); + throw utils::ParserException(m_context.parser, "Unknown problem section \"" + sectionIdentifier + "\""); + } + + // Skip section for now and parse it later + skipSection(parser); + + parser.skipWhiteSpace(); + } + + parser.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + void Problem::parse() { - m_context.parser.expect("("); - m_context.parser.expect("define"); - m_context.parser.expect("("); - m_context.parser.expect("problem"); + auto &parser = m_context.parser; - m_name = m_context.parser.parseIdentifier(isIdentifier); + if (m_domainPosition == -1) + throw ConsistencyException("Problem description does not specify the corresponding domain"); - std::cout << "Parsing problem " << m_name << std::endl; + parser.seek(m_domainPosition); + parseDomainSection(); - m_context.parser.expect(")"); - - while (true) + if (m_requirementsPosition != -1) { - m_context.parser.skipWhiteSpace(); - - if (m_context.parser.currentCharacter() == ')') - break; - - parseSection(); + parser.seek(m_requirementsPosition); + parseRequirementSection(); } - computeDerivedRequirements(); + if (m_objectsPosition != -1) + { + parser.seek(m_objectsPosition); + parseObjectSection(); + } - m_isDeclared = true; -} + if (m_initialStatePosition == -1) + throw ConsistencyException("Problem description does not specify an initial state"); -//////////////////////////////////////////////////////////////////////////////////////////////////// - -bool Problem::isDeclared() const -{ - return m_isDeclared; + parser.seek(m_initialStatePosition); + parseInitialStateSection(); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -108,64 +181,43 @@ const expressions::Constants &Problem::objects() const //////////////////////////////////////////////////////////////////////////////////////////////////// -void Problem::parseSection() +void Problem::parseDomainSection() { auto &parser = m_context.parser; parser.expect("("); parser.expect(":"); + parser.expect("domain"); - // TODO: check order of the sections - if (parser.probe("domain")) - parseDomainSection(); - else if (parser.probe("requirements")) - parseRequirementSection(); - else if (parser.probe("objects")) - parseObjectSection(); - else if (parser.probe("init")) - parseInitialStateSection(); - else if (parser.probe("goal") - || parser.probe("constraints") - || parser.probe("metric") - || parser.probe("length")) - { - std::cout << "Skipping section" << std::endl; - skipSection(m_context.parser); - } - else - { - const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); - throw utils::ParserException(m_context.parser, "Unknown problem section \"" + sectionIdentifier + "\""); - } -} + parser.skipWhiteSpace(); -//////////////////////////////////////////////////////////////////////////////////////////////////// - -void Problem::parseDomainSection() -{ - m_context.parser.skipWhiteSpace(); - - const auto domainName = m_context.parser.parseIdentifier(isIdentifier); + const auto domainName = parser.parseIdentifier(isIdentifier); if (m_domain.name() != domainName) - throw utils::ParserException(m_context.parser, "Domains do not match (\"" + m_domain.name() + "\" and \"" + domainName + "\")"); + throw utils::ParserException(parser, "Domains do not match (\"" + m_domain.name() + "\" and \"" + domainName + "\")"); - m_context.parser.expect(")"); + parser.expect(")"); } //////////////////////////////////////////////////////////////////////////////////////////////////// void Problem::parseRequirementSection() { - m_context.parser.skipWhiteSpace(); + auto &parser = m_context.parser; - while (m_context.parser.currentCharacter() != ')') + parser.expect("("); + parser.expect(":"); + parser.expect("requirements"); + + parser.skipWhiteSpace(); + + while (parser.currentCharacter() != ')') { - m_context.parser.expect(":"); + parser.expect(":"); m_requirements.emplace_back(Requirement::parse(m_context)); - m_context.parser.skipWhiteSpace(); + parser.skipWhiteSpace(); } // TODO: do this check only once the domain is parsed @@ -173,7 +225,7 @@ void Problem::parseRequirementSection() if (m_requirements.empty()) m_requirements.emplace_back(Requirement::Type::STRIPS); - m_context.parser.expect(")"); + parser.expect(")"); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -246,21 +298,33 @@ void Problem::computeDerivedRequirements() void Problem::parseObjectSection() { - m_context.parser.skipWhiteSpace(); + auto &parser = m_context.parser; + + parser.expect("("); + parser.expect(":"); + parser.expect("objects"); + + parser.skipWhiteSpace(); // Store constants expressions::Constant::parseTypedDeclarations(m_context, *this); - m_context.parser.expect(")"); + parser.expect(")"); } //////////////////////////////////////////////////////////////////////////////////////////////////// void Problem::parseInitialStateSection() { + auto &parser = m_context.parser; + + parser.expect("("); + parser.expect(":"); + parser.expect("init"); + m_initialState = InitialState::parseDeclaration(m_context, *this); - m_context.parser.expect(")"); + parser.expect(")"); } ////////////////////////////////////////////////////////////////////////////////////////////////////