Click here to Skip to main content
Click here to Skip to main content

Wave: a Standard conformant C++ preprocessor library

By , 10 Jan 2004
 

Sample Image - wave_preprocessor.jpg

Introduction

Ever wanted to have your own C/C++ preprocessor? Or maybe you are curious about how this invisible everyday helper of your toolbox works? If yes, you may want to read further. If no - before hitting the 'back' button of your browser consider to learn something new and read further too :-).

The C++ preprocessor is a macro processor that under normal circumstances is used automatically by your C++ compiler to transform your program before the actual compilation. It is called a macro processor because it allows you to define macros, which are brief abbreviations for longer constructs. The C++ preprocessor provides four separate facilities that you can use as you see fit:

  • Inclusion of header files
  • Macro expansion
  • Conditional compilation
  • Line control

These features are greatly underestimated today, even more, the preprocessor has been frowned on for so long that its usage just hasn't been effectively pushed until the Boost preprocessor library [1] came into being a few years ago. Only today we begin to understand, that preprocessor generative metaprogramming combined with template metaprogramming in C++ is by far one of the most powerful compile-time reflection/metaprogramming facilities that any language has ever supported.

The C++ Standard [2] was adopted back in 1998, but there is still no (known to me) C++ compiler, which has a bug free implementation of the rather simple preprocessor requirements mandated therein. This may be a result of the mentioned underestimation or even banning of the preprocessor from good programming style during the last few years or may stem from the somewhat awkward standardized dialect of English used to describe it.

So the Wave preprocessor library is an attempt to:

  • Provide a free, fully Standard conformant and (hopefully) bugfree implementation of the mandated preprocessor functionality
  • Make maximal usage of the C++ STL and/or Boost [3] libraries (for compactness and maintainability)
  • Achieve straightforward extendibility for the implementation of additional features
  • Build a flexible library for different C++ lexing and preprocessing needs.

To simplify the parsing task of the input stream (which is most of the time, but not restricted to, a file) the Spirit parser construction library [4] is used.

Background

The Wave C++ preprocessor is not a monolithic application, it's rather a modular library, which exposes mainly a context object and an iterator interface. The context object helps to configure the actual preprocessing process (as search path's, predefined macros, etc.). The exposed iterators are generated by this context object too. Iterating over the sequence defined by these two iterators will return the preprocessed tokens, which are to be built on the fly from the given input stream.

The C++ preprocessor iterator itself is feeded by a C++ lexer iterator, which implements an unified interface. By the way, the C++ lexers contained within the Wave library may be used standalone too and are not tied to the C++ preprocessor iterator at all. As a lexer I'll understand a piece of code, which combines several consecutive characters in the input stream into a stream of objects (called tokens) more suitable for subsequent parsing. These tokens carry around not only the information about the matched character sequence, but additionally the position in the input stream, where a particular token was found. In other words the lexer removes all this so-needed-by-human garbage like spaces, newlines, etc. (i.e. performs some lexical transformation) leaving the structural transformation for parser.

To make the Wave C++ preprocessing library modular, the C++ lexer is held completely separate and independent from the preprocessor. To proof this concept, there are two different C++ lexers implemented and contained within the library by now, which are functionally completely identical. The C++ lexers expose the mentioned unified interface, so that the C++ preprocessor iterator may be used with both of them. The abstraction of the C++ lexer from the C++ preprocessor iterator library was done to allow to plug in different other C++ lexers too, without the need to re-implement the preprocessor. This will allow for benchmarking and specific finetuning of the process of preprocessing itself.

During the last weeks Wave got another field of application: testing the usability and applicability of different Standards proposals. A new C++0x mode was implemented, which allows to try out and help to establish some ideas, which are designed to overcome some of the known limitations of the C++ preprocessor.

Using the code

The actual preprocessing is a highly configurable process, so obviously you have to define a couple of parameters to control this process, such as:

  • Include search paths, which define, where to search for files to be included with #include <...> and #include "..." directives
  • Which macros to predefine and which of the predefined macros to undefine
  • Several other options as for instance to control, whether to enable some extensions to the C++ Standard (for instance variadics and placemarkers) or not.

You can access all these processing parameters through the wave::context object. So you have to instantiate at least one object of this type to use the Wave library. For more information about the context template please refer to the class reference as included in the downloadable file or as may be found here. The context object is a template class, for which you have to supply at least two template parameters: the iterator type of the underlying input stream to use and the type of the token to be returned from the preprocessing engine. The type of the used input stream is defined by you, so may the token type, but as a starting point I would recommend to use the token type predefined as the default inside the Wave library - the wave::cpplexer::lex_token<> template class. A full reference of this class you can find inside the downloadable file or here.

The main preprocessing iterators are not to be instantiated directly, but should be generated through this context object too. The following code snippet preprocesses a given input file and outputs the generated text into std::cout.

    // Open the file and read it into a string variable
    std::ifstream instream("input.cpp");
    std::string input(
        std::istreambuf_iterator<char>(instream.rdbuf());
        std::istreambuf_iterator<char>());

    // The template wave::cpplexer::lex_token<> is the default 
    // token type to be used by the Wave library.
    // This token type is one of the central types throughout 
    // the library, because it is a template parameter to many 
    // of the public classes and templates and it is returned 
    // from the iterators itself.
    typedef wave::context<std::string::iterator, 
                wave::cpplexer::lex_token<> >
            context_t;

    // The C++ preprocessor iterators shouldn't be constructed 
    // directly. These are to be generated through a 
    // wave::context<> object. Additionally this wave::context<> 
    // object is to be used to initialize and define different 
    // parameters of the actual preprocessing.
    context_t ctx(input.begin(), input.end(), "input.cpp");
    context_t::iterator_t first = ctx.begin();
    context_t::iterator_t last = ctx.end();

    // The preprocessing of the input stream is done on the fly 
    // behind the scenes during the iteration over the 
    // context_t::iterator_t based stream. 
       while (first != last) {
           std::cout << (*first).get_value();
           ++first;
       }

