Click here to Skip to main content
15,896,063 members
Articles / Programming Languages / C++

Wave: a Standard conformant C++ preprocessor library

Rate me:
Please Sign up or sign in to vote.
4.96/5 (58 votes)
10 Jan 200413 min read 402.6K   4.4K   81  
Describes a free and fully Standard conformant C++ preprocessor library
/*=============================================================================
    Wave: A Standard compliant C++ preprocessor

    Copyright (c) 2001-2004 Hartmut Kaiser
    http://spirit.sourceforge.net/

    Use, modification and distribution is subject to 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)

    See Copyright.txt for full acknowledgements.
=============================================================================*/

#if !defined(CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED)
#define CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED

#include <exception>
#include <string>

#include <boost/assert.hpp>
#include <boost/config.hpp>

#include "wave/cpplexer/macro_scoping_tokens.hpp"

///////////////////////////////////////////////////////////////////////////////
// helper macro for throwing exceptions
#ifdef BOOST_NO_STRINGSTREAM
#include <strstream>
#define CPP_THROW(cls, code, msg, act_pos) \
    { \
    using namespace wave; \
    std::strstream stream; \
        stream << cls::severity_text(cls::code) << ": " \
        << cls::error_text(cls::code); \
    if ((msg)[0] != 0) stream << ": " << (msg); \
    stream << std::ends; \
    std::string throwmsg = stream.str(); stream.freeze(false); \
    throw cls(throwmsg.c_str(), cls::code, (act_pos).get_line(), \
        (act_pos).get_column(), (act_pos).get_file().c_str()); \
    } \
    /**/
#else
#include <sstream>
#define CPP_THROW(cls, code, msg, act_pos) \
    { \
    using namespace wave; \
    std::stringstream stream; \
        stream << cls::severity_text(cls::code) << ": " \
        << cls::error_text(cls::code); \
    if ((msg)[0] != 0) stream << ": " << (msg); \
    stream << std::ends; \
    throw cls(stream.str().c_str(), cls::code, (act_pos).get_line(), \
        (act_pos).get_column(), (act_pos).get_file().c_str()); \
    } \
    /**/
#endif // BOOST_NO_STRINGSTREAM

///////////////////////////////////////////////////////////////////////////////
namespace wave {

///////////////////////////////////////////////////////////////////////////////
// exception severity
namespace util {

    enum severity {
        severity_remark = 0,
        severity_warning,
        severity_error,
        severity_fatal,
        severity_commandline_error
    };
    
