Made Parser seekable for easier maintenance.
This commit is contained in:
@@ -18,9 +18,8 @@ namespace pddl
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Description::Description(std::istream &istream)
|
||||
: m_parser(istream),
|
||||
m_context(m_parser),
|
||||
Description::Description()
|
||||
: m_context(m_parser),
|
||||
m_domain{std::make_unique<Domain>(Domain(m_context))},
|
||||
m_problem{std::make_unique<Problem>(Problem(m_context, *m_domain))}
|
||||
{
|
||||
@@ -31,9 +30,9 @@ Description::Description(std::istream &istream)
|
||||
|
||||
Description Description::fromStream(std::istream &istream)
|
||||
{
|
||||
Description description(istream);
|
||||
Description description;
|
||||
|
||||
description.m_parser.setFileName("std::cin");
|
||||
description.m_parser.readStream("std::cin", istream);
|
||||
|
||||
description.parseContent();
|
||||
description.checkConsistency();
|
||||
@@ -47,29 +46,15 @@ Description Description::fromFiles(const std::vector<std::string> &paths)
|
||||
{
|
||||
BOOST_ASSERT(!paths.empty());
|
||||
|
||||
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 + "\"");
|
||||
});
|
||||
|
||||
std::ifstream fileStream;
|
||||
Description description(fileStream);
|
||||
Description description;
|
||||
|
||||
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.m_parser.readFile(path);
|
||||
});
|
||||
|
||||
description.parseContent();
|
||||
description.checkConsistency();
|
||||
|
||||
return description;
|
||||
@@ -92,7 +77,7 @@ void Description::parseContent()
|
||||
{
|
||||
m_context.parser.skipWhiteSpace();
|
||||
|
||||
if (m_context.parser.atEndOfFile())
|
||||
if (m_context.parser.atEndOfStream())
|
||||
return;
|
||||
|
||||
m_context.parser.expect<std::string>("(");
|
||||
|
@@ -30,18 +30,11 @@ Description::Description()
|
||||
|
||||
Description Description::fromStream(std::istream &istream)
|
||||
{
|
||||
utils::Parser parser;
|
||||
parser.readStream("std::cin", istream);
|
||||
|
||||
Description description;
|
||||
|
||||
utils::Parser parser(istream);
|
||||
|
||||
description.parseVersionSection(parser);
|
||||
description.parseMetricSection(parser);
|
||||
description.parseVariablesSection(parser);
|
||||
description.parseMutexSection(parser);
|
||||
description.parseInitialStateSection(parser);
|
||||
description.parseGoalSection(parser);
|
||||
description.parseOperatorSection(parser);
|
||||
description.parseAxiomSection(parser);
|
||||
description.parseContent(parser);
|
||||
|
||||
return description;
|
||||
}
|
||||
@@ -53,9 +46,13 @@ Description Description::fromFile(const boost::filesystem::path &path)
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
throw std::runtime_error("File does not exist: \"" + path.string() + "\"");
|
||||
|
||||
std::ifstream fileStream(path.string(), std::ios::in);
|
||||
utils::Parser parser;
|
||||
parser.readFile(path);
|
||||
|
||||
return Description::fromStream(fileStream);
|
||||
Description description;
|
||||
description.parseContent(parser);
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -146,6 +143,20 @@ bool Description::usesConditionalEffects() const
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseContent(utils::Parser &parser)
|
||||
{
|
||||
parseVersionSection(parser);
|
||||
parseMetricSection(parser);
|
||||
parseVariablesSection(parser);
|
||||
parseMutexSection(parser);
|
||||
parseInitialStateSection(parser);
|
||||
parseGoalSection(parser);
|
||||
parseOperatorSection(parser);
|
||||
parseAxiomSection(parser);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseVersionSection(utils::Parser &parser) const
|
||||
{
|
||||
parser.expect<std::string>("begin_version");
|
||||
|
@@ -27,12 +27,16 @@ void Logger::setPedantic(bool isPedantic)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Logger::parserWarning(const Parser &parser, const std::string &text)
|
||||
void Logger::parserWarning(const Parser &parser, const std::string &message)
|
||||
{
|
||||
if (m_isPedantic)
|
||||
throw ParserWarning(parser, text);
|
||||
throw ParserWarning(parser, message);
|
||||
|
||||
std::cerr << "Warning: " << parser.fileName() << ":" << parser.row() << ":" << parser.column() << " " << text << std::endl;
|
||||
const auto coordinate = parser.coordinate();
|
||||
|
||||
std::cerr << "Warning: " << coordinate.sectionName << ":"
|
||||
<< std::to_string(coordinate.row) + ":" + std::to_string(coordinate.column)
|
||||
<< " " << message << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include <plasp/utils/Parser.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
@@ -21,56 +22,116 @@ const std::istreambuf_iterator<char> Parser::EndOfFile = std::istreambuf_iterato
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser::Parser(std::istream &istream)
|
||||
: m_istream(istream),
|
||||
m_position(m_istream),
|
||||
m_row{1},
|
||||
m_column{1},
|
||||
m_isCaseSensitive{true},
|
||||
m_atEndOfFile{false}
|
||||
Parser::Parser()
|
||||
: m_isCaseSensitive{true}
|
||||
{
|
||||
std::setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// Don’t skip whitespace
|
||||
istream.exceptions(std::istream::badbit);
|
||||
m_stream.exceptions(std::istream::badbit);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::setFileName(std::string fileName)
|
||||
Parser::Parser(std::string streamName, std::istream &istream)
|
||||
: Parser()
|
||||
{
|
||||
m_fileName = fileName;
|
||||
readStream(streamName, istream);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const std::string &Parser::fileName() const
|
||||
void Parser::readStream(std::string streamName, std::istream &istream)
|
||||
{
|
||||
return m_fileName;
|
||||
// Store position of new section
|
||||
const auto position = m_stream.tellp();
|
||||
|
||||
m_streamDelimiters.push_back({position, streamName});
|
||||
|
||||
m_stream << istream.rdbuf();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::resetPosition()
|
||||
void Parser::readFile(const boost::filesystem::path &path)
|
||||
{
|
||||
m_row = 1;
|
||||
m_column = 1;
|
||||
m_atEndOfFile = false;
|
||||
m_position = std::istreambuf_iterator<char>(m_istream);
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
throw std::runtime_error("File does not exist: \"" + path.string() + "\"");
|
||||
|
||||
std::ifstream fileStream(path.string(), std::ios::in);
|
||||
|
||||
readStream(path.string(), fileStream);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Parser::row() const
|
||||
void Parser::reset()
|
||||
{
|
||||
return m_row;
|
||||
m_stream.clear();
|
||||
seek(std::ios::beg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Parser::column() const
|
||||
void Parser::seek(Position position)
|
||||
{
|
||||
return m_column;
|
||||
m_stream.clear();
|
||||
m_stream.seekg(position);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser::Position Parser::position() const
|
||||
{
|
||||
return m_stream.tellg();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser::Coordinate Parser::coordinate() const
|
||||
{
|
||||
const auto currentPosition = position();
|
||||
|
||||
// Find current section
|
||||
auto currentFile = std::find_if(m_streamDelimiters.crbegin(), m_streamDelimiters.crend(),
|
||||
[&](const auto &fileDelimiter)
|
||||
{
|
||||
return currentPosition >= fileDelimiter.position;
|
||||
});
|
||||
|
||||
// If the parser is at the end of the stream, still count from the beginning of the last section
|
||||
if (currentFile == m_streamDelimiters.crend())
|
||||
currentFile = m_streamDelimiters.crbegin();
|
||||
|
||||
// Go back to beginning of section
|
||||
m_stream.clear();
|
||||
m_stream.seekg(currentFile->position);
|
||||
|
||||
size_t row = 1;
|
||||
size_t column = 1;
|
||||
|
||||
// Compute the coordinate character by character
|
||||
while (true)
|
||||
{
|
||||
if (currentPosition == -1 && atEndOfStream())
|
||||
break;
|
||||
else if (currentPosition >= 0 && position() >= currentPosition)
|
||||
break;
|
||||
|
||||
const auto character = currentCharacter();
|
||||
|
||||
if (character == '\n')
|
||||
{
|
||||
row++;
|
||||
column = 1;
|
||||
}
|
||||
else if (std::isblank(character) || std::isprint(character))
|
||||
column++;
|
||||
|
||||
m_stream.ignore(1);
|
||||
}
|
||||
|
||||
return {currentFile->sectionName, row, column};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -84,29 +145,27 @@ void Parser::setCaseSensitive(bool isCaseSensitive)
|
||||
|
||||
char Parser::currentCharacter() const
|
||||
{
|
||||
checkStream();
|
||||
|
||||
if (m_isCaseSensitive)
|
||||
return *m_position;
|
||||
return m_stream.peek();
|
||||
|
||||
return std::tolower(*m_position);
|
||||
return std::tolower(m_stream.peek());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Parser::atEndOfFile() const
|
||||
bool Parser::atEndOfStream() const
|
||||
{
|
||||
return m_position.equal(EndOfFile);
|
||||
return position() == -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::checkStream() const
|
||||
{
|
||||
if (atEndOfFile())
|
||||
if (atEndOfStream())
|
||||
throw ParserException(*this, "Reading past end of file");
|
||||
|
||||
if (m_istream.fail())
|
||||
if (m_stream.fail())
|
||||
throw ParserException(*this);
|
||||
}
|
||||
|
||||
@@ -115,18 +174,7 @@ void Parser::checkStream() const
|
||||
void Parser::advance()
|
||||
{
|
||||
checkStream();
|
||||
|
||||
const auto character = currentCharacter();
|
||||
|
||||
if (character == '\n')
|
||||
{
|
||||
m_row++;
|
||||
m_column = 1;
|
||||
}
|
||||
else if (std::isblank(character) || std::isprint(character))
|
||||
m_column++;
|
||||
|
||||
m_position++;
|
||||
m_stream.ignore(1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -246,7 +294,7 @@ uint64_t Parser::parseIntegerBody()
|
||||
|
||||
uint64_t value = 0;
|
||||
|
||||
while (!atEndOfFile())
|
||||
while (!atEndOfStream())
|
||||
{
|
||||
const auto character = currentCharacter();
|
||||
|
||||
|
Reference in New Issue
Block a user