This sample shows, how the input may be read into a string variable, from where it is fed into the preprocessor. But the parameters to the constructor of the wave::context<> object are not restricted to this type of input stream. It can take a pair of arbitrary iterator types (conceptually at least forward_iterator type iterators) to the input stream, from where the data to be preprocessed should be read. The third parameter supplies a filename, which is subsequently accessible from inside the preprocessed tokens returned from the preprocessing to indicate the token position inside the underlying input stream. Note though, that this filename is used only as long no #include or #line directives are encountered, which in turn will alter the current filename.

The iteration over the preprocessed tokens is relatively straight forward. Just get the starting and the ending iterators from the context object (maybe after initializing some include search paths) and you are done! The dereferencing of the iterator will return the preprocessed tokens, which are generated on the fly from the input stream.

As you may have seen, the complete library resides in a C++ namespace wave. So you have to explicitly specify this while using the different classes. The other way around is certainly to place a using namespace wave; somewhere at the beginning of your source files.

The Wave tracing facility

If you ever had the need to debug a macro expansion you had to discover, that your tools provide only little or no support for this task. For this reason the Wave library got a tracing facility, which allows to get selectively some information about the expansion of a certain macro or several macros.

The tracing of macro expansions generates a possibly huge amount of information, so it is recommended, that you explicitly enable/disable the tracing for the macro in question only. This may be done with the help of a special #pragma:

#pragma wave trace(enable)    // enable the tracing
// the macro expansions here will be traced
// ...
#pragma wave trace(disable)   // disable the tracing

To see, what the Wave driver generates while expanding a simple macro, I suggest, that you try to compile the following with 'wave -t test.trace test.cpp':

// test.cpp
#define X(x)          x
#define Y()           2
#define CONCAT_(x, y) x ## y
#define CONCAT(x, y)  CONCAT_(x, y)
#pragma wave trace(enable)
// this macro expansion is to be traced
CONCAT(X(1), Y())     // should expand to 12
#pragma wave trace(disable)

After executing this command the file test.trace will contain the generated trace output. The generated output is relatively straightforward to understand, but you can find a thorough description of the trace output format in the documentation included with the downloadable file.

The experimental C++0x mode

In order to prepare and support a proposal for the C++ Standards committee, which will describe certain new and enhanced preprocessor facilities, the Wave preprocessor library has implemented experimental support for the following features:

  • Variadic macros and placemarker tokens in C++
  • Well defined token-pasting
  • A macro scoping mechanism
  • New alternative preprocessor tokens

Variadic macros and placemarker tokens are known already from the C99 Standard. Its addition to the C++ Standard would help to make C99 and C++ less different.

Token-pasting of unrelated tokens (i.e. token-pasting resulting in multiple preprocessing tokens) is currently undefined behaviour for no substantial reason. It is not dependent on architecture nor is it difficult for an implementation to diagnose. Furthermore, retokenization is what most, if not all, preprocessors already do and what most programmers already expect the preprocessor to do. Well-defined behavior is simply standardizing existing practice and removing an arbitrary and unnecessary undefined behavior from the Standard.

One of the major problems of the preprocessor is that macro definitions do not respect any of the scoping mechanisms of the core language. As history has shown, this is a major inconvenience and drastically increases the likelihood of name clashes within a translation unit. The solution is to add both a named and unnamed scoping mechanism to the C++ preprocessor. This limits the scope of macro definitions without limiting its accessibility.

The proposed scoping mechanism is implemented with the help of three new preprocessor directives: #region, #endregion and #import (note that the actual names for the directives may change during the standardization process). Additionally it changes minor details of some of the existing preprocessor directives: #ifdef, #ifndef and the operator defined().

