The framework is highly modular and is organized in layers
Spirit is currently organized in basically two layers, the core and all the modules above the core: Debug, Attribute, Symbols, Tree, Utility, Dynamic and Error Handling. In the future, new layers may be built on top of existing layers. The framework's architecture is completely orthogonal. The relationship between the layers is totally acyclic. The core does not depend nor know the existence of the other layers. Modules in a layer do not depend on other modules in the same layer.
The client may use only the modules that she wants without incurring any compile time nor run time penalty. A minimalistic approach is to use only the core as is. The highly streamlined core is usable by itself. The core is highly suitable for tasks such as micro parsing.
Attribute module introduces advanced semantic action machinery with emphasis on extraction and passing of data up and down the parser hierarchy through inherited and synthesized attributes. Attributes may also be used to actually control the parsing. Parametric parsers are a form of dynamic parsers that change its behavior at run time based on some attribute or data.
The Debug module provides library wide parser debugging functionalities. This module essentially hooks itself up transparently into the core unintrusively and only when necessary.
The Dynamic module focuses on parsers with behavior that can be modified at run-time.
Error Handling. The framework would not be complete without Error Handling. C++'s exception handling mechanism is a perfect match for Spirit due to its highly recursive functional nature. C++ Exceptions are used extensively by this module for handling errors.
The Iterator module is independent of Spirit and may be used in other contexts as well. This module is a compilation of stand-alone iterators and iterator wrappers compatible with Spirit. Over the course of time, these iterators were found to be most useful for parsing with Spirit.
Symbols module focuses on symbol table management. This module is rather basic as of now. The goal is to build a sub-framework that will be able to accommodate C++ style multiple scope mechanisms. C++ is a great model for the complexity of scoping that perhaps has no parallel in any other language. There are classes and inheritance, private, protected and public access restrictions, friends, namespaces, using declarations, using directives, Koenig lookup and more. The symbol table functionality we have now will be the basis of a complete facility that will attempt to model this.
I wish that I could ever see, a structure as lovely as a tree...
Parse Tree and Abstract Syntax Tree (AST) generation are handled by the Tree module. There are advantages with Parse Trees and Abstract Syntax Trees over semantic actions. You can make multiple passes over the data without having to re-parse the input. You can perform transformations on the tree. You can evaluate things in any order you want, whereas with attribute schemes you have to process in a begin to end fashion. You do not have to worry about backtracking and action side effects that may occur with an ambiguous grammar.
The Utility module is a set of commonly useful parsers that were found to be quite useful. This library of parsers significantly reduce the development time. There are parsers that handle common tasks such as list processing, comments, confix expressions, etc.
Spirit is designed to be header only. Generally, there are no libraries to build and link against. Certain features, however, require additional libraries; in particular the regular expression parser requires Boost.Regex and multithreading support requires Boost.Threads.
Using Spirit is as easy as including the main header file:
Doing so will include all the header files. This might not be desirable. A low cholesterol alternative is to include only the module that you need. Each of the modules has its own header file. The master spirit header file actually includes all the module files:
#include <boost/spirit/attribute.hpp> #include <boost/spirit/debug.hpp> #include <boost/spirit/dynamic.hpp> #include <boost/spirit/error_handling.hpp> #include <boost/spirit/iterator.hpp> #include <boost/spirit/symbols.hpp> #include <boost/spirit/tree.hpp> #include <boost/spirit/utility.hpp>
To avoid unnecessary inclusion of features that you do not need, it is better to include only the modules that you need. For even finer control of header file inclusion, you can include only the specific files that you need. Each module is in its own sub-directory. For example, if you need only the closures in addition to the core:
#include <boost/spirit/core.hpp> #include <boost/spirit/attribute/closure.hpp>
Copyright © 1998-2003 Joel de Guzman
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)