summaryrefslogtreecommitdiff
path: root/src/core/parser/generic
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/parser/generic')
-rw-r--r--src/core/parser/generic/ParserState.cpp161
-rw-r--r--src/core/parser/generic/ParserState.hpp284
-rw-r--r--src/core/parser/generic/ParserStateStack.cpp216
-rw-r--r--src/core/parser/generic/ParserStateStack.hpp361
4 files changed, 1022 insertions, 0 deletions
diff --git a/src/core/parser/generic/ParserState.cpp b/src/core/parser/generic/ParserState.cpp
new file mode 100644
index 0000000..f635d86
--- /dev/null
+++ b/src/core/parser/generic/ParserState.cpp
@@ -0,0 +1,161 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ParserState.hpp"
+
+namespace ousia {
+
+/* Class ParserState */
+
+ParserState::ParserState() : elementHandler(nullptr) {}
+
+ParserState::ParserState(ParserStateSet parents, Arguments arguments,
+ RttiSet createdNodeTypes,
+ HandlerConstructor elementHandler)
+ : parents(parents),
+ arguments(arguments),
+ createdNodeTypes(createdNodeTypes),
+ elementHandler(elementHandler)
+{
+}
+
+ParserState::ParserState(const ParserStateBuilder &builder)
+ : ParserState(builder.build())
+{
+}
+
+/* Class ParserStateBuilder */
+
+ParserStateBuilder &ParserStateBuilder::copy(const ParserState &state)
+{
+ this->state = state;
+ return *this;
+}
+
+ParserStateBuilder &ParserStateBuilder::parent(const ParserState *parent)
+{
+ state.parents = ParserStateSet{parent};
+ return *this;
+}
+
+ParserStateBuilder &ParserStateBuilder::parents(const ParserStateSet &parents)
+{
+ state.parents = parents;
+ return *this;
+}
+
+ParserStateBuilder &ParserStateBuilder::arguments(const Arguments &arguments)
+{
+ state.arguments = arguments;
+ return *this;
+}
+
+ParserStateBuilder &ParserStateBuilder::createdNodeType(const Rtti *type)
+{
+ state.createdNodeTypes = RttiSet{type};
+ return *this;
+}
+
+ParserStateBuilder &ParserStateBuilder::createdNodeTypes(const RttiSet &types)
+{
+ state.createdNodeTypes = types;
+ return *this;
+}
+
+ParserStateBuilder &ParserStateBuilder::elementHandler(
+ HandlerConstructor elementHandler)
+{
+ state.elementHandler = elementHandler;
+ return *this;
+}
+
+const ParserState &ParserStateBuilder::build() const { return state; }
+
+/* Class ParserStateDeductor */
+
+ParserStateDeductor::ParserStateDeductor(
+ std::vector<const Rtti *> signature,
+ std::vector<const ParserState *> states)
+ : tbl(signature.size()),
+ signature(std::move(signature)),
+ states(std::move(states))
+{
+}
+
+bool ParserStateDeductor::isActive(size_t d, const ParserState *s)
+{
+ // Lookup the "active" state of (d, s), if it was not already set
+ // (e.second is true) we'll have to calculate it
+ auto e = tbl[d].emplace(s, false);
+ bool &res = e.first->second;
+ if (!e.second) {
+ return res;
+ }
+
+ // Check whether this node is generative (may have produced the Node
+ // described by the current Signature element)
+ bool isGenerative = signature[d]->isOneOf(s->createdNodeTypes);
+
+ if (isGenerative && d == 0) {
+ // End of recursion -- the last signature element is reached and the
+ // node was generative
+ res = true;
+ } else {
+ // Try repetition of this node
+ if (isGenerative && isActive(d - 1, s)) {
+ res = true;
+ } else {
+ // Check whether any of the parent nodes were active -- either for
+ // the previous element (if this one is generative) or for the
+ // current element (assuming this node was not generative)
+ for (const ParserState *parent : s->parents) {
+ if ((isGenerative && isActive(d - 1, parent)) ||
+ isActive(d, parent)) {
+ res = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return res;
+}
+
+std::vector<const ParserState *> ParserStateDeductor::deduce()
+{
+ std::vector<const ParserState *> res;
+ if (!signature.empty()) {
+ const size_t D = signature.size();
+ for (auto s : states) {
+ if (signature[D - 1]->isOneOf(s->createdNodeTypes) &&
+ isActive(D - 1, s)) {
+ res.push_back(s);
+ }
+ }
+ }
+ return res;
+}
+
+/* Constant initializations */
+
+namespace ParserStates {
+const ParserState All;
+const ParserState None;
+}
+}
+
diff --git a/src/core/parser/generic/ParserState.hpp b/src/core/parser/generic/ParserState.hpp
new file mode 100644
index 0000000..6487fdd
--- /dev/null
+++ b/src/core/parser/generic/ParserState.hpp
@@ -0,0 +1,284 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file ParserState.hpp
+ *
+ * Defines the ParserState class used within the ParserStack pushdown
+ * automaton and the ParserStateBuilder class for convenient construction of
+ * such classes.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_PARSER_STATE_HPP_
+#define _OUSIA_PARSER_STATE_HPP_
+
+#include <unordered_set>
+
+#include <core/common/Rtti.hpp>
+#include <core/common/Argument.hpp>
+
+namespace ousia {
+
+// Forward declarations
+class ParserStateBuilder;
+class ParserState;
+class HandlerData;
+class Handler;
+using HandlerConstructor = Handler *(*)(const HandlerData &handlerData);
+
+/**
+ * Set of pointers of parser states -- used for specifying a set of parent
+ * states.
+ */
+using ParserStateSet = std::unordered_set<const ParserState *>;
+
+/**
+ * Class used for the complete specification of a ParserState. Stores possible
+ * parent states, state handlers and arguments to be passed to that state.
+ */
+struct ParserState {
+ /**
+ * Vector containing all possible parent states.
+ */
+ ParserStateSet parents;
+
+ /**
+ * Descriptor of the arguments that should be passed to the handler.
+ */
+ Arguments arguments;
+
+ /**
+ * Set containing the types of the nodes that may be created in this
+ * ParserState. This information is needed for Parsers to reconstruct the
+ * current ParserState from a given ParserScope when a file is included.
+ */
+ RttiSet createdNodeTypes;
+
+ /**
+ * Pointer at a function which creates a new concrete Handler instance for
+ * the elements described by this state. May be nullptr in which case no
+ * handler instance is created.
+ */
+ HandlerConstructor elementHandler;
+
+ /**
+ * Default constructor, initializes the handlers with nullptr.
+ */
+ ParserState();
+
+ /**
+ * Constructor taking values for all fields. Use the ParserStateBuilder
+ * class for a more convenient construction of ParserState instances.
+ *
+ * @param parents is a vector containing all possible parent states.
+ * @param arguments is a descriptor of arguments that should be passed to
+ * the handler.
+ * @param createdNodeTypes is a set containing the types of the nodes tha
+ * may be created in this ParserState. This information is needed for
+ * Parsers to reconstruct the current ParserState from a given ParserScope
+ * when a file is included.
+ * @param elementHandler is a pointer at a function which creates a new
+ * concrete Handler instance for the elements described by this state. May
+ * be nullptr in which case no handler instance is created.
+ */
+ ParserState(ParserStateSet parents, Arguments arguments = Arguments{},
+ RttiSet createdNodeTypes = RttiSet{},
+ HandlerConstructor elementHandler = nullptr);
+
+ /**
+ * Creates this ParserState from the given ParserStateBuilder instance.
+ */
+ ParserState(const ParserStateBuilder &builder);
+};
+
+/**
+ * The ParserStateBuilder class is a class used for conveniently building new
+ * ParserState instances.
+ */
+class ParserStateBuilder {
+private:
+ /**
+ * ParserState instance that is currently being built by the
+ * ParserStateBuilder.
+ */
+ ParserState state;
+
+public:
+ /**
+ * Copies the ParserState instance and uses it as internal state. Overrides
+ * all changes made by the ParserStateBuilder.
+ *
+ * @param state is the state that should be copied.
+ * @return a reference at this ParserStateBuilder instance for method
+ * chaining.
+ */
+ ParserStateBuilder &copy(const ParserState &state);
+
+ /**
+ * Sets the possible parent states to the single given parent element.
+ *
+ * @param parent is a pointer at the parent ParserState instance that should
+ * be the possible parent state.
+ * @return a reference at this ParserStateBuilder instance for method
+ * chaining.
+ */
+ ParserStateBuilder &parent(const ParserState *parent);
+
+ /**
+ * Sets the ParserState instances in the given ParserStateSet as the list of
+ * supported parent states.
+ *
+ * @param parents is a set of pointers at ParserState instances that should
+ * be the possible parent states.
+ * @return a reference at this ParserStateBuilder instance for method
+ * chaining.
+ */
+ ParserStateBuilder &parents(const ParserStateSet &parents);
+
+ /**
+ * Sets the arguments that should be passed to the parser state handler to
+ * those given as argument.
+ *
+ * @param arguments is the Arguments instance describing the Arguments that
+ * should be parsed to a Handler for this ParserState.
+ * @return a reference at this ParserStateBuilder instance for method
+ * chaining.
+ */
+ ParserStateBuilder &arguments(const Arguments &arguments);
+
+ /**
+ * Sets the Node types this state may produce to the given Rtti descriptor.
+ *
+ * @param type is the Rtti descriptor of the Type that may be produced by
+ * this state.
+ * @return a reference at this ParserStateBuilder instance for method
+ * chaining.
+ */
+ ParserStateBuilder &createdNodeType(const Rtti *type);
+
+ /**
+ * Sets the Node types this state may produce to the given Rtti descriptors.
+ *
+ * @param types is a set of Rtti descriptors of the Types that may be
+ * produced by this state.
+ * @return a reference at this ParserStateBuilder instance for method
+ * chaining.
+ */
+ ParserStateBuilder &createdNodeTypes(const RttiSet &types);
+
+ /**
+ * Sets the constructor for the element handler. The constructor creates a
+ * new concrete Handler instance for the elements described by this state.
+ * May be nullptr in which case no handler instance is created (this is
+ * the default value).
+ *
+ * @param elementHandler is the HandlerConstructor that should create a
+ * new Handler instance.
+ * @return a reference at this ParserStateBuilder instance for method
+ * chaining.
+ */
+ ParserStateBuilder &elementHandler(HandlerConstructor elementHandler);
+
+ /**
+ * Returns a reference at the internal ParserState instance that was built
+ * using the ParserStateBuilder.
+ *
+ * @return the built ParserState.
+ */
+ const ParserState &build() const;
+};
+
+/**
+ * Class used to deduce the ParserState a Parser is currently in based on the
+ * types of the Nodes that currently are on the ParserStack. Uses dynamic
+ * programming in order to solve this problem.
+ */
+class ParserStateDeductor {
+public:
+ /**
+ * Type containing the dynamic programming table.
+ */
+ using Table = std::vector<std::unordered_map<const ParserState *, bool>>;
+
+private:
+ /**
+ * Dynamic programming table.
+ */
+ Table tbl;
+
+ /**
+ * Signature given in the constructor.
+ */
+ const std::vector<const Rtti *> signature;
+
+ /**
+ * List of states that should be checked for being active.
+ */
+ const std::vector<const ParserState *> states;
+
+ /**
+ * Used internally to check whether the given parser stack s may have been
+ * active for signature element d.
+ *
+ * @param d is the signature element.
+ * @param s is the parser state.
+ * @return true if the the given ParserState may have been active.
+ */
+ bool isActive(size_t d, const ParserState *s);
+
+public:
+ /**
+ * Constructor of the ParserStateDeductor class.
+ *
+ * @param signature a Node type signature describing the types of the nodes
+ * which currently reside on e.g. the ParserScope stack.
+ * @param states is a list of states that should be checked.
+ */
+ ParserStateDeductor(std::vector<const Rtti *> signature,
+ std::vector<const ParserState *> states);
+
+ /**
+ * Selects all active states from the given states. Only considers those
+ * states that may have produced the last signature element.
+ *
+ * @return a list of states that may actually have been active.
+ */
+ std::vector<const ParserState *> deduce();
+};
+
+/**
+ * The ParserStates namespace contains all the global state constants used
+ * in the ParserStack class.
+ */
+namespace ParserStates {
+/**
+ * State representing all states.
+ */
+extern const ParserState All;
+
+/**
+ * State representing the initial state.
+ */
+extern const ParserState None;
+}
+}
+
+#endif /* _OUSIA_PARSER_STATE_HPP_ */
+
diff --git a/src/core/parser/generic/ParserStateStack.cpp b/src/core/parser/generic/ParserStateStack.cpp
new file mode 100644
index 0000000..1265851
--- /dev/null
+++ b/src/core/parser/generic/ParserStateStack.cpp
@@ -0,0 +1,216 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <sstream>
+
+#include <core/common/Utils.hpp>
+#include <core/common/Exceptions.hpp>
+#include <core/model/Project.hpp>
+
+#include "ParserScope.hpp"
+#include "ParserStack.hpp"
+
+namespace ousia {
+
+/* A default handler */
+
+/**
+ * The DefaultHandler class is used in case no element handler is specified in
+ * the ParserState descriptor.
+ */
+class DefaultHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(Variant::mapType &args) override {}
+
+ void end() override {}
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new DefaultHandler{handlerData};
+ }
+};
+
+/* Class Handler */
+
+void Handler::data(const std::string &data, int field)
+{
+ if (Utils::hasNonWhitepaceChar(data)) {
+ logger().error("Expected command but found character data.");
+ }
+}
+
+/* Class ParserStack */
+
+/**
+ * Returns an Exception that should be thrown when a currently invalid command
+ * is thrown.
+ */
+static LoggableException InvalidCommand(const std::string &name,
+ const std::set<std::string> &expected)
+{
+ if (expected.empty()) {
+ return LoggableException{
+ std::string{"No nested elements allowed, but got \""} + name +
+ std::string{"\""}};
+ } else {
+ return LoggableException{
+ std::string{"Expected "} +
+ (expected.size() == 1 ? std::string{"\""}
+ : std::string{"one of \""}) +
+ Utils::join(expected, "\", \"") + std::string{"\", but got \""} +
+ name + std::string{"\""}};
+ }
+}
+
+ParserStack::ParserStack(
+ ParserContext &ctx,
+ const std::multimap<std::string, const ParserState *> &states)
+ : ctx(ctx), states(states)
+{
+}
+
+bool ParserStack::deduceState()
+{
+ // Assemble all states
+ std::vector<const ParserState *> states;
+ for (const auto &e : this->states) {
+ states.push_back(e.second);
+ }
+
+ // Fetch the type signature of the scope and derive all possible states,
+ // abort if no unique parser state was found
+ std::vector<const ParserState *> possibleStates =
+ ParserStateDeductor(ctx.getScope().getStackTypeSignature(), states)
+ .deduce();
+ if (possibleStates.size() != 1) {
+ ctx.getLogger().error(
+ "Error while including file: Cannot deduce parser state.");
+ return false;
+ }
+
+ // Switch to this state by creating a dummy handler
+ const ParserState *state = possibleStates[0];
+ Handler *handler =
+ DefaultHandler::create({ctx, "", *state, *state, SourceLocation{}});
+ stack.emplace(handler);
+ return true;
+}
+
+std::set<std::string> ParserStack::expectedCommands()
+{
+ const ParserState *currentState = &(this->currentState());
+ std::set<std::string> res;
+ for (const auto &v : states) {
+ if (v.second->parents.count(currentState)) {
+ res.insert(v.first);
+ }
+ }
+ return res;
+}
+
+const ParserState &ParserStack::currentState()
+{
+ return stack.empty() ? ParserStates::None : stack.top()->state();
+}
+
+std::string ParserStack::currentCommandName()
+{
+ return stack.empty() ? std::string{} : stack.top()->name();
+}
+
+const ParserState *ParserStack::findTargetState(const std::string &name)
+{
+ const ParserState *currentState = &(this->currentState());
+ auto range = states.equal_range(name);
+ for (auto it = range.first; it != range.second; it++) {
+ const ParserStateSet &parents = it->second->parents;
+ if (parents.count(currentState) || parents.count(&ParserStates::All)) {
+ return it->second;
+ }
+ }
+
+ return nullptr;
+}
+
+void ParserStack::start(const std::string &name, Variant::mapType &args,
+ const SourceLocation &location)
+{
+ ParserState const *targetState = findTargetState(name);
+// TODO: Andreas, please improve this.
+// if (!Utils::isIdentifier(name)) {
+// throw LoggableException(std::string("Invalid identifier \"") + name +
+// std::string("\""));
+// }
+
+ if (targetState == nullptr) {
+ targetState = findTargetState("*");
+ }
+ if (targetState == nullptr) {
+ throw InvalidCommand(name, expectedCommands());
+ }
+
+ // Fetch the associated constructor
+ HandlerConstructor ctor = targetState->elementHandler
+ ? targetState->elementHandler
+ : DefaultHandler::create;
+
+ // Canonicalize the arguments, allow additional arguments
+ targetState->arguments.validateMap(args, ctx.getLogger(), true);
+
+ // Instantiate the handler and call its start function
+ Handler *handler = ctor({ctx, name, *targetState, currentState(), location});
+ handler->start(args);
+ stack.emplace(handler);
+}
+
+void ParserStack::start(std::string name, const Variant::mapType &args,
+ const SourceLocation &location)
+{
+ Variant::mapType argsCopy(args);
+ start(name, argsCopy);
+}
+
+void ParserStack::end()
+{
+ // Check whether the current command could be ended
+ if (stack.empty()) {
+ throw LoggableException{"No command to end."};
+ }
+
+ // Remove the current HandlerInstance from the stack
+ std::shared_ptr<Handler> inst{stack.top()};
+ stack.pop();
+
+ // Call the end function of the last Handler
+ inst->end();
+}
+
+void ParserStack::data(const std::string &data, int field)
+{
+ // Check whether there is any command the data can be sent to
+ if (stack.empty()) {
+ throw LoggableException{"No command to receive data."};
+ }
+
+ // Pass the data to the current Handler instance
+ stack.top()->data(data, field);
+}
+}
+
diff --git a/src/core/parser/generic/ParserStateStack.hpp b/src/core/parser/generic/ParserStateStack.hpp
new file mode 100644
index 0000000..efc4e4a
--- /dev/null
+++ b/src/core/parser/generic/ParserStateStack.hpp
@@ -0,0 +1,361 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file ParserStack.hpp
+ *
+ * Helper classes for document or description parsers. Contains the ParserStack
+ * class, which is an pushdown automaton responsible for accepting commands in
+ * the correct order and calling specified handlers.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_PARSER_STACK_HPP_
+#define _OUSIA_PARSER_STACK_HPP_
+
+#include <cstdint>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <stack>
+#include <vector>
+
+#include <core/common/Variant.hpp>
+#include <core/common/Logger.hpp>
+#include <core/common/Argument.hpp>
+
+#include "Parser.hpp"
+#include "ParserContext.hpp"
+#include "ParserState.hpp"
+
+namespace ousia {
+
+/**
+ * Struct collecting all the data that is being passed to a Handler instance.
+ */
+struct HandlerData {
+ /**
+ * Reference to the ParserContext instance that should be used to resolve
+ * references to nodes in the Graph.
+ */
+ ParserContext &ctx;
+
+ /**
+ * Contains the name of the tag that is being handled.
+ */
+ const std::string name;
+
+ /**
+ * Contains the current state of the state machine.
+ */
+ const ParserState &state;
+
+ /**
+ * Contains the state of the state machine when the parent node was handled.
+ */
+ const ParserState &parentState;
+
+ /**
+ * Current source code location.
+ */
+ const SourceLocation location;
+
+ /**
+ * Constructor of the HandlerData class.
+ *
+ * @param ctx is the parser context the handler should be executed in.
+ * @param name is the name of the string.
+ * @param state is the state this handler was called for.
+ * @param parentState is the state of the parent command.
+ * @param location is the location at which the handler is created.
+ */
+ HandlerData(ParserContext &ctx, std::string name, const ParserState &state,
+ const ParserState &parentState, const SourceLocation location)
+ : ctx(ctx),
+ name(std::move(name)),
+ state(state),
+ parentState(parentState),
+ location(location){};
+};
+
+/**
+ * The handler class provides a context for handling an XML tag. It has to be
+ * overridden and registered in the StateStack class to form handlers for
+ * concrete XML tags.
+ */
+class Handler {
+private:
+ /**
+ * Structure containing the internal handler data.
+ */
+ const HandlerData handlerData;
+
+public:
+ /**
+ * Constructor of the Handler class.
+ *
+ * @param data is a structure containing all data being passed to the
+ * handler.
+ */
+ Handler(const HandlerData &handlerData) : handlerData(handlerData){};
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~Handler(){};
+
+ /**
+ * Returns a reference at the ParserContext.
+ *
+ * @return a reference at the ParserContext.
+ */
+ ParserContext &context() { return handlerData.ctx; }
+
+ /**
+ * Returns the command name for which the handler was created.
+ *
+ * @return a const reference at the command name.
+ */
+ const std::string &name() { return handlerData.name; }
+
+ /**
+ * Returns a reference at the ParserScope instance.
+ *
+ * @return a reference at the ParserScope instance.
+ */
+ ParserScope &scope() { return handlerData.ctx.getScope(); }
+
+ /**
+ * Returns a reference at the Manager instance which manages all nodes.
+ *
+ * @return a referance at the Manager instance.
+ */
+ Manager &manager() { return handlerData.ctx.getManager(); }
+
+ /**
+ * Returns a reference at the Logger instance used for logging error
+ * messages.
+ *
+ * @return a reference at the Logger instance.
+ */
+ Logger &logger() { return handlerData.ctx.getLogger(); }
+
+ /**
+ * Returns a reference at the Project Node, representing the project into
+ * which the file is currently being parsed.
+ *
+ * @return a referance at the Project Node.
+ */
+ Rooted<Project> project() { return handlerData.ctx.getProject(); }
+
+ /**
+ * Reference at the ParserState descriptor for which this Handler was
+ * created.
+ *
+ * @return a const reference at the constructing ParserState descriptor.
+ */
+ const ParserState &state() { return handlerData.state; }
+
+ /**
+ * Reference at the ParserState descriptor of the parent state of the state
+ * for which this Handler was created. Set to ParserStates::None if there
+ * is no parent state.
+ *
+ * @return a const reference at the parent state of the constructing
+ * ParserState descriptor.
+ */
+ const ParserState &parentState() { return handlerData.parentState; }
+
+ /**
+ * Returns the current location in the source file.
+ *
+ * @return the current location in the source file.
+ */
+ SourceLocation location() { return handlerData.location; }
+
+ /**
+ * Called when the command that was specified in the constructor is
+ * instanciated.
+ *
+ * @param args is a map from strings to variants (argument name and value).
+ */
+ virtual void start(Variant::mapType &args) = 0;
+
+ /**
+ * Called whenever the command for which this handler is defined ends.
+ */
+ virtual void end() = 0;
+
+ /**
+ * Called whenever raw data (int the form of a string) is available for the
+ * Handler instance. In the default handler an exception is raised if the
+ * received data contains non-whitespace characters.
+ *
+ * @param data is a pointer at the character data that is available for the
+ * Handler instance.
+ * @param field is the field number (the interpretation of this value
+ * depends on the format that is being parsed).
+ */
+ virtual void data(const std::string &data, int field);
+};
+
+/**
+ * HandlerConstructor is a function pointer type used to create concrete
+ * instances of the Handler class.
+ *
+ * @param handlerData is the data that should be passed to the new handler
+ * instance.
+ * @return a newly created handler instance.
+ */
+using HandlerConstructor = Handler *(*)(const HandlerData &handlerData);
+
+/**
+ * The ParserStack class is a pushdown automaton responsible for turning a
+ * command stream into a tree of Node instances.
+ */
+class ParserStack {
+private:
+ /**
+ * Reference at the parser context.
+ */
+ ParserContext &ctx;
+
+ /**
+ * Map containing all registered command names and the corresponding
+ * state descriptors.
+ */
+ const std::multimap<std::string, const ParserState *> &states;
+
+ /**
+ * Internal stack used for managing the currently active Handler instances.
+ */
+ std::stack<std::shared_ptr<Handler>> stack;
+
+ /**
+ * Used internally to get all expected command names for the current state.
+ * This function is used to build error messages.
+ *
+ * @return a set of strings containing the names of the expected commands.
+ */
+ std::set<std::string> expectedCommands();
+
+ /**
+ * Returns the targetState for a command with the given name that can be
+ * reached from for the current state.
+ *
+ * @param name is the name of the requested command.
+ * @return nullptr if no target state was found, a pointer at the target
+ *state
+ * otherwise.
+ */
+ const ParserState *findTargetState(const std::string &name);
+
+public:
+ /**
+ * Creates a new instance of the ParserStack class.
+ *
+ * @param ctx is the parser context the parser stack is working on.
+ * @param states is a map containing the command names and pointers at the
+ * corresponding ParserState instances.
+ */
+ ParserStack(ParserContext &ctx,
+ const std::multimap<std::string, const ParserState *> &states);
+
+ /**
+ * Tries to reconstruct the parser state from the Scope instance of the
+ * ParserContext given in the constructor. This functionality is needed for
+ * including files,as the Parser of the included file needs to be brought to
+ + an equivalent state as the one in the including file.
+ *
+ * @param scope is the ParserScope instance from which the ParserState
+ * should be reconstructed.
+ * @param logger is the logger instance to which error messages should be
+ * written.
+ * @return true if the operation was sucessful, false otherwise.
+ */
+ bool deduceState();
+
+ /**
+ * Returns the state the ParserStack instance currently is in.
+ *
+ * @return the state of the currently active Handler instance or STATE_NONE
+ * if no handler is on the stack.
+ */
+ const ParserState &currentState();
+
+ /**
+ * Returns the command name that is currently being handled.
+ *
+ * @return the name of the command currently being handled by the active
+ * Handler instance or an empty string if no handler is currently active.
+ */
+ std::string currentCommandName();
+
+ /**
+ * Function that should be called whenever a new command starts.
+ *
+ * @param name is the name of the command.
+ * @param args is a map from strings to variants (argument name and value).
+ * Note that the passed map will be modified.
+ * @param location is the location in the source file at which the command
+ * starts.
+ */
+ void start(const std::string &name, Variant::mapType &args,
+ const SourceLocation &location = SourceLocation{});
+
+ /**
+ * Function that should be called whenever a new command starts.
+ *
+ * @param name is the name of the command.
+ * @param args is a map from strings to variants (argument name and value).
+ * @param location is the location in the source file at which the command
+ * starts.
+ */
+ void start(std::string name,
+ const Variant::mapType &args = Variant::mapType{},
+ const SourceLocation &location = SourceLocation{});
+
+ /**
+ * Function called whenever a command ends.
+ */
+ void end();
+
+ /**
+ * Function that should be called whenever data is available for the
+ * command.
+ *
+ * @param data is the data that should be passed to the handler.
+ * @param field is the field number (the interpretation of this value
+ * depends on the format that is being parsed).
+ */
+ void data(const std::string &data, int field = 0);
+
+ /**
+ * Returns a reference to the parser context the parser stack is currently
+ * working on.
+ *
+ * @return a reference to the parser context.
+ */
+ ParserContext &getContext() { return ctx; }
+};
+}
+
+#endif /* _OUSIA_PARSER_STACK_HPP_ */
+