To avoid overly detailed descriptions of the new features in this article, a simple example is provided here (taken from the experimental version of the preprocessor library written by Paul Mensonides), which demonstrates the proposed extensions:

    # ifndef ::CHAOS_PREPROCESSOR::chaos::WSTRINGIZE_HPP
    # region ::CHAOS_PREPROCESSOR::chaos
    #
    # define WSTRINGIZE_HPP
    #
    # include <chaos/experimental/cat.hpp>
    #
    # // wstringize
    #
    # define wstringize(...) \
        chaos::primitive_wstringize(__VA_ARGS__) \
        /**/
    #
    # // primitive_wstringize
    #
    # define primitive_wstringize(...) \
        chaos::primitive_cat(L, #__VA_ARGS__) \
        /**/
    #
    # endregion
    # endif

    # import ::CHAOS_PREPROCESSOR
 
    chaos::wstringize(a,b,c) // expands to: L"a,b,c"

The macro scope syntax is resembled after the namespace scoping already known from the core C++ language. There is a significant difference though. The #region and #endregion directives are opaque for any macro definition from outside or inside the spanned region, respective. This way macros defined inside a specific region are visible from outside this region only, if these are imported (by the #import directive) or if these are qualified (as for instance the argument to the #ifndef directive above).

For more details about the new experimental features please refer to the documentation included with the downloadable file.

The described features are enabled by the --c++0x command line option of the Wave driver. Alternatively you can enable these features by calling the wave::context<>::set_language() function with the wave::support_cpp0x value.

The command line preprocessor driver

To see, how you may write a full blown preprocessor, you may refer to the Wave driver sample, included in the downloadable file. This Wave driver program fully utilizes the capabilities of the library. It is usable as a preprocessor executable on top of any other C++ compiler. It outputs the textual representation of the preprocessed tokens generated from a given input file. This driver program has the following command line syntax:

Usage: wave [options] [@config-file(s)] file:
 
  Options allowed on the command line only:
    -h [--help]:            print out program usage (this message)
    -v [--version]:         print the version number
    -c [--copyright]:       print out the copyright statement
    --config-file filepath: specify a config file (alternatively: @filepath)
 
  Options allowed additionally in a config file:
    -o [--output] path:          specify a file to use for output instead of 
                                 stdout
    -I [--include] path:         specify an additional include directory
    -S [--sysinclude] syspath:   specify an additional system include directory
    -F [--forceinclude] file:    force inclusion of the given file
    -D [--define] macro[=[value]]:    specify a macro to define
    -P [--predefine] macro[=[value]]: specify a macro to predefine
    -U [--undefine] macro:       specify a macro to undefine
    -n [--nesting] depth:        specify a new maximal include nesting depth
    
  Extended options (allowed everywhere)
    -t [--traceto] path:    output trace info to a file [path] or to stderr [-]
    --timer:                output overall elapsed computing time to stderr 
    --variadics:            enable variadics and placemarkers in C++ mode
    --c99:                  enable C99 mode (implies variadics)
    --c++0x:                enable experimental C++0x support (implies 
                            variadics)
 

To allow the tracing output, the Wave driver now has a special command line option -t (--trace), which should be used to specify a file, to which the generated trace information will be put. If you use a single dash ('-') as the file name, the output goes to the std::cerr stream.

There is left one caveat to mention. To use the Wave library or to compile the Wave driver yourself you will need at least the VC7.1 compiler (the C++ compiler included in the VS.NET 2003 release). Alternatively you may compile it with a recent version of the gcc compiler (GNU Compiler Collection) or the Intel V7.0 C++ complier. Sorry, for now no VC6 and no VC7 - these are to far away from C++ Standard conformance. But I will eventually try to alter parts of the Wave library to make it compilable with this compilers too - it depends on your response.

Wave depends on the Boost library (at least V1.30.2) and the Program Options library from Vladimir Prus (at least rev. 160, recently adopted to Boost, but not included yet) , so please be sure to install these libraries, before trying to recompile Wave.

Conclusion

Despite the fact, that the Wave library is quite complex and heaviliy uses advanced C++ idioms, as templates and template based metaprogramming, it is farely simple to be used in a broad spectrum of applications. It nicely fits into well known paradigms used over years by the C++ Standard Template Library (STL).

The Wave driver program is the only known to me C++ preprocessor, which

  • allows to enable variadics and placemarkers for C++ programs
  • exposes facilities to support the debugging of the macro expansion process
  • implements experimental C++0x support as macro scoping,which will be proposed as a C++ Standards addition

therefore it may be an invaluable tool for the development of modern C++ programs.

As recent developments like the Boost Preprocessor Library show [1], we will see in the future a lot of applications for advanced preprocessor techniques. But these need a solid base - a Standard conformant preprocessor. As long as the widely available compilers do not fit into these needs, the Wave library may fill this gap.

References

  1. The Boost Library Preprocessor Subset for C/C++
  2. Programming languages - C++ (INCITS/ISO/IEC 14882:1998)
  3. The Boost Libraries Documentation
  4. The Spirit parser construction framework
  5. The Wave C++ preprocessor library

History

03/25/2003 (Wave V0.9.1)

  • Initial Version of this article

03/26/2003

  • Fixed a broken link in the references section

04/07/2003 (Wave V0.9.2)

  • Fixed several typos in the article text
  • Added the tracing facility to trace the macro expansion process
  • Added the predefined macro __INCLUDE_LEVEL__
  • Added support for the operator _Pragma() (C99 and --variadics mode only)
  • Added new command line options to the Wave driver program
  • Fixed a couple of bugs (see the ChangeLog file inside the downloadable file)
  • Updated the documentation (inside the downloadable file)

05/16/2003 (Wave V0.9.3)

  • Added the _Pragma wave system()
  • Added the possibility to pre-include files
  • Added the experimental C++0x mode with
    • macro scoping support
    • well defined token-pasting
    • variadics and placemarkers
    • __comma__, __lparen__ and __rparen__ alternative pp-tokens
  • Fixed a lot of bugs (see the ChangeLog file inside the downloadable file)

05/22/2003

  • Corrected several typos

06/04/2003

  • Fixed a couple of macro expansion bugs
  • Updated the attached source and demo files (see the ChangeLog file inside the downloadable file)

01/05/2004 (Wave V1.0)

  • Added support for #pragma once directive
  • Added support for #pragma wave timer() and the --timer command line switch (see the documentation inside the downloadable file)
  • Included a finite state machine, which suppresses not needed whitespace. This makes the generated output much more dense.
  • Added an optional IDL mode, which besides not recognizing C++ specific tokens doesn't recognize any keywords (except true and false), but only identifiers.
  • Incorporated a couple of changes, which improved the overall performance
  • Fixed a lot of bugs (see the ChangeLog file inside the downloadable archive)
  • Switched licensing to use the Boost Software License, Version 1.0.

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

About the Author

Hartmut Kaiser
United States United States
Member
Actively involved in Boost and the development of the Spirit parser construction framework.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: Changing to relative paths in #line output?memberHartmut Kaiser18 Apr '10 - 6:46 
Just for the records, here is my latest reply on the Boost users list outlining what has been changed in the version of Wave to be released with Boost V1.43:
 
Here is a list of things I implemented:
 
- Added new preprocessing hook: emit_line_directive, allowing to customize the
format of the generated #line directive.
- Changed --line/-l command line option of the wave driver application to
accept 0, 1, and 2 as options. The option values 0 and 1 behave as before
(disable/enable the generation of #line directives), while the option value 2
will generate the #line directive using the relative filename (instead of the
absolute filename emitted from option 1). The default option is value 1.
- Added new example: emit_custom_line_directives, demonstrating the use of the
new preprocessing hook.
 
Regards Hartmut
 
---------------
Meet me at BoostCon
www.boostcon.com
GeneralControlling output formatmemberRowan S-B27 Feb '10 - 9:18 
I'm looking for a macroprocessor that can generate highly repetitive sections of assembler code for the 8051 microprocessor. It's obviously not C or C++, but I've got the beginnings of a system working with the MCPP self-contained C preprocessor. However this doens't support recursion or repeat/for loops, which I need for these repetitive code sections. I wonder whether Wave with the Boost pre-processor library might do this. I've downloaded it and installed it, and tested it against my code. However, I wonder whether it's possible to improve the output:
1. I don't need/want #line directives - they confuse my assembler, and I don't want to have to run another pass with some other sort of processor to remove them. MCPP has an option to turn these off.
2. I would like to preserve white space, since the code is pretty illegible without it, and this code may have to be maintained manually. MCPP has an option for this.
3. Wave inserts a space inside tokens like 20d or 5ah (meaning decimal or hex constants), converting these to 20 d and 5 ah. Can I prevent this happening? MCPP doesn't do this...
 
Many thanks - Rowan
GeneralRe: Controlling output formatmemberHartmut Kaiser27 Feb '10 - 10:56 
Rowan,
 
First of all, you should use the latest version of Wave (distributed as part of the Boost libraries, www.boost.org[^]) as it has evolved quite a bit since I published this article.
Rowan S-B wrote:
1. I don't need/want #line directives - they confuse my assembler, and I don't want to have to run another pass with some other sort of processor to remove them. MCPP has an option to turn these off.

Use the --line=0 command line option of the wave tool.
Rowan S-B wrote:
2. I would like to preserve white space, since the code is pretty illegible without it, and this code may have to be maintained manually. MCPP has an option for this.

Use the command line option --preserve=2 (all whitespace is preserved).
Rowan S-B wrote:
3. Wave inserts a space inside tokens like 20d or 5ah (meaning decimal or hex constants), converting these to 20 d and 5 ah. Can I prevent this happening? MCPP doesn't do this...

To disable this you may want to utilize the command line option --disambiguate=0.
 
Generally, just invoke wave with --help to get a full list of available options or read the docs here[^].
 
HTH
Regards Hartmut
GeneralUsing wave librarymemberPrasanta Chakravarty19 Jun '07 - 1:16 
Hi,
 
I have downloaded Boost1.34.0 versions in my machine. I have a requirement of passing variable no. of arguments in macro. So, I have build Boost wave library and got .dll and .lib file.
But I am not able to use it. Please help me out how to use that one.
Please let me know with an example.
 
Thanks & Regards'
Prasanta

QuestionHow to use wavememberVincent_RICHOMME29 Nov '06 - 22:06 
Hi,
 
I am trying to use the sample device wave.exe.
First I have created a config file (wave.cfg) with my system include but it seems wave doesn't know how to interpret windows PATH. I try to put double quotes but it doesn't work either.
So now I am giving all the paramteres on the command line but nothing happens to my test file. This file is just a header file (test.h) that contains a few declarations like :
 
#include
 
#define TEST 10
#define FOO TEST
 
DWORD foo(char szTest[FOO])
 

and when I execute wave.exe I got nothing. What I would like is something like
 
unsigned long(char szTest[10]);
 
Maybe wave is not what I think????
 

 


AnswerRe: How to use wavememberHartmut Kaiser13 Dec '06 - 2:51 
Hi,
 
sorry for the late reply, I didn't get a notification mail from codeproject that there is a new comment ...
 
Vincent_RICHOMME wrote:
First I have created a config file (wave.cfg) with my system include but it seems wave doesn't know how to interpret windows PATH.

 
Wave should be able to interpret Windows paths correctly. Could you send me your cfg file?
 
Vincent_RICHOMME wrote:
and when I execute wave.exe I got nothing.

 
The copy of wave I have here on my harddrive gives me:
 
C:/CVS/wave/tools/wave/build/wave/Debug/t26.cpp:1:1: error: ill formed #include directive
#line 6 "C:\\CVS\\wave\\tools\\wave\\build\\wave\\Debug\\t.cpp"
DWORD foo(char szTest[10])
 
which is what I expected.
 
But I must admit, I'm using a much more mature version here (V1.3). Since wave is now part of the Boost libraries (www.boost.org[^]), you will find the current version there.
 
HTH
Regards Hartmut

GeneralUsing relative paths in #includemembertalewisx15 Feb '06 - 5:44 
I found that include statements which include relative paths (such as "..\..\INCLUDE\PlatformBinding.h" generates an error such as:
 
(1): exception caught: boost::filesystem::path: invalid name "..\..\INCLUDE\PlatformBinding.h" in path: "..\..\INCLUDE\PlatformBinding.h"
 
This seems to be a problem with Boost's path parsing code. However, this passes other preprocessors that I have. Any thoughts?
 
Thanks, Tim
AnswerRe: Using relative paths in #includememberHartmut Kaiser15 Feb '06 - 5:55 
talewisx wrote:
I found that include statements which include relative paths (such as "..\..\INCLUDE\PlatformBinding.h" generates an error such as:
 
(1): exception caught: boost::filesystem::path: invalid name "..\..\INCLUDE\PlatformBinding.h" in path: "..\..\INCLUDE\PlatformBinding.h"
 
This seems to be a problem with Boost's path parsing code. However, this passes other preprocessors that I have. Any thoughts?

 
Which version of Wave do you use? The one attached to this article?
 
If yes, could you please consider downloading the most recent version of Wave (which is now part of the Boost libraries - see www.boost.org[^]). I've tried your sample code with Wave V1.2.2 (which is part of Boost 1.33.1) and I was not able to reproduce your problem there.
 
Regards Hartmut
 

 
-- modified at 14:07 Wednesday 15th February, 2006
General[Message Deleted]membernfwu25 May '05 - 2:03 

GeneralRe: Preprocessor For CompiliermemberHartmut Kaiser25 May '05 - 3:59 
nfwu wrote:
Is wave compatible with other languages?
 
The answer is twofold:
 
1. Wave as it is today is designed to be used with a C-like language only.
 
2. Since Wave consists out of several more or less independant components it seems to be doable to replace the lexing component to match another base language. In this case the preprocessing component may be reused for a completely different language. If you're interested in doing so please get in direct contact with me to discuss the needed steps.
 
HTH
Regards Hartmut

GeneralGenerated Line DirectivesmemberRoss MacGregor20 May '04 - 23:30 
Can the line directives output by wave be suppressed? I am considering using wave to process files that are not C source code.

GeneralRe: Generated Line DirectivesmemberHartmut Kaiser20 May '04 - 23:43 
Ross MacGregor wrote:
Can the line directives output by wave be suppressed? I am considering using wave to process files that are not C source code.
 
No, not yet. But implementing it shouldn't be difficult (well, removing something seems to be easier, than adding it Poke tongue | ;-P ).
 
I'm currently refactoring the C++0x stuff to overcome some problems we noticed since then, and I'll try to add your suggestion along the lines, ok? Should I keep you in the loop?
 
Regards Hartmut

GeneralRe: Generated Line DirectivesmemberRoss MacGregor21 May '04 - 11:15 
Perhaps I should just build support for the line directives in my application.
 
I think I found a bug with the line directives. They don't appear unless there are blank lines in the input file. I am testing with the wave.exe version 1.0.0.753 (20040105).
 
Thanks for considering the option. I can watch the web page for updates.

GeneralRe: Generated Line DirectivesmemberHartmut Kaiser23 May '04 - 3:46 
Ross MacGregor wrote:
I think I found a bug with the line directives. They don't appear unless there are blank lines in the input file. I am testing with the wave.exe version 1.0.0.753 (20040105).
 
I tried to optimize (minimise) the generated output from Wave. So Wave generates a #line directive only, if the generated output gets out of sync with the input in terms of file name and/or line number.
Unless this rule is broken for your example, I'd consider it a feature, not a bug Smile | :)
 
Thanks anyway.
Regards Hartmut
GeneralBuilding wave test driver from boost / spirit CVSmemberPieter Viljoen18 May '04 - 18:29 
Hartmut Kaiser
 
Please describe the wave source distribution model:
- SourceForge lists 1.0 as the latest wave version.
- http://spirit.sourceforge.net/dl_more/ lists 1.0.6 and 1.1.5 as the latest versions.
- This forum refers to 1.0.6 as the latest version, what the difference with 1.1.5?
- Neither boost 1.31 nor boost CVS includes wave. Will they?
- spirit CVS includes wave, but not the test driver project, at least not the vcproj file.
- How do I integrate the test driver with the CVS build of boost or spirit?
- I am having difficulty integrating "program_options", the downloadable version does not appear to work with boost 1.31, boost CVS, or spirit CVS.
- boost CVS now includes "program_options", but boost CVS does not work with wave 1.0.
 
In summary:
1) Where can I get the latest released version of wave that works with the latest released version of boost.
2) Where can I get the current CVS version of wave that works with the current CVS version of boost.
3) Is there a forum or website for wave that discusses integration with the current latest / CVS boost and spirit releases.
 
