diff options
Diffstat (limited to 'src/core/parser/generic')
-rw-r--r-- | src/core/parser/generic/ParserState.cpp | 161 | ||||
-rw-r--r-- | src/core/parser/generic/ParserState.hpp | 284 | ||||
-rw-r--r-- | src/core/parser/generic/ParserStateStack.cpp | 216 | ||||
-rw-r--r-- | src/core/parser/generic/ParserStateStack.hpp | 361 |
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 ©(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 ¤tState(); + + /** + * 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_ */ + |