    inline char const *
    get_severity(severity level) 
    {
        static char const *severity_text[] = 
        {
            "remark",           // severity_remark
            "warning",          // severity_warning
            "error",            // severity_error
            "fatal error",      // severity_fatal
            "command line error"    // severity_commandline_error
        };
        BOOST_ASSERT(severity_remark <= level && 
            level <= severity_commandline_error);
        return severity_text[level];
    }
}

///////////////////////////////////////////////////////////////////////////////
//  cpp_exception, the base class for all specific C preprocessor exceptions 
class cpp_exception
:   public std::exception
{
public:
    cpp_exception(int line_, int column_, char const *filename_) throw() 
    :   line(line_), column(column_) 
    {
        unsigned int off = 0;
        while (off < sizeof(filename) && *filename_)
            filename[off++] = *filename_++;
        filename[off] = 0;
    }
    ~cpp_exception() throw() {}
    
    virtual char const *what() const throw() = 0;   // to be overloaded
    virtual char const *description() const throw() = 0;
    
    int line_no() const throw() { return line; }
    int column_no() const throw() { return column; }
    char const *file_name() const throw() { return filename; }
    
protected:
    char filename[512];
    int line;
    int column;
};

///////////////////////////////////////////////////////////////////////////////
// preprocessor error
class preprocess_exception :
    public cpp_exception
{
public:
    enum error_code {
        unexpected_error = 0,
        macro_redefinition,
        macro_insertion_error,
        bad_include_file,
        bad_include_statement,
        ill_formed_directive,
        error_directive,
        warning_directive,
        ill_formed_expression,
        missing_matching_if,
        missing_matching_endif,
        ill_formed_operator,
        bad_define_statement,
        too_few_macroarguments,
        too_many_macroarguments,
        improperly_terminated_macro,
        bad_line_statement,
        bad_undefine_statement,
        bad_macro_definition,
        illegal_redefinition,
        duplicate_parameter_name,
        invalid_concat,
        last_line_not_terminated,
        ill_formed_pragma_option,
        include_nesting_too_deep,
        misplaced_operator,
        unexpected_endregion,
        illegal_global_region,
        alreadydefined_name,
        undefined_macroname,
        invalid_macroname,
        unexpected_qualified_name
    };

    preprocess_exception(char const *what_, error_code code, int line_, 
        int column_, char const *filename_) throw() 
    :   cpp_exception(line_, column_, filename_), level(severity_level(code))
    {
        unsigned int off = 0;
        while (off < sizeof(buffer) && *what_)
            buffer[off++] = *what_++;
        buffer[off] = 0;
    }
    ~preprocess_exception() throw() {}
    
    virtual char const *what() const throw()
    {
        return "wave::preprocess_exception";
    }
    virtual char const *description() const throw()
    {
        return buffer;
    }
    util::severity get_severity()
    {
        return level;
    }

    static char const *error_text(int code)
    {
    // error texts in this array must appear in the same order as the items in
    // the error enum above
        static char const *preprocess_exception_errors[] = {
            "unexpected error (should not happen)",     // unexpected_error
            "illegal macro redefinition",               // macro_redefinition
            "macro definition failed (out of memory?)", // macro_insertion_error
            "could not find include file",              // bad_include_file
            "ill formed #include directive",            // bad_include_statement
            "ill formed preprocessor directive",        // ill_formed_directive
            "encountered #error directive or #pragma wave stop()", // error_directive
            "encountered #warning directive",           // warning_directive
            "ill formed preprocessor expression",       // ill_formed_expression
            "the #if for this directive is missing",    // missing_matching_if
            "detected at least one missing #endif directive",   // missing_matching_endif
            "ill formed preprocessing operator",        // ill_formed_operator
            "ill formed #define directive",             // bad_define_statement
            "too few macro arguments",                  // too_few_macroarguments
            "too many macro arguments",                 // too_many_macroarguments
            "improperly terminated macro invocation "
            "or replacement-list terminates in partial "
            "macro expansion (not supported yet)",      // improperly_terminated_macro
            "ill formed #line directive",               // bad_line_statement
            "#undef may not be used on this predefined name",   // bad_undefine_statement
            "invalid macro definition",                 // bad_macro_definition
            "this predefined name may not be redefined",    // illegal_redefinition
            "duplicate macro parameter name",           // duplicate_parameter_name
            "pasting the following two tokens does not "
            "give a valid preprocessing token",         // invalid_concat
            "last line of file ends without a newline", // last_line_not_terminated
            "unknown or illformed pragma option",       // ill_formed_pragma_option
            "include files nested too deep",            // include_nesting_too_deep
            "misplaced operator defined()",             // misplaced_operator
            "unexpected " WAVE_PP_ENDREGION " at global scope", // unexpected_endregion
            "a global " WAVE_PP_REGION " may not be opened "
            "inside a nameless " WAVE_PP_REGION,        // illegal_global_region
            "the name is already used in this scope as "
            "a macro or scope name",                    // alreadydefined_name
            "undefined macro or scope name may not be imported", // undefined_macroname
            "ill formed macro name or " WAVE_PP_REGION " name",  // invalid_macroname
            "qualified names are supported in C++0x mode only"   // unexpected_qualified_name
        };
        BOOST_ASSERT(unexpected_error <= code && 
            code <= unexpected_qualified_name);
        return preprocess_exception_errors[code];
    }

    static util::severity severity_level(int code)
    {
        static util::severity preprocess_exception_severity[] = {
            util::severity_fatal,              // unexpected_error
            util::severity_warning,            // macro_redefinition
            util::severity_fatal,              // macro_insertion_error
            util::severity_error,              // bad_include_file
            util::severity_error,              // bad_include_statement
            util::severity_error,              // ill_formed_directive
            util::severity_fatal,              // error_directive
            util::severity_warning,            // warning_directive
            util::severity_error,              // ill_formed_expression
            util::severity_error,              // missing_matching_if
            util::severity_error,              // missing_matching_endif
            util::severity_error,              // ill_formed_operator
            util::severity_error,              // bad_define_statement
            util::severity_warning,            // too_few_macroarguments
            util::severity_warning,            // too_many_macroarguments
            util::severity_error,              // improperly_terminated_macro
            util::severity_warning,            // bad_line_statement
            util::severity_warning,            // bad_undefine_statement
            util::severity_commandline_error,  // bad_macro_definition
            util::severity_warning,            // illegal_redefinition
            util::severity_error,              // duplicate_parameter_name
            util::severity_error,              // invalid_concat
            util::severity_warning,            // last_line_not_terminated
            util::severity_warning,            // ill_formed_pragma_option
            util::severity_fatal,              // include_nesting_too_deep
            util::severity_error,              // misplaced_operator
            util::severity_error,              // unexpected_endregion
            util::severity_error,              // illegal_global_region
            util::severity_error,              // alreadydefined_name
            util::severity_error,              // undefined_macroname
            util::severity_error,              // invalid_macroname
            util::severity_error               // unexpected_qualified_name
        };
        BOOST_ASSERT(unexpected_error <= code && 
            code <= unexpected_qualified_name);
        return preprocess_exception_severity[code];
    }
    static char const *severity_text(int code)
    {
        return util::get_severity(severity_level(code));
    }

private:
    char buffer[512];
    util::severity level;
};

///////////////////////////////////////////////////////////////////////////////
}   // namespace wave

#endif // !defined(CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
Actively involved in Boost and the development of the Spirit parser construction framework.

Comments and Discussions