Regards
 
Pieter
GeneralRe: Building wave test driver from boost / spirit CVSmemberHartmut Kaiser18 May '04 - 22:34 
Hi Peter,
 
thanks for your feedback and first of all, seems, that I should have given more attention to the formal release methodology for Wave. Sorry for any confusion.
 
There are two different versions of Wave out there: the 1.0.x is the 'stable' version, which get's only bug fixes introduced and which changes intependently from the 1.1.x version series, which is the development version, where the real development is done. For this reason there is currently a different numbering for these two. But seems, that's better, if I would bring the numbering scheme in sync...
 
Pieter Viljoen wrote:
SourceForge lists 1.0 as the latest wave version.
I'll make a sourceforge release in the near future, couldn't get my hands on this yet...
 
Pieter Viljoen wrote:
http://spirit.sourceforge.net/dl_more/ lists 1.0.6 and 1.1.5 as the latest versions.
That's correct, these are the latest available downloads.
 
Pieter Viljoen wrote:
This forum refers to 1.0.6 as the latest version, what the difference with 1.1.5?
I think, I've answered this question above. I mentioned the stable version on this forum only, because there was a incompatible interface change in between the 1.0.x and 1.1.x branches and I didn't wanted to change the current document.
 
Pieter Viljoen wrote:
Neither boost 1.31 nor boost CVS includes wave. Will they?
That's correct too. Wave is currently available in the boost-sandbox CVS (1.1.x version only). I've submitted Wave for Boost review, which hopefully will happen sometime this year. After a successful Boost review, Wave will be moved over completely to the Boost CVS.
 
Pieter Viljoen wrote:
spirit CVS includes wave, but not the test driver project, at least not the vcproj file.
The V1.0.x branch isn't on any CVS yet, it is maintained locally on my machine only. If there is interest I'll re-add it to the Spirit CVS.
 
Pieter Viljoen wrote:
How do I integrate the test driver with the CVS build of boost or spirit?
Actually I thought, that there aren't any problems. I'm able to build both Wave versions using at least Boost V1.30.2. The Wave V1.1.x is fully integrated into the Boost build process (bjam based).
Could you please elaborate, what your concrete problems are (maybe offline), I'll try to help you to get it built.
 
Pieter Viljoen wrote:
I am having difficulty integrating "program_options", the downloadable version does not appear to work with boost 1.31, boost CVS, or spirit CVS.
There were incompatible interface changes in the program_options library during the last couple of weeks. I decided to leave the Wave 1.0.x branch using the 'old' program_options library, which should be available here: http://zigzag.cs.msu.su:7813/program_options[^]
 
Pieter Viljoen wrote:
boost CVS now includes "program_options", but boost CVS does not work with wave 1.0.
Only the Wave V1.1.x was 'ported' to use the new program_options library, which currently is in the Boost CVS.
 
Pieter Viljoen wrote:
1) Where can I get the latest released version of wave that works with the latest released version of boost.
Wave 1.1.x should work with the latest Boost release (and Boost CVS HEAD branch). If not, please drop me a note.
 
Pieter Viljoen wrote:
2) Where can I get the current CVS version of wave that works with the current CVS version of boost.
Boost-Sandbox CVS
 
Pieter Viljoen wrote:
3) Is there a forum or website for wave that discusses integration with the current latest / CVS boost and spirit releases.
Nope, sorry. All Wave related problems are currently discussed on the Spirit mailing lists.
 
HTH
Regards Hartmut
 


GeneralRe: Building wave test driver from boost / spirit CVSmemberHartmut Kaiser20 May '04 - 23:03 
Hi Peter,
 
just another update: There were recently some changes in the program_options library again (sigh), which made impossible to compile the current Wave library version out of the box. I'm working to provide a solution, please give me a couple of days.
 
Regards Hartmut

GeneralRe: Building wave test driver from boost / spirit CVSmemberHartmut Kaiser25 May '04 - 23:15 
There were again some interface breaking changes in the program_options library, which broke the Wave build process. So I've posted a new Wave version (V1.1.6) here[^] which now should be compilable with the current Boost CVS head.
 
The stable version of Wave had no changes: download it from here[^]. It should be usable with all boost versions starting from 1.30.2 if you ensure, that the prereview version of the program options library is used (download it from here[^]), i.e. put this program options version first on your include and linker path.
 

Generalerror: ill formed #include directivesussAlexandre Barbosa20 Apr '04 - 11:44 
I get the following message "error: ill formed #include directive" when I use wave to preprocess the files below:
File: test.cpp
01 #include /* */ "test.h"
02
03 /*
04 */
 
File: test.h
01 #ifndef TEST_H
02 #define TEST_H
03
04 int a;
05
06 #endif
 
And, when I remove the lines 03 and 04 of test.cpp file and call wave again the preprocess work correctly. I'd like to know if anybody have had a similar situation and if there is a explanation for it.
 
Best regards,
 
Alexandre Barbosa
 


GeneralRe: error: ill formed #include directivememberHartmut Kaiser21 Apr '04 - 2:03 
Alexandre Barbosa wrote:
I get the following message "error: ill formed #include directive" when I use wave to preprocess the files below:
 
Thanks for this bug report. It should be fixed now. You can download an updated source package here Wave V1.0.6[^].
 
Regards Hartmut

GeneralWave in a commercial projectmemberPete422 Apr '04 - 12:13 
Hello, is it possible to use Wave in a commercial project? If yes, is there any licence agreement that has to be fulfilled?
GeneralRe: Wave in a commercial projectmemberHartmut Kaiser2 Apr '04 - 20:43 
Pete42 wrote:
Hello, is it possible to use Wave in a commercial project? If yes, is there any licence agreement that has to be fulfilled?
 
You can use Wave without any charge in any way you want as long it fulfills the (Boost Software License V1.0[^]). But a donation is always welcome Wink | ;-) .
 
If you need commercial support, I'd be able to provide it. Please contact me privately for details: hkaiser [at] users [dot] sourceforge [dot] net.
 
Regards Hartmut

GeneralCompile WavememberEduardooo26 Mar '04 - 2:39 
Hello!
what compiler did you use to build wave? Im trying to do this in visual C++ but it didnt work...
 
Thanks!!

GeneralRe: Compile WavememberHartmut Kaiser26 Mar '04 - 3:50 
Hi,
 
Eduardooo wrote:
what compiler did you use to build wave?
 
Wave has been shown to compile successfully with VC7.1, gcc 3.2.x and gcc3.3.x (Cygwin and Linux), Intel7.1 (Windows and Linux), Intel8.0 Windows.
 
Eduardooo wrote:
Im trying to do this in visual C++ but it didnt work...
 
What Boost/Spirit version are you using? There are compilation problems in the Wave 1.0.0 version because of late breaking changes in the Spirit library. Please try to use the Wave version from here: Wave V1.0.4[^]. This should solve all compilation problems with Boost V1.30.2/Spirit V1.6.x and Boost V1.31.0/Spirit 1.8.x.
 
Regards Hartmut

GeneralCompile WavememberEduardooo29 Mar '04 - 3:20 
Hello!
I tryed to compile Wave 1.0.4 with gcc 3.3.4, it dinit work because of spirit an boost, that are ready to compile in linux or unix, not in windows (my plataform).
Could you give me some instructions on how to compile it?
 
Thnaks a lot!
Eduardo
GeneralRe: Compile WavememberHartmut Kaiser29 Mar '04 - 3:35 
Eduardooo wrote:
I tryed to compile Wave 1.0.4 with gcc 3.3.4, it dinit work because of spirit an boost, that are ready to compile in linux or unix, not in windows (my plataform).
Could you give me some instructions on how to compile it?

 
Could you be a little bit more specific? What does not compile, which errors do you get? I've tried to compile it with gcc 3.3.1 (Windows/Cygwin) and had no problems at all.
 
If you want, we may take this discussion offline: hkaiser [at] users [dot] sourceforge [dot] net.
 
Regards Hartmut

GeneralRe: Compile WavememberRoss MacGregor20 May '04 - 22:55 
Is it possible to compile wave with MS VC6.0? I know some boost libs don't work great with VC6.

GeneralRe: Compile WavememberHartmut Kaiser20 May '04 - 23:01 
Ross MacGregor wrote:
Is it possible to compile wave with MS VC6.0? I know some boost libs don't work great with VC6.
 
No sorry, no VC6 (yet - do you want to help porting it?)
 
Regards Hartmut
GeneralRe: Compile WavememberBitmonk820 Sep '04 - 10:55 
I have tried to compile Wave 1.0.6 with Boost V1.30.2 and Boost V1.31.0.
 
Boost V1.30.2 doesn't compile, it complains about a template specialization of a boost:spirit class.
 
Boost V1.31.0 seems to work fine (with the provided program_options project).
 
Best regards,
Thomas Andersen
GeneralTwo questions!memberNosAchamos22 Mar '04 - 3:24 
Nice tool! But I'm having a little (newbie?) problem:
 
1) the include path don't seem to find files, I tried using "-I c:\mingw32\include" and "--include \mingw32\include" and stuff like that, it just don't seem to find the header files. Am I using it the right way?
 
2) can I set multiple directories with the -I option?
 
thanks
GeneralRe: Two questions!memberHartmut Kaiser22 Mar '04 - 3:46 
NosAchamos wrote:
Nice tool!
 
Thanks!
 
NosAchamos wrote:
1) the include path don't seem to find files, I tried using "-I c:\mingw32\include" and "--include \mingw32\include" and stuff like that, it just don't seem to find the header files. Am I using it the right way?
 
-I (--include) finds the files only, which are specified with an #include "..." directive, not those to included with #include <...>. To find those, you'll have to use -S (--sysinclude). This is very much modelled after the way, how it's implemented in gcc.
 
NosAchamos wrote:
2) can I set multiple directories with the -I option?
 
Sure. Multiple -S should work too.
 
Regards Hartmut

Generalwarning: last line of file ends without a newlinesussoneocean4 Feb '04 - 14:50 
test.c is as following
 
#include "test.h"
int i;

 
I found that if the last line of header file(test.h) is ends without a newline, the preprocessor won't generate result for test.c( maybe won't parse).
 
Is that an expecting behavior?
GeneralRe: warning: last line of file ends without a newlinememberHartmut Kaiser6 Feb '04 - 2:30 
Currently, the Wave library uses exceptions to report errors and warnings to the client code, i.e. the normal preprocessing is interrupted, whenever a warning or an error is diagnosed.
 
This behaviour leads directly to the effect you've reported. The preprocessing is canceled at the point, where the warning is issued, i.e. at the end of the included file "test.h". So the int i; statement is never seen by the preprocessor.
 
Regards Hartmut

GeneralRe: warning: last line of file ends without a newlinesussAnonymous28 Nov '04 - 11:48 
Exceptions are great for reporting errors (my own, as yet incomplete, C++ preprocessor uses them for that) but warnings are different -- they normally should not abort the current operation.
 
To be fair, I don't have a good solution for warnings either; nothing else in my preprocessor uses any global state, but I don't really want to have to pass a warning sink around to every single place that might want to issue a warning.

GeneralRe: warning: last line of file ends without a newlinememberBoniolopez22 Aug '06 - 8:17 
Hi,
I am wondering that exception is thrown on warnings too. Why not just add one more if to BOOST_WAVE_THROW?
i.e.
if (severity!=util::severity::warning) throw blabla.

Generalconfig file problemsussoneocean2 Feb '04 - 21:23 
when I put the following command in a config file(ex. define.txt)
 
-D Enable
 
and run: wave.exe test.c @define.txt
 
it seems wave doesn't recognize -D option and return following error message
 
command line(0): command line error: invalid macro definition: Enable
 
I also tried -P and got similar result. What's wrong with that?

GeneralRe: config file problemmemberHartmut Kaiser3 Feb '04 - 1:34 
Hi,
 
This isn't the expected behaviour! Thanks for reporting this, I'll have a look at it ASAP.
 
Please try in the mean time to use the -D and -P switches without any whitespace in between the option and the macro name, i.e.
 
-DEnable
 
and not
 
-D Enable
 
this should work.
 
Thanks and regards
Hartmut
 

GeneralGreatmemberJohn R. Shaw22 Jan '04 - 11:03 
You got my 5!
I was glued to this article for the pass half hour.
I have not looked at the code yet, but I will. I hope by examining the code that it will give me ideas or point me in a new direction (way of thinking).
 
I love to learn.
 
INTP
GeneralRe: GreatmemberHartmut Kaiser22 Jan '04 - 20:14 
John R. Shaw wrote:
You got my 5!
 
Thanks.
 
John R. Shaw wrote:
I have not looked at the code yet, but I will. I hope by examining the code that it will give me ideas or point me in a new direction (way of thinking).
 
Simply drop me a note, if I may be of any assistence to you.
 
Regards Hartmut

Generalinternal compiler errormemberdrkhound14 Jan '04 - 16:46 
Hi again,
 
I'm having difficulties compiling wave 1.0 (I use vs .net 2003 v 7.1.3088)
 
first, by using boost 1.30.2, I got many errors, which I fixed by downloading spirit 1.7.0.
 
Then I got wrong include path error:   (wave couldnt find
cpp_grammar.hpp and cpp_predef_macros_grammar.hpp couldnt find boost/spirit/utility/parsers/lists.hpp and
boost/spirit/utility/parsers/confix.hpp
so I changed the include path by removing parsers/ (parsers/ doesnt exist in spirit).
 
but then, I got an internal compiler error.
compiler output gives:
Compiling...
instantiate_predef_macros.cpp
instantiate_cpp_grammar.cpp
cpp.cpp
C:\boost-1.30.2\boost\iterator_adaptors.hpp(686) : fatal error C1001: INTERNAL COMPILER ERROR
            (compiler file 'msc1.cpp', line 2701)
 
Can anyone help?
 
Btw, is there a forum or something where one might find info about this kind of problem?
 
thanks
GeneralRe: internal compiler errormemberHartmut Kaiser16 Jan '04 - 5:26 
Sorry for the delayed response, I was offline for a couple of days ...
 
drkhound wrote:
first, by using boost 1.30.2, I got many errors, which I fixed by downloading spirit 1.7.0.
 
Yes, I've already got a report, that Wave does not compile out of the box with Boost 1.30.2/Spirit 1.6.1. Sorry for that, I'm working on a solution, please stay tuned. The errors are based on the fact, that there were some subtle interface breaking changes in Spirit since its last release.
drkhound wrote:
Then I got wrong include path error: (wave couldnt find
cpp_grammar.hpp and cpp_predef_macros_grammar.hpp couldnt find boost/spirit/utility/parsers/lists.hpp and
boost/spirit/utility/parsers/confix.hpp
so I changed the include path by removing parsers/ (parsers/ doesnt exist in spirit).

 
That's the only way to do it. BTW in the soon to be released Spirit V1.8.0 the directory structure was reverted to the previous one and these problems should be fixed then (I'll update the Wave archives on this site shortly after the new release is out).
 
drkhound wrote:
but then, I got an internal compiler error.
 
This one is strange and I don't know, what's going on. My experience with VC7.1 ICE's are, that they happen often if the compiler sees wrong C++ code, but this couldn't be... Hmmm, is it possible for you the get a current Boost version from the CVS - use the -r RC_1_31_0 command line option, while getting Boost (BTW this should contain a fairly up to date Spirit version too, so there isn't any need to have a separate Spirit version in this case)?
 
Regards Hartmut
 

QuestionOutput of dependency tree?memberladislav Hruska14 Jan '04 - 8:45 
Does Wave have any option to ouput dependency tree for TU? Or even update 'project database' of dependencies?
 
And it also sounds as beginning of full C++ parser, doesn't it?
AnswerRe: Output of dependency tree?memberHartmut Kaiser16 Jan '04 - 5:14 
Sorry for the delayed response, I was offline for a couple of days ...
 
ladislav Hruska wrote:
Does Wave have any option to ouput dependency tree for TU?
 
The Wave driver hasn't such an option, but the Wave library essentially has. The wave::context<> type has an optional trace related policy, which could be used not only for the tracing of the macro expansion process (as implemented in the Wave driver program), but also for tracking, which include files are found/opened. There is an additional sample inside the source code archive illustrating this. But please note, that there may be a problem, if you expect to get a full dependency tree, because the Wave library only tracks those include directives, which are visible to the preprocessor. Consider the following sample:
 
#if defined(SOME_PP_CONSTANT)
#include
#else
#include
#endif
 
where the Wave library will report only the include file, which correspondents to the SOME_PP_CONSTANT defined state - Wave will report only file_a.h or file_b.h
 
ladislav Hruska wrote:
Or even update 'project database' of dependencies?
 
Do you mean in *.pbd format?
 
ladislav Hruska wrote:
And it also sounds as beginning of full C++ parser, doesn't it?
 
Yes, I'm working on it (occasionally), but this is a major adventure, so I have not results yet.
 
Regards Hartmut
 

GeneralRe: Output of dependency tree?memberladislav Hruska17 Jan '04 - 6:03 

Hartmut Kaiser wrote:
ladislav Hruska wrote:
Or even update 'project database' of dependencies?
 
Do you mean in *.pbd format?

 

I do not know about *.pdb format. I mean data in some predefined CSV or XML format.
GeneralRe: Output of dependency tree?memberHartmut Kaiser17 Jan '04 - 9:26 
ladislav Hruska wrote:
I do not know about *.pdb format. I mean data in some predefined CSV or XML format.
 
If you use the mentioned callback trace policy you can output the dependency information in whatever format you want. How do you would like to have the header dependency output?
 
Regards Hartmut

Generalgetting original file &amp; linememberdrkhound13 Jan '04 - 18:43 
Just a quick question. With the actual wave version, would it be possible to easily get the original file and line number from another file/line ?
 
For example, when a cpp is preprocessed, the compiled cpp is obviously not the same as the original. But normally, the build process, in the case of an error/warning, is able to clearly indicate in which file and which line the original error/warning occured.
 
for example:
 
//main.cpp file
// line 0
#include "test.h"
 
int main()
{
      //...
}
 
// line 8 (end of main.cpp)
 
//test.h
//line 0
inline void test(int i)
{
      i = &i; //line 3, gives error
}
//line 4 (end of test.h)
 
the pp will output this file:
 
//main_pp.cpp
// line 0
inline void test(int i)
{
      i = &i; //line 4
}
 

int main()
{
      //...
}
 
// line 13
 
So when the compiler sees the error in file main_pp.cpp at line 4, I'd need to know that it was in fact line 3 of file test.h that failed.
 
Is there an easy way to do this ?
 
thanks for your time
GeneralRe: getting original file &amp; linememberHartmut Kaiser13 Jan '04 - 18:56 
Hi,
 
every token returned while dereferencing the Wave supplied iterators contains the full position information of the point, where this token was found. I.e.
 
context_t ctx(input.begin(), input.end(), "input.cpp");
context_t::iterator_t first = ctx.begin();
context_t::iterator_t last = ctx.end();
 
while (first != last) {
context_t::token_t current_token = *first;
context_t::position_t current_position =
current_token.get_position()
 
std::cout << current_token.get_value();
 
// current_position.get_file(); returns current file name
// current_position.get_line(); returns current line
 
++first;
}
 
HTH
Regards Hartmut

Generalerror in VC++.NETmemberlorenzo.dematte@ibttn.it3 Oct '03 - 5:44 
I'm using VC++.NET with STLPort 4.5.3 and boost 1.30.2, but I can't compile wave... I have several errors on this line
 
Wave\wave\util\unput_queue_iterator.hpp(139) : error C2065: "IteratorT": undeclared identifier
Wave\wave\util\unput_queue_iterator.hpp(139) : error C2065: "TokenT": undeclared identifier
Wave\wave\util\unput_queue_iterator.hpp(139) : error C2065: "ContainerT": undeclared identifier
 
what's wrong?
 

GeneralRe: error in VC++.NETmemberlorenzo.dematte@ibttn.it3 Oct '03 - 6:29 
oh, I see... no support for Visual C++.NET 2002 (or 7.0), neither in Wave nor in Spirit.. sigh!
 

GeneralRe: error in VC++.NETmemberHartmut Kaiser3 Oct '03 - 6:40 
lorenzo.dematte@ibttn.it wrote:
oh, I see... no support for Visual C++.NET 2002 (or 7.0), neither in Wave nor in Spirit.. sigh!
 
Yes, sorry. Please upgrade to the VC7.1 (VS.NET 2003). It's worth it!
 
Regards Hartmut

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 11 Jan 2004
Article Copyright 2003 by Hartmut Kaiser
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid