diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..3e84d7c70 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..47a6b4924 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1142 @@ +Wave: A Standard compliant C++ preprocessor library +http://spirit.sourceforge.net/ + +Copyright (c) 2001-2005 Hartmut Kaiser. 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) +------------------------------------------------------------------------------- + +TODO (known issues): +- Fix expansion of macros, which replacement-list terminates in a partial + macro expansion. +- Fix the re2c lexer for iterators others then string::iterator (or more + generally for iterators, which aren't random access iterators) +- Enforce, that #if/#endif are balanced file wise +- Try to remove the second parameter from the pp_iterator<>::force_include + function. +- Fix the trigraph backslash problem in the re2c (C/C++ and IDL) scanners, if + there is the end of the (internal) buffer just in between a '??/' and a '\n'. + +- Do a sourceforge release. + +------------------------------------------------------------------------------- + +CHANGELOG + +Mon Feb 21 09:30:04 WEST 2005 +Version 1.1.14 (Fixes in response to the Boost review) + +Wave was accepted into Boost! + +With special thanks to Tom Brinkman, who volunteered to be the review manager. + +With thanks to David Abrahams, Beman Dewes, Reece Dunn, Larry Evans, +Doug Gregor, Joel de Guzman, Baptiste Lepilleur, Andy Little, Paul Mensonides, +Dan Nuffer, Andreas Pokorny, Vladimir Prus, Gennadiy Rozental, Michiel Salters, +Jonathan Turkanis, Chris Uzdavinis, Pavel Vozenilek, Michael Walter for bug +reports, fixes and hints. + +- Added support for the MS extensions #region and #endregion, which simply get + ignored by Wave. The support for these is enabled only, when the pp constant + BOOST_WAVE_SUPPORT_MS_EXTENSIONS is defined. Otherwise these get flagged as + an illegal preprocessor directive (as before). +- Fixed a problem, where the replacement text for a #pragma directive got lost + if this directive was on the last line of a processed (include-)file. +- Changed the default value for BOOST_WAVE_SUPPORT_MS_EXTENSIONS for non- + Windows systems to zero. +- Updated outdated external links in the documentation. +- Fixed certain grammatical and stylistic quirks in the documentation. +- Fixed a problem in libs/wave/build/Jamfile.v2 (as reported by Larry Evans). + Fixed the Jamfile.v2 in the samples directories accordingly. +- Added the 'vc-7_1:off' to all Jamfile.v2 files to adjust for + the internal buffer overflow bug in the VC7.1 compiler (reported by Joel de + Guzman). +- Changed the 'vc-7_1:off' to 'vc-7.1:off' as + required by the Boost.Build.v2 library (suggested by Vladimir Prus). +- Finally fixed the Jamfile.v2 file (after a suggestion from Reece Dunn) +- Fixed the column number reported for tokens for Slex lexer based + configurations (reported by Baptiste Lepilleur). +- Added the __BASE_FILE__ predefined macro, which contains a string literal + of the main file name to preprocess (the one the context<> template was + created with). (suggested by Pavel Vozenilek) +- Used the boost::reverse_iterator instead of the std::reverse_iterator + for the flex_string class to allow compilation of Wave with VC7.0 + (as suggested by Reece Dunn). +- Fixed a problem in the include_path template, which throwed a + boost::filesystem exception whenever a character was used in a file name + to include, which is marked as illegal by the default name checker of the + boost::filesystem::path. + +Version 1.1.13 (Boost review candidate 2, bug fixed version) +- Fixed a problem, where the context<> template referenced temporary iterator + objects from the underlying stream (thanks to Michiel Salters for reporting + this). +- Fixed a bug in the re2c lexer, which allowed to dereference the end iterator + of the underlying input stream (thanks to Doug Gregor for pointing this out). +- Fixed several assertions fired by the iterator checking code of the VC8 stl. + +Version 1.1.12 (Boost review candidate) +- A rough performance analysis showed, that 30% of the time is spent parsing + the input for pp directives (cpp_grammar), 35% of the time is spent inside + the flex_string code, mainly in the copy constructor and assignment + operator, 15% of the time is spent inside the list and vector member + functions, 10% is spent for memory allocation but only 1% of the time is + spent in the re2c lexer. +- Identified a performance problem, where the token_cache was instantiated + for every created lexer object, but needed to be initialsed only once. +- Added #include to wave_config.hpp +- Fixed problems reported by the gcc 3.4.1 compiler. +- Adjusted Jamfiles for the new toolset names introduced in Boost V1.32. + +Version 1.1.11 +- Updated copyrights. +- Fixed some bugs introduced by the latest refactoring. +- Tried to fix the expansion of macros, which replacement-list terminates in a + partial macro expansion. No success so far. + +Version 1.1.10 +- Refactored some of the macro map (macro namespace) code (added comments, + splitted into separate files), +- Fixed some typename errors in cpp_macromap.hpp (thanks to Vladimir Prus). +- Fixed the BoostBuild V2 Jamfiles (thanks to Vladimir Prus). + +Version 1.1.9 +- Moved all of the #pragma wave option(value) operators out of the wavelib into + the wave driver program. Removed enable_trace() and trace_flags() policy + functions. Renamed trace_policy into context_policy. +- Added the defined_macro() and undefined_macro() preprocessing hooks to allow + easily to build macro cross referencers and such. + +Version 1.1.8 +- Replaced the usage of the string::erase() and string::insert() functions, + which were the only non-const string member functions used. +- Token pasting is now well defined in variadics mode (was in C++0x mode only). +- Changed the timing code in the wave driver to include the parsing of + files included by the --forceinclude command line switch. +- Performance measurements (very informal) [sec], the files are some of the + preprocessor specific test cases from Paul Mensonides chaos_pp library. + + std::string flex_string const_string const_string + 12 Byte 28 Byte + arithmetic.cpp 2.543 1.742 0.951 1.001 + array.cpp 2.453 1.762 0.951 1.011 + comparison.cpp 0.560 0.340 0.270 0.280 + control.cpp 0.590 0.340 0.290 0.300 + debug.cpp 0.370 0.310 0.190 0.190 + detection.cpp 0.050 0.060 0.030 0.030 + extended.cpp 0.370 0.260 0.190 0.190 + facilities.cpp 0.610 0.340 0.290 0.300 + iteration.cpp 1.081 0.550 0.410 0.450 + list.cpp 1.742 1.141 0.811 0.851 + logical.cpp 0.070 0.200 0.040 0.040 + punctuation.cpp 0.030 0.080 0.020 0.020 + repetition.cpp 1.392 0.851 0.650 0.690 + selection.cpp 0.440 0.270 0.210 0.220 + slot.cpp 0.680 0.350 0.240 0.270 + tuple.cpp 0.420 0.240 0.190 0.210 + + +Wed Aug 25 13:23:27 WEDT 2004 +Version 1.1.7 +- Branched for Boost Release. +- Removed several features from the code base: + . removed C++0x support + . removed TST support +- Fixed the program_option validator syntax, which has changed since the last + update. +- Removed misleading configuration options from the cpp_config.hpp file, + because the application will have to use the same config options as were used + during the compilation of the library. +- Changed the naming convention of typedef'd types in the library. Removed the + _t suffix, wherever possible. +- Updated the documentation to reflect the removal of the C++0x features. + +- Changed the licensing scheme to: +// Copyright 2004 Joe Coder. 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) + +Mon May 24 10:02:47 WEDT 2004 +Version 1.1.6 +- Fixed a incompatibility with the new program_options version. + +Version 1.1.5 +Version 1.0.6 +- Fixed a bug, which reported an #include statement as ill formed, if it was + followed by an empty C comment only. This was an error in the cpp.re regular + expression for C comments. Additionally, since this change simplified the + Re2C generated lexer a lot it was possible to remove the compiler workaround + for the VC7.1 compiler which prevented the optimization of this lexer. + +Mon Mar 29 09:36:59 WEDT 2004 +- Corrected the signature of the main() functions (was main(int, char const*[])). + +Sun Mar 28 12:55:59 WEDT 2004 +Version 1.1.4 +- Fixed a problem, where the first returned token was lost, whenever a + --forceinclude file was given. +- Adjusted the Wave driver and the other samples to use the new program_options + library syntax (V1.1.x only). + +Mon Mar 1 19:14:21 WEST 2004 +Version 1.1.2 +Version 1.0.4 +- Fixed a problem, which does not report an error, if in a #define statement in + between a macro name and its replacement list were no whitespace given. +- Fixed a bug, which generated an unexpected exception of the $ character in the + input. +- Macro definitions, which differ by whitespace only (one definition contains + whitespace at a certain position, the other definition does not) are correctly + reported as a warning now. +- Fixed a problem, where different formal argument names during macro + redefinition were not flagged as a warning. +- A wide character string used in a #line directive wasn't flagged as an error. + +Sun Feb 29 19:10:14 WEST 2004 +Used the test suite distributed with the mcpp V2.4 preprocessor to fix a bunch +of mostly minor issues: +- Fixed trigraph backslash followed by a newline handling (??/ \n) in the + re2c (C/C++ and IDL) scanners. +- Fixed a digraph/trigraph token type handling problem during macro expansion. +- Fixed a digraph/trigraph token type problem during handling of the null + preprocessor directive. +- Fixed several signed/unsigned conversion bugs in the expression evaluator. +- Fixed the || and && operators in the expression evaluator to stop evaluation, + as only the outcome of the overall expression is determined. +- Fixed the expression evaluation engine to detect divide by zero errors. +- Fixed a bug with operator || and && arithmetic (the deduced type was wrong). +- Fixed a bug with the unary operators ! and - which IN conjunction with an + arithmetic operation yielded A wrong result type. +- Fixed a bug, which reported a macro definition as an invalid redefinition, if + it was different from the original definition only by different whitespaces. +- Fixed a bug, which reported the redefinition of one of the alternative tokens + as 'and', 'bit_and' etc. as invalid. +- Fixed a bug in the character literal parser, which prevented the recognition + of multibyte character literals. + +- Moved the cpp_token_ids.hpp header into the main wave.hpp header, because the + values defined therein aren't changeable by the user anyway. +- Fixed some spelling errors in the documentation (thanks to Rob Stewart). + +Tue Feb 3 20:20:16 WEST 2004 +- Fixed the problem, that macro definitions in a config file were flagged as + an error, if there was any whitespace in between the -D and the macro name + (same problem existed for -P). + +Fri Jan 30 20:28:27 WEST 2004 +- Fixed a missing boostification in the trace support header. +- Added a missing std:: namespace qualification to the list_includes.cpp sample + file. +- Fixed line ending problems with the cpp.re and idl.re files. +- Added quick_start sample. + +Sun Jan 25 20:26:45 WEST 2004 +This version was submitted to Boost as the review candidate (V1.1.0) +- Fixed invalid explicit instantiation syntax as reported by the Comeau + compiler. +- Added a missing header to flex_string.hpp. + +Sat Jan 24 19:47:44 WEST 2004 +- Completely decoupled the used lexer from the preprocessor. +- Unfortunately had to change the template interface of the context class. It + now instead of the token type takes the type of the lexer to use. +- Reintroduced the cpp_tokens, list_includes and waveidl samples. + . cpp_tokens is based on the SLex lexer + . list_includes shows the usage of the include file tracing capability + . waveidl uses the Re2C based IDL lexer in conjunction with the default token + type + +Tue Jan 13 20:43:04 WEST 2004 +- Fixed several compilation issues under linux (gcc 3.2.3, gcc 3.3, gcc 3.3.2, + gcc 3.4, Intel V7.1) +- Fixed a compatibility problem with Spirit versions older than V1.7. + +Mon Jan 12 20:39:50 WEST 2004 +- Boostified the code base: + . Moved code into namespace boost. + . Prefixed all pp constants with "BOOST_". + . Refactured the directory structure. +- Removed IDL mode and SLex lexer from the code base. These will be re-added as + samples. +- Changed the Wave configuration system to be more flexible (all + #if defined(BOOST_WAVE_...) changed to #if BOOST_WAVE_... != 0), + which allows to configure the library without changing the code base itself + +Sat Jan 10 18:17:50 WEST 2004 +- Incorporated Andrei Alexandrescu's latest changes to the flex_string class, + which resulted in an overall spedd gain of about 5-10%. + +Wed Jan 7 17:46:45 WEST 2004 +- Found a major performance hole! The achieved general speedup is about 50-70%. +- Added missing old MS specific extensions to the re2c lexer (_based, + _declspec, _cdecl, _fastcall, _stdcall, _inline and _asm). +- Added support for #include_next (as implemented by gcc). +- Fixed compilation problems with gcc 3.3.1 +- Avoid to look up in symbol table of a potential macro name twice. +- Added the Spirit SLex lexer sample to the Wave source tree, because it was + removed from the Spirit distribution. +- Removed the configuration option, which allowed to reverse the names stored + in the symbol tables. +- Implemented experimental support for using a TST (ternary search tree) as the + container for the symbol tables. + +Sun Jan 5 12:30:50 2004 +- Released V1.0.0 + +Sun Jan 4 00:11:50 2004 +- Removed tabs from the flex_string.hpp file. +- Modified the input_functor.hpp file to sqeeze out some milliseconds at + runtime. +- The --timer option now prints the overall elapsed time even if an error + occured. +- Added support for #pragma once. + +Fri Jan 2 22:58:54 2004 +- Fixed a bug in the code, which predefines the preprocessor constants. +- Fixed a bug in intlit_grammar<> initialisation code. + +Thu Jan 1 21:15:03 2004 +- Fixed a bug while predefining a macro with a value through the commmand line. +- Fixed a bug, which reported a macro definition as illegal, if the redefined + macro was a function like macro with parameters. +- Fixed a bug, if concatenation of two tokens resulted in a C++ comment start + token. + +Thu Jan 1 15:01:54 2004 +- Finished license migration. + +Wed Dec 31 12:23:55 2003 +- Changed the copyright and licensing policiy to be Boost compatible. + +Wed Dec 31 12:01:14 2003 +- Fixed a problem while compiling certain headers from the Microsoft Windows + SDK: + #define CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y,\ + nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\ + CreateWindowExA(0L, lpClassName, lpWindowName, dwStyle, x, y,\ + nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) + where essentially is no whitespace between the parameter list and the macro + replacement list. +- Fixed a problem with the MS extension __declspec, which now is recognized + correctly. + +Sat Dec 27 14:48:29 2003 +- Fixed remaining problems with assign/assign_a. +- Fixed some gcc warnings about signed/unsigned comparision mismatch. + +Tue Nov 11 20:51:41 WEST 2003 +- Changed the IDL mode to recognize identifiers only. All keywords (except + 'true' and 'false') are returned as identifiers. This allows for easy + extension of the IDL language. The drawback is, that after preprocessing + there needs to be just another lexing stage, which recognizes the keywords. +- Fixed a possible problem, when in between a #if/#elif directive and a + subsequent opening parenthesis Wave finds no whitespace: + #if(_WIN_VER >= 0x0500) + is now recognized correctly. + (This problem was pointed out by Porter Schermerhorn). + +Sun Nov 9 21:05:23 WEST 2003 +- Started to work on implementation of an IDL lexer for the TAO idl compiler. + . Branched off the Re2C C++ lexer and related files as a starting point for + the new IDL lexer. Added connfiguration means to allow compile time + decision, in which mode to operatoe (C++ or IDL). + . Implemented the Re2C based IDL lexing component. + . Fixed all occurences of non-IDL tokens (as T_COLON_COLON and T_ELLIPSIS) + +Sat Nov 8 20:05:52 WEST 2003 +- Version 1.0.0 +- Munged the email addresses embedded within the source files. +- Adjusted for the new actor names in Spirit (assign_a and append_a). + +Thu Aug 21 16:54:20 2003 +- Removed the internally used macro 'countof()' to avoid possible nameclashes + with user code. +- Fixed a bug, which prevented the execution of the concatination operator '##' + while expanding object-like macros. + +Tue Aug 5 10:04:00 2003 +- Fixed a false assertion, if a #pragma directive started with some whitespace + on the line. +- Added the #pragma wave timer() directive to allow rough timings during + processing. This is done on top of a new callback hook for unrecognized + #pragma's, which allows to easily add new pragma commands without changing + the Wave library. +- Fixed a bug in the whitespace insertion engine, which prevented the insertion + of a whitespace token in between two consecutive identifier tokens or a + integer literal token followed by an identifier token. +- Fixed a bug during macro concatenation, which allowed to concatenate + unrelated tokens from the input stream: + #define CAT(a, b) PRIMITIVE_CAT(a, b) + #define PRIMITIVE_CAT(a, b) a ## b + #define X() B + #define ABC 1 + CAT(A, X() C) // AB C + CAT(A, X()C) // correct: AB C, was 1 +- Fixed a 64 bit portability problem. +- Added pragma wave timer(suspend) and wave timer(resume) +- Fixed a ODR problem with static initialization data for predefined macros. +- Ported the iterators to the new iterator_adaptors. +- Updated the documentation to reflect the recent changes + +Sun Jun 29 12:35:00 2003 +- Fixed 64 bit compatibility warnings. +- Fixed a bug, which prevented the correct recognition of a #line directive, if + only the filename part of this directive was generated by a macro expansion. +- Fixed a bug during macro expansion of conditional expressions, which + prevented the correct expansion of certain scoped macros. + +Fri Jun 27 09:50:14 2003 +- Changed the output of the overall elapsed time (option --timer) to cerr. +- Added a configuration constant WAVE_REVERSE_MACRONAMES_FOR_SYMBOLTABLE, which + reverses the macro names while storing them into the symbol table, which + allows to speed up name lookup especially, if the macro names are very long + and if these share a common prefix. +- Fixed a very subtle bug, which prevented the recognition of fully qualified + macro names during the macro expansion of conditionals expressions (for + #if/#elif). +- Improved the error output for the illformed pp expression error. + +Thu Jun 26 08:20:30 2003 +- Done a complete spell check of the source code comments. + +Wed Jun 25 20:33:52 2003 +- Changed the conditional expression engine to work with integer numeric + literals only. Distinguished signed and unsigned literals. +- Importing a region twice is allowed now. +- Fixed a bug, which does not removed all placeholder tokens from a expanded + token sequence while evaluating conditional expressions (C++0x mode only). + +Wed Jun 25 15:01:51 2003 +- Changed the conditional expression engine to respect the type of numeric + literals, now expressions like '#if 1 / 10 == 0' evaluate correctly (to true + :-) +- Fixed a bug, where macro names referring to global macros (as ::A::B) were + not correctly recognized under certain circumstances. +- Empty parameter lists for macros with ellipses only sometimes generated a + placemarker token in the output: + #define STR(...) #__VA_ARGS__ + STR() // resulted in "§" instead of "" . + +Wed Jun 25 08:35:06 2003 +- Fixed several gcc compilation errors (missing typename's etc.) +- Fixed a compilation problem, if Wave is built on top of the SLEX scanner. +- Reformatted the --timer output from pure seconds to a more reasonable format. + +Fri Jun 20 19:33:30 2003 +- Changed the enable_tracing function of the tracing_policies to take a + trace_flags variable instead of a bool, to allow to control tracing with more + granulation. +- Added the tracing_enabled function to the tracing_policies, which returns the + current tracing status. +- Updated the documentation of the tracing policies. + +Thu Jun 19 21:45:39 2003 +- Reactivated the list_includes sample with the help of the new include file + tracing facility. + +Thu Jun 19 17:55:35 2003 +- Eliminated the TraceT template parameter from the macromap<> template. +- Added two hooks to the trace policy to allow to trace the opening and + closing of include files. + +Thu Jun 19 14:08:10 2003 +- Added the command line option --timer, which enables the output to std::cout + of the overall elapsed time during the preprocessing of the given file. + +Fri Jun 13 09:11:29 2003 +- Emitted an error message, if an ellipses was found as a formal macro + parameter and variadics were disabled. +- Fixed a false error message, that the last line was not terminated with a + newline, which occured, if no output was generated by the last line of the + source file. + +Thu Jun 12 15:20:22 2003 +- Fixed the recent change in argument expansion for the variadics/C99/C++0x + mode. +- Fixed a problem, where an additional whitespace between _Pragma and the + opening parenthesis resulted in a false error message. +- Used a pool allocator for the token sequence containers (std::list<>'s), + which gives a speed gain of more than 60% (while profiling the Order + library). + +Wed Jun 11 22:18:54 2003 +- Fixed a macro scoping/expansion problem, when a macro returned a full scope + which is continued on the call site to form a full qualified name, the name + wasn't recognized correctly: + # region A + # define MACRO 1 + # region B + # define MACRO 2 + # endregion + # endregion + # define ID(x) x + ID(A)::MACRO // 1 + ID(A::B)::MACRO // 2, was expanded to A::B::MACRO +- Changed the expansion of macro arguments such, that these will be expanded + only, if the result is to be used for substitution during the expansion + of the replacement list. + +Wed Jun 11 14:40:29 2003 +- Included a whitespace eating finite state machine (FSM) for minimal + whitespace in the generated output. This was suggested by Paul Mensonides. +- Updated the acknowledgement section + +Wed Jun 4 08:03:04 2003 +- Fixed a bug reported by Faisal Vali, which prevented the correct evaluation + of conditional expressions, if these referenced macro names, which expanded + to a sequence containing non-expandable tokens. +- Fixed the above bug for #elif directives too (in the first place this was + fixed for #if directives only) + +Mon May 26 22:15:40 2003 +- Added missing copyrights in several files. +- Fixed false output, if a unknown _Pragma were encountered. +- Fixed a macro expansion problem with qualified names, were constructs like + the following were not expanded correctly: + #define ID(x) x + #region SCOPE + # define TEST 1 + #endregion + ID(SCOPE::) TEST // should expand to 1 +- Changed #import semantics for macros from copy semantics to reference + semantics, i.e. macros are now considered to be implicitly imported into the + scope, where they are defined. If a macro is imported into another scope and + the original macro is undefined, the imported macro still exists. Further, + if the imported macro is expanded, then while rescanning the original macro + is disabled too: + #region A + # define B(x) x + #endregion + #import A + B (A::B) (*) // A::B(*) + A::B (B) (*) // B(*) + B (B) (*) // B(*) + A::B (A::B) (*) // A::B(*) +- Fixed a recently introduced problem, where placemarker tokens slipped through + to the output under certain conditions (in variadics/C99/C++0x modes only). + +Mon May 19 16:30:49 2003 +- Fixed a bug, which prevented the recognition of the __lparen__, __rparen__ or + __comma__ alternative tokens, if these were the first token after an emitted + #line directive (reported by Vesa Karvonen). +- Added an optimization, that only those tokens are considered for a macro + expansion, which may result in an expansion. + +Tue May 13 18:16:26 2003 +- Fixed a newly introduced problem, where a omitted argument consisting out + of whitespace only were failed to be replaced by a placemarker token. This + lead to problems with constructs like the following: + #define paste(a, b, c) a ## b ## c + paste(1, , 3) // should expand to 13, but expanded to 1## 3 +- Fixed a problem with the tracing support, which throwed an unexpected + exception if there were too few arguments given while expanding a macro. +- Allowed to open and to import the global scope ('#region ::' and + '#import ::'). +- Fixed a bug, if more than one file was given with a --forceinclude command + line option. + +Sat May 10 21:30:29 2003 +- Added __STDC_FULL_REGION__ and __STDC_CURRENT_REGION__ to the list of not + undefinable macros. +- In normal C++ mode and C99 mode the #ifdef/#ifndef and the operator defined() + should not support qualified names. This is fixed now. +- Updated the documentation. +- Fixed minor gcc -Wall compilation warnings. +- Added better error support for qualified names used as arguments for #ifdef, + #ifndef and operator defined(). + +Sat May 10 09:51:18 2003 +- Removed the feature, that the comma before the ellipsis parameter in a macro + definition may be omitted. +- Resolved an issue with the expansion of qualified macros, when these + qualified names were partially generated by a previous macro expansion +- Allowed to specify fully qualified names as arguments to the #region directive + +Wed May 7 22:44:21 2003 +- Changed the names of __SCOPE__ and __FULL_SCOPE__ predefined macros to + __STDC_CURRENT_REGION__ and __STDC_FULL_REGION__ resp. The names are subject + to change if the #region keyword actually will be renamed to #scope/#module + or whatever. +- In C++0x mode it is now possible to omit the last comma before a variadics + ellipsis in a macro definition: + #define cat_i(a, b, c, d, e ...) a ## b ## c ## d ## e +- Fixed a bug in the stringize code, where an ellipsis to stringize resulted in + stringizing of the first ellipsis parameter only. Preserved the original + whitespace delimiting in between the ellipsis arguments. +- Introduced the wave::language_support enum for convenient switching of the + supported language features throughout the library. +- Fixed a bug, which prevented the definition of the predefined macro + __WAVE_HAS_VARRIADICS__, if --variadics were given on the command line. + +Tue May 6 15:49:45 2003 +- Made predefined macros available at every macro scope without qualification. +- Predefined a new macro in C++0x mode: __STDC_GLOBAL__, which is defined at + global macro scope only and equals to '1' (integer literal). +- In C++0x mode there are two new predefined macros: + __SCOPE__: expands to the last part of the qualified name of the + current macro scope + __FULL_SCOPE__: expands to the full qualified name of the current macro + scope + +Mon May 5 23:02:48 2003 +- Fixed a problem in the new well defined token pasting code, which occured for + constructs like the following: + #define is_empty(...) is_empty_ ## __VA_ARGS__ ## _other + i.e. where two or more '##' operators were contained in the replacement text. +- Implemented __comma__, __lparen__ and __rparen__ alternative pp-tokens, which + may be used as the ',', '(' and ')' tokens during preprocessing. These are + only converted to there respective string representation in a special + translation phase after preprocessing. This was proposed by Vesa Karvonen. +- Changed the macro scoping rules to: "If a qualified name does not find a + nested name, it is not a qualified name to the preprocessor." This seems to + be the simplest usable solution for the possible ambiguities. +- Fixed a bug in the macro expansion engine in C++0x mode, where the skipping + of whitespace inside of a qualified name wasn't consistent. + +Sun May 4 10:48:53 2003 +- Fixed a bug in the expression grammar, which prevented 'not' to be recognized + as a valid operator. +- Qualified names are now supported as parameters to #ifdef and #ifndef too. +- Remove one specialization of the macro expansion engine. It gets instantiated + only twice now (for the main input iterator and for list<>'s of tokens. +- Simplified the required explicit specialization of the defined_grammar + template. It has to be explicitely instantiated by providing the token type + only (just as for the explicit instantiations of the other grammars). + +Fri May 2 22:44:27 2003 +- Qualified names are now allowed as parameters to the operator defined() in + C++0x mode. +- Separated the defined() functionality into a separate translation unit to + work around a VC7.1 ICE. + +Fri May 2 15:38:26 2003 +- The C++0x mode now has a special set of predefined macros. +- The predefined macro __WAVE_HAS_VARIADICS__ is now defined in C99 and C++0x + modes too (--variadics is implied for these modes). +- Updated the documentation to reflect the recent changes and additions. +- In C++0x mode Wave now supports macro scopes: + - new keywords #region/#endregion/#import + - qualified macro names +- In C++0x mode Wave now supports token pasting of unrelated tokens. These are + concatenated, the result is re-tokenized and inserted into the output stream. +- Fixed a minor bug in the macro expansion engine, if a qualified function-like + macro was found in an object-like context. +- Fixed an issue with well defined token pasting of unrelated tokens. + +Tue Apr 29 08:47:37 2003 +- Fixed a bug in the macro expansion engine, which prevented the expansion + of a certain macro under specific conditions (if the left of two tokens to + concatenate were a disabled one (T_NONREPLACABLE_IDENTIFIER), then the + resulting token was disabled too). +- Added additional diagnostics to the Wave driver to disambiguate the C99 and + C++0x modes. +- Implemented a new API function and a corresponding Wave driver command line + option, which allows to specify one or more include files to be preprocessed + before the regular file is preprocessed (the files are processed as normal + input and all the resulting output is included, before processing the regular + input file). The Wave driver command line option is --forceinclude (-F). +- Wave now compiles the Order library from Vesa Karvonen. + +Mon Apr 28 07:57:10 2003 +- Fixed a bug in the macro expansion engine. +- Removed a lot of (not needed) whitespace in the generated output (but still + not optimal). + +Sat Apr 26 20:30:53 2003 +- Fixed a bug in the initialization code of the Slex lexer while working in + C99 mode (reported by Reece Dunn). + +Fri Apr 18 08:37:35 2003 +- Fixed the handling of option_value's inside of pragma directives: + _Pragma("wave option(option_value)") + inside which all all whitespaces were deleted. +- Started to implement experimental macro scoping. + +Thu Apr 10 10:20:07 2003 +- Fixed a problem with the #pragma wave stop(), where only the first token + inside the stop directive was output, when the preprocessor stops in result + of this pragma. +- Implemented a new #pragma wave system(command), which spawns a new operation + system command exactly as specified inside the system directive, intercepts + the stdout output of this process, retokenizes this output and inserts the + generated token sequence in place of the original #pragma or operator _Pragma. + Please note that the generated output is _not_ subject to any macro expansion + before its insertion as the replacement of the pragma itself. If you need to + macro expand the replacement text, you always may force this by writing: + #define SCAN(x) x + SCAN(_Pragma("wave system(...)")) + which re-scans the replacement once. +- Replaced the Wave position_iterator with the boost::spirit::position_iterator + (without any problems!). + +Mon Apr 7 10:45:30 2003 +- Fixed macro_trace_policies::expand_object_like_macro not to be called with + the formal arguments as one of its parameters. +- Updated the documentation to reflect the changes needed for the tracing + stuff. + +Mon Mar 31 19:07:05 2003 +- Fixed variadics support in the trace output. +- Fixed preprocessing of operator _Pragma() before it's execution. +- Added _Pragma("wave stop(errmsg)") (#pragma wave stop(errmsg)) to allow + diagnostics output from inside macro expansion. +- Fixed operator _Pragma for unknown pragmas (these are simply put through to + the output). +- Implemented a maximal possible include nesting depth to avoid an out of + memory error. The initial value for this is configurable through the compile + time constant WAVE_MAX_INCLUDE_LEVEL_DEPTH, which defaults to 1024, if not + given. + Additionally this may be enlarged through a new command line option: + -n/--nesting (Wave driver only). + +Sun Mar 30 20:40:17 2003 +- Implemented the predefined macro __INCLUDE_LEVEL__, which expands to a + decimal integer constant that represents the depth of nesting in include + files. The value of this macro is incremented on every '#include' directive + and decremented at every end of file. +- Implemented the operator _Pragma(). It is recognized in C99 mode and whenever + variadics are enabled. + +Sun Mar 30 08:30:12 2003 +- Changed the tracing format to be more readable. +- Changed the tracing #pragma's to + enable tracing: #pragma wave trace(enable) + disable tracing: #pragma wave trace(disable) + or + enable tracing: #pragma wave trace(1) + disable tracing: #pragma wave trace(0) +- Changed the semantics of the -t (--traceto) switch. Without any -t switch + there isn't generated any trace output at all, even, if the corresponding + #pragma directives are found. To output the trace info to a file, the + '-t file' syntax may be used, to output to std::cerr, the '-t-' (or '-t -') + syntax may be used. + +Fri Mar 28 17:27:25 2003 +- Added a new template parameter to the wave::context<> object, which allows + to specify a policy for controlling the macro expansion tracing. The default + macro_trace_policy does no tracing at all. This way one can add specific + macro expansion tracing facilities to the library. +- #pragma directives starting with a STDC identifier are no longer not macro + expanded in C++ mode, in C++ mode these are now expanded as usual, in C99 + mode not. +- The tracing can be enabled/disabled from inside the preprocessed stream by + inserting a special #pragma directive: + enable tracing: #pragma wave_option(trace: enable) + disable tracing: #pragma wave_option(trace: disable) +- The Wave driver now allows to specify a destination for the macro expansion + tracing trough a new command line switch: '-t path' or '--traceto path'. If + this option isn't given, the trace output goes to stderr. +- The Wave driver now allows to specify the name of the file, where the + preprocessed result stream is to be saved: '-o path' or '--output path'. If + this option is not given, the output goes to stdout. + +Wed Mar 26 20:39:11 2003 +- Fixed a problem with alternative tokens (as 'and', 'or' etc.) and trigraph + tokens, which were not correctly recognized inside #if/#elif expressions. +- Alternative tokens ('and', 'or' etc.) are no longer subject to a possible + macro redefinition. +- Fixed the special handling of 'true' and 'false' during the macro expansion + of #if/#elif expressions. + +Tue Mar 25 12:12:35 2003 +- Released Wave V0.9.1 + +Mon Mar 24 13:34:27 2003 +- Implemented placemarkers, i.e. Wave now supports empty arguments during macro + invocations. This must be enabled by means of a new pp constant: + WAVE_SUPPORT_VARIADICS_PLACEMARKERS which must be defined to enable the + placemarker and variadics code and by defining the command line option + '--variadics' (Wave driver only). +- Implemented variadics, i.e. Wave now supports macros with variable parameter + counts. This must be enabled by means of the pp constant: + WAVE_SUPPORT_VARIADICS_PLACEMARKERS which must be defined to enable the + placemarker and variadics code and by defining the command line option + '--variadics' (Wave driver only). +- Implemented a C99 mode. This mode enables variadics and placemarkers by + default and rejects some specific C++ tokens (as the alternate keywords and + '::', '->*', '.*'). This mode must be enabled by the means of the pp constant + WAVE_SUPPORT_VARIADICS_PLACEMARKERS (see above). The C99 mode is enabled by + the command line switch '--c99' (Wave driver only). + This involved some changes in the C99/C++ lexers. + +Fri Mar 21 16:02:10 2003 +- Fixed a bug in the macro expansion engine, which prevented the expansion of + macros, which name was concatenated out of a identifier and a integer + followed directly by another identifier: + #define X() X_ ## 0R() // note: _zero_ followed by 'R' + #define X_0R() ... + X() // expanded to: X_0R(), but should expand to ... + This is a problem resulting from the fact, that the Standard requires the + preprocessor to act on so called pp-tokens, but Wave acts on C++ tokens. + +Thu Mar 20 21:39:21 2003 +- Fixed a problem with expression parsing (#if/#elif constant expressions), + which failed to produce an error message for expressions like + #if 1 2 3 4 5 + i.e. where the token sequence starts with a valid constant expression, but + the remainder of the line contained other tokens than whitespace. +- Integrated the flex_string class from Andrei Alexandrescu (published on the + CUJ site) to get COW-string behaviour for the token values and position + filename strings. This resulted in a major overall speedup (about 2-3 times + faster in dependency of the complexity of pp usage in the input stream). +- Fixed a bug, which reported ill formed #if/#else expressions as errors, even + if the current if block status (conditional compilation status) is false. +- Added a warning, if the last line of a file does not end with a newline. +- Improved error recognition and handling for malformed preprocessor directives + +Mon Mar 17 19:53:29 2003 +- Fixed a concatenation problem: constructs like a##b##c where expanded + incorrectly. +- Optimized the recognition of pp directives: + - the parser is used only, if the next non-whitespace token starts a pp + directive + - null directives now are recognized without calling the parser + - the parser isn't called anymore, if the if_block_status is false and no + conditional pp directive (#if etc.) is to be recognized. + These optimizations give a speed improvement by upto 40%. +- Removed adjacent whitespace during macro expansion (needs to be revised, + since there is some whitespace left, which may be removed) + +Sun Mar 16 23:19:11 2003 +- Fixed a problem with include pathes given on the command line, if the file + to preprocess was not given as a full path (driver executable). +- Fixed a problem with path names containing blanks (driver executable). +- Cleaned command line and argument handling (driver executable). +- Fixed a severe memory leak. +- Fixed a bug, if a C++ keyword was used as a macro name or macro parameter + name, which prevented the macro recognition and expansion to function + properly. +- Implemented the WAVE_SUPPORT_MS_EXTENSIONS compiler switch for the re2c + generated lexer too. +- Fixed a problem, which caused an internal T_PLACEHOLDER token to show up + outside the macro replacement engine. +- Fixed a problem with macro #include directives, which prevents to find the + file to include, if after the macro expansion the token sequence representing + the filename began or ended with at least one whitespace token. +- Fixed a problem, which caused a false error message if the '#' character was + to be concatenated with an arbitrary other token. +- The concatenation of a whitespace token with an arbitrary other token was + reported as illegal token pasting (but it is certainly not). + +Sat Mar 15 21:43:56 2003 +- Added a default constructor to the wave::util::file_position template. +- Report the concatenation of unrelated tokens as an error. +- Finished the documentation. + +Fri Mar 14 20:14:18 2003 +- More work on documentation +- Changed file_position to expose accessor functions (the member variables are + marked as private now). This opens up the possibility to provide another + file_position implementation, which may be optimized in some way. +- Fixed a problem with the token name table, the alternate and trigraph token + names were printed incorrectly. +- Fixed a bug, which prevented the correct recognition of 'defined X' (without + parenthesises). +- Fixed a bug, which allowed to redefine and undefine the predefined name + 'defined'. +- Fixed a bug, which prevents the correct recognition of a macro based #include + directive, if it expands to something like #include <...>. +- Fixed a bug, which prevented the recognition of duplicate macro parameter + names. +- Removed the insertion of additional whitespace inside of string literals + (during stringizing). + +Wed Mar 12 19:16:40 2003 +- Fixed a bug, which prevented the instantiation of the wave::context object + with auxiliary iterators. The token type isn't coupled anymore with the + iterator type. + This required some changes in the interface: + - The wave::context object now has three template parameters (the iterator + type, the token type and the input policy type) + - The token type does not have the iterator type as it's template parameter + anymore. +- Implemented a new position_iterator template on top of the iterator_adaptor<> + template to make it work even for input_iterator type iterators. +- Fixed a bug in the regular expressions for the Slex lexer. +- The function 'set_sys_include_delimiter()' was renamed to + 'set_sysinclude_delimiter()' to better fit the naming scheme of the other + functions. +- Wrote more documentation +- Unified the different token definitions of the lexers, so that there is only + one token type left. This required some changes in the interface: + - There is no need anymore to explicitly specify the namespace of the token + type to use. +- Added the command line option -P to the Wave driver program, which predefines + a macro (i.e. defines it such, that is _not_ undefinable through an #undef + directive from inside the preprocessed program). + +Sat Mar 8 07:46:43 2003 +- Released Wave 0.9.0 + +Thu Mar 6 20:02:44 2003 +- Compiled Wave with IntelV7.0/DinkumwareSTL (from VC6sp5) +- Fixed new compilation problems with gcc -Wall +- Fixed the list_includes and cpp_tokens samples to compile and link correctly. +- Fixed a bug, where a wrong filename was reported by the generated #line + directive. +- Fixed a bug, where the __FILE__ macro was expanded without '\"' around the + filename. +- The generated #line directives and the expanded __FILE__ macro now report + the filename in a native (to the system) format. Additionally the generated + string literals are now escaped correctly. + +Wed Mar 5 21:11:14 2003 +- Reorganized the directory structure to mirror the namespace structure of the + library +- Fixed a bug, where the complete input after the first found #include + directive were eaten up. +- Fixed a bug, where the __LINE__ macro expanded to a incorrect linenumber, if + the __LINE__ macro was encountered on a line after a '\\' '\n' sequence. + +Tue Mar 4 11:50:24 2003 +- The new name of the project is 'Wave'. +- Adjusted namespaces, comments etc. to reflect the new name. +- Added the command line option -U [--undefine], which allows to remove one of + the predefined macros (except __LINE__, __FILE__, __DATE__, __TIME__, + __STDC__ and __cplusplus) + +Sun Mar 2 20:10:04 2003 +- Fixed a bug while expanding macros without any definition part (empty macros) +- The pp-iterator will not emit a newline for every recognized preprocessing + directive anymore. The generated output is much more condensed this way. +- The pp-iterator now emits #line directives at appropriate places. +- Added an additional parser to the library, which may be used to parse macros + given in the command line syntax, i.e. something like 'MACRO(x)=definition'. +- Added the possibility to the cpp driver sample, to add macros from the + command line through the -D command line switch. +- Martin Wille contributed a test script to allow automatic testing of the + cpp driver sample by feeding all files contained in the test_files directory + through the cpp driver and comparing the generated output with the + corresponding expectations. +- Added config file support to allow for predefined option sets (for instance + for the emulation of other compilers) +- Changed the way, how include pathes are defined. It resembles now the + behaviour of gcc. + Any directories specified with '-I' options before an eventually given '-I-' + option are searched only for the case of '#include "file"', they are not + searched for '#include ' directives. If additional directories are + specified with '-I' options after a '-I-' option was given, these directories + are searched for all '#include' directives. In addition, the '-I-' option + inhibits the use of the current directory as the first search directory for + '#include "file"'. Therefore, the current directory is searched only if it is + requested explicitly with '-I.'. Specifying both '-I-' and '-I.' allows to + control precisely which directories are searched before the current one + and which are searched after. +- Added config file support to the cpp driver. +- stored not only the current 'name' of a file (given eventually by a #line + directive) but in parallel the actual full file system name of this file too. + +Tue Feb 25 21:44:19 2003 +- Fixed the warnings emitted by gcc -Wall. +- Fixed a bug in the cpp grammar, which causes to failing the recognition of + certain preprocessor directives if at the end of this directive were placed + a C++ comment. +- Simplified and extended the insertion of whitespace tokens at places, where + otherwise two adjacent tokens would form a new different token, if + retokenized. + +Mon Feb 24 19:13:46 2003 +- defined() functionality was broken +- added missing typename keywords +- added missing using namespace statements, where appropriate +- added a warning, when a predefined macro is to be undefined (by an #undef + directive) +- removed the 'compile in C mode' hack for the re2c generated lexer (VC7.1 + (final beta) is not able to compile it with optimizations switched on + anyway :( ) +- compiled with gcc 3.2 and Intel V7.0 (20030129Z) + +Sun Feb 23 23:39:33 2003 +- Fixed a couple of 'missing typename' bugs (thanks to Martin Wille) +- Added code to insert whitespace at places, where otherwise two adjacent + tokens would form a new different token, if retokenized. +- Fixed a severe macro expansion bug. +- Added the handling of invalid or not allowed universal character values + inside of string literals and character literals. + +Sat Feb 22 20:52:06 2003 +- Bumped version to 0.9.0 +- Added test for invalid or not allowed universal character values (see + C++ Standard 2.2.2 [lex.charset] and Annex E) +- Fixed a bug with newlines between a macro name and the opening parenthesis + during the macro expansion and a bug with newlines inside the parameter list + during the macro expansion. +- Added the following predefined macros: + __SPIRIT_PP__ + expands to the version number of the pp-iterator lib (i.e. 0x0090 for + V0.9.0) + __SPIRIT_PP_VERSION__ + expands to the full version number of the pp-iterator lib (i.e. + 0x00900436 for V0.9.0.436) + __SPIRIT_PP_VERSION_STR__ + expands to the full version string of the pp-iterator lib (i.e. + "0.9.0.436") + +Fri Feb 21 22:09:04 2003 (feature complete!) +- Allowed to optionally compile the Re2c generated lexer in 'C' mode, because + at least the VC7.1 (final beta) compiler has problems to compile it in 'C++' + mode with optimizations switch on +- Implemented #error and #warning (optional) directives (C++ standard 16.5). + Additionally there are now allowed the following preprocessor configuration + constants: + CPP_PREPROCESS_ERROR_MESSAGE_BODY + if defined, preprocesses the message body of #error and #warning + directives to allow for better diagnostics. + CPP_SUPPORT_WARNING_DIRECTIVE + if defined, then the #warning directive will be recognized such, that + a warning with the given message will be issued +- Adjusted the error handling for the Re2c generated C++ lexer, so that any + error inside the lexer is now propagated as an cpplexer_exception. +- Implemented the #line directive (C++ standard 16.4) +- Implemented #pragma directive (C++ standard 16.6) + Additionally there are now allowed the following preprocessor configuration + constants: + CPP_RETURN_PRAGMA_DIRECTIVES + if defined, then the whole pragma directive is returned as a token + sequence to the caller, if not defined the whole pragma directive is + skipped + CPP_PREPROCESS_PRAGMA_BODY + if defined, then the #pragma body will be preprocessed +- Implemented #include directive with macro arguments (C++ standard 16.2.4) +- Made the namespace structure finer granulated to leave only the main + interface classes in the main namespace cpp. All other classes are moved into + sub-namespaces to reflect the logical dependencies +- Reorganized the public interface of the context<> template class, made all + non relevant functions into the protected. +- Implemented predefined macros (__LINE__ et.al.) (C++ standard 16.8) +- Further documentation work + +Wed Feb 19 23:44:47 2003 +- Corrected a lot of bugs in the macro expansion engine, which now should be + conformant to the C++ standard. +- # (null) directive (C++ standard 16.7) + +Sun Feb 16 08:40:38 2003 +- Added a macro expansion engine which expands macros with arguments + C++ standard 16.3 [cpp.replace] +- Added a new sample: cpp_tokens. This sample preprocesses a given file and + prints out the string representations of all tokens returned from the pp + iterator +- Added documentation (to be continued!) +- Added a couple of small test files to test elementary functionality + (the tests mainly were contributed by Paul Mensonides) +- The main cpp sample is now a simple preprocessor driver program, which + outputs the string representation of the preprocessed input stream. Use + cpp --help to get a hint, how to use it. +- Fixed a bug in the preprocessor grammar which failed to recognize a pp + statement, if there was a C++ comment at the end of the line +- Added '#' operator (C++ standard 16.3.2) [cpp.stringize] +- Fixed a bug in the slex based C++ lexer to handle the concatenation + characters correctly ('\\' followed by a '\n') + +Sun Feb 9 23:01:00 2003 +- Improved error handling for #if et.al. +- Fixed a pair of lexer errors +- Implemented the #if/#elif statements, the sample now contains a complete C++ + expression evaluation engine (for the calculation of the outcome of the + #if/#elif statement conditions) +- Implemented macro replacement (with parameters) +- Implemented the '##' [cpp.concat] operator +- Implemented the defined() [cpp.cond] operator + +Sun Feb 2 23:28:24 2003 +- Implemented the #define, #undef, #ifdef, #ifndef, #else and #endif + statements +- Added optional parse tree output as xml stream (controlled through the config + pp constant CPP_DUMP_PARSE_TREE) + +Fri Jan 31 21:30:55 2003 +- Fixed different minor issues and a border case (#include statement at the + last line of a included file) + +Wed Jan 29 21:13:32 2003 +- Fixed exception handling to report the correct error position +- Fixed another bug in the stream position calculation scheme +- Added a more elaborate sample 'list_includes' which lists the dependency + information for a given source file (see test/list_includes/readme.txt). + +Sat Jan 18 22:01:03 2003 +- Fixed a bug in the stream position calculation scheme +- Made cpp::exceptions more standard conformant (added 'throw()' at appropriate + places) +- Overall housekeeping :-) + +Wed Jan 15 21:54:20 2003 +Changes since project start (still 0.5.0) +- Added #include <...> and #include "..." functionality +- pp directives are now generally recognized +- Decoupled the C++ lexers and the pp grammar to separate compilation + units (optionally) to speed up compilation (a lot!) + +Thu Jan 2 12:39:30 2003 +A completely new version 0.5.0 of the C preprocessor was started. It's a +complete rewrite of the existing code base. The main differences are: +- The preprocessor is now implemented as an iterator, which returns the + current preprocessed token from the input stream. +- The preprocessing of include files isn't implemented through recursion + anymore. This follows directly from the first change. As a result of this + change the internal error handling is simplified. +- The C preprocessor iterator itself is feeded by a new unified C++ lexer + iterator. BTW, this C++ lexer iterator could be used standalone and is not + tied to the C preprocessor. There are two different C++ lexers implemented + now, which are functionally completely identical. These expose a similar + interface, so the C preprocessor could be used with both of them. +- The C++ lexers integrated into the C preprocessor by now are: + Slex: A spirit based table driven regular expression lexer (the slex + engine originally was written by Dan Nuffer and is available as a + separate Spirit sample). + Re2c: A C++ lexer generated with the help of the re2c tool. This C++ + lexer was written as a sample by Dan Nuffer too. + It isn't hard to plug in additional different C++ lexers. There are plans to + integrate a third one written by Juan Carlos Arevalo-Baeza, which is + available as a Spirit sample. + +------------------------------------------------------------------------------- +Tue Feb 12 22:29:50 2002 +Changes from 0.2.3 to 0.2.4: +- Moved XML dumping functions to the main Spirit directory +- Fixed operator '##', it was not correctly implemented somehow :-( + +Sun Feb 10 21:07:19 2002 +Changes from 0.2.2 to 0.2.3: +- Implemented concatenation operator '##' (cpp.concat) +- Removed defined() functionality for Intel compiler (it ICE's) until this + issue is resolved +- Separated code for dumping a parse tree to XML for inclusion in the main + Spirit headers + +Thu Jan 17 23:51:21 2002 +Changes from 0.2.1 to 0.2.2: +- Fixes to compile with gcc 2.95.2 and gcc 3.0.2 (thanks Dan Nuffer) +- Reformatted the grammars to conform to a single formatting guideline +- Assigned explicit rule_id's to the rules of cpp_grammar, so that the + access code to the embedded definition class is not needed anymore +- Fixed a remaining const problem + +Tue Jan 15 23:40:40 2002 +Changes from 0.2.0 to 0.2.1: +- Corrected handling of defined() operator +- In preprocessing conditionals undefined identifiers now correctly + replaced by '0' +- Fixed several const problems +- Added parse_node_iterator for traversing one node in a parse_tree + without going deeper down the hierarchy than one level (this is useful, + if all inspected tokens arranged along a single node in the parse tree. + The main difference to the parse_tree_iterator is, that the underlying + iterator generally can be adjusted correctly after advancing the attached + parse_node_iterator +- Fixed a problem with gcc 2.95.2, which doesn't have a header +- Prepared usage of slex for lexer states + +Sun Jan 13 10:21:16 2002 +Changes from 0.1.0 to 0.2.0: +- Added operator 'defined()' +- Added directive '#warning' +- Corrected error reporting +- Added command line option -I- for finer control of the searched include + directories (-I and -I- should now work as in gcc, see readme.html for + more info) +- Corrected conditional preprocessing (should be fully functional now) +- Fixed existing code base for changes made in parse tree support +- Moved parse tree utility functions to a separate header (prepared for + inclusion to the Spirit main library) diff --git a/build/Jamfile b/build/Jamfile new file mode 100644 index 000000000..03726b9d7 --- /dev/null +++ b/build/Jamfile @@ -0,0 +1,64 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Build Jamfile +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +subproject libs/wave/build ; + +SOURCES = instantiate_cpp_exprgrammar + instantiate_cpp_grammar + instantiate_cpp_literalgrammars + instantiate_defined_grammar + instantiate_predef_macros + instantiate_re2c_lexer + instantiate_re2c_lexer_string + cpplexer/re2clex/aq + cpplexer/re2clex/cpp.re + ; + +lib boost_wave + : ../src/$(SOURCES).cpp + : # build requirements + [ common-names ] # magic for install and auto-link features + $(BOOST_ROOT) + $(BOOST_ROOT) + <*>off # workaround for compiler bug + cpp.re.cpp + : debug release # build variants + ; + +#dll boost_wave +# : ../src/$(SOURCES).cpp +# : # build requirements +# [ common-names ] # magic for install and auto-link features +# BOOST_WAVE_DYN_LINK=1 # tell source we're building dll's +# dynamic # build only for dynamic runtimes +# $(BOOST_ROOT) +# $(BOOST_ROOT) +# : debug release # build variants +# ; + +install wave lib + : boost_wave +# boost_wave + ; + +stage stage/lib : boost_wave # boost_wave + : + # copy to a path rooted at BOOST_ROOT: + $(BOOST_ROOT) + # make sure the names of the libraries are correctly named: + [ common-names ] + # add this target to the "stage" and "all" pseudo-targets: + stage + all + : + debug release + ; + +# end diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 new file mode 100644 index 000000000..47d1a5e28 --- /dev/null +++ b/build/Jamfile.v2 @@ -0,0 +1,33 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Build Jamfile +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +project boost/wave + : source-location ../src + ; + +SOURCES = instantiate_cpp_exprgrammar + instantiate_cpp_grammar + instantiate_cpp_literalgrammars + instantiate_defined_grammar + instantiate_predef_macros + instantiate_re2c_lexer + instantiate_re2c_lexer_string + cpplexer/re2clex/aq + cpplexer/re2clex/cpp.re + ; + +lib boost_wave + : $(SOURCES).cpp + $(BOOST_ROOT)/libs/filesystem/build//boost_filesystem + : + msvc-7.1:off # workaround for compiler bug + # Not supported by V2 + # cpp.re.cpp + ; diff --git a/doc/acknowledgements.html b/doc/acknowledgements.html new file mode 100644 index 000000000..153b52d6e --- /dev/null +++ b/doc/acknowledgements.html @@ -0,0 +1,86 @@ + + + +Acknowledgements + + + + + + + + + + +

Acknowledgements
+
+ + + + + + + +
+

Special thanks to:

+
+

Paul Mensonides for his invaluable help while developing the macro + expansion engine and his insightful tips. He developed the recursive macro + expansion algorithm implemented herein and also contributed most of the small + testcases used for testing the correctness of the macro expansion.

+

Dan Nuffer, who wrote the initial Re2C based C++ lexer and the Slex + (Spirit Lex) scanner generator sample.

+

Martin Wille for helping with the port to Linux, testing on Linux and for contributing + the automated test scripts.

+

Vladimir Prus for helping with the command line and config file options + analysis fro the Wave driver executable.

+

Juan Carlos Arevalo-Baeza, who wrote the Spirit cpp_lexer sample, + from which are taken some ideas.

+

Andrei Alexandrescu for allowing to use his flex_string class, +a policy based std::basic_string<> compatible string implementation.

+

Reece Dunn, Vesa Karvonen, Faisal Vali, Porter Schermerhorn and Daniel Fontijne for + reporting several problems and bugs.

+

Tarmo Pikaro for reporting several bug while compiling specific + headers from the Microsoft Windows SDK.

+

Rob Stewart helped a lot with proof reading the documentation.

+
+

and last but not least

+
+

Joel de Guzman for nudging me into this adventure and for his work + on the Spirit parser framework, without which the Wave library + wouldn't have been possible.

+
+

The Wave library uses the following Boost [8] + libraries:

+
+

 Boost + Spirit (LL parser framework that represents parsers directly as EBNF grammars + in inlined C++)
+ Boost + Iterator Adaptor Library (Adapt a base type into a standard conforming iterator)
+ Boost + Filesystem Library (Portable paths, iteration over directories, and other + useful filesystem operations)
+  Boost Program + options and arguments library

+
+

and other small parts of different Boost libraries.

+ + + + + + + +
+
+ +Last updated: + Monday, January 17, 2005 16:39 + + + diff --git a/doc/class_reference_context.html b/doc/class_reference_context.html new file mode 100644 index 000000000..5365a9385 --- /dev/null +++ b/doc/class_reference_context.html @@ -0,0 +1,441 @@ + + + + The Context Object + + + + + + + + + + +

The + Context Object
+
+ + + + + + + +
+
+

Introduction
+ Header 'wave/context.hpp' synopsis
+ Public Typedefs
+ Template parameters
+ Member functions

+
+

Introduction

+

The boost::wave::context<> object is the main user visible object of + the Wave library. It exists to generate the pair of iterators, which + while dereferenced return the preprocessed tokens. Additionally it is used + to control other aspects of the preprocessing, such as

+
+

 include + search pathes, 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 several extensions + to the C++ Standard (as for instance variadics and placemarkers) or not.

+
+

Header wave/cpp_context.hpp + synopsis

+
namespace boost {
+namespace wave { 
+    
+    template <
+        typename IteratorT, typename LexIteratorT, 
+        typename InputPolicyT, typename TracePolicyT 
+    > 
+    class context : public InputPolicyT 
+    {
+    public: 
+
+        typedef pp_iterator<context> iterator_type; 
+        typedef TokenT token_type;
+        typedef typename token_type::position_type position_type;
+
+    // constructor
+        context(IteratorT const &first_, 
+            IteratorT const &last_, 
+            char const *fname = "<Unknown>",
+            TracePolicyT &trace = TracePolicyT())
+
+    // iterator interface
+        iterator_type begin() const;
+        iterator_type end() const;
+
+    // maintain include paths
+        bool add_include_path(char const *path_);
+        bool add_sysinclude_path(char const *path_);
+        void set_sysinclude_delimiter();
+  
+        size_t get_iteration_depth() const;
+
+    // maintain defined macros
+        bool add_macro_definition(std::string macrostring, 
+            bool is_predefined = false);
+        bool is_defined_macro(std::string const &name) const;
+        bool remove_macro_definition(std::string const &name, 
+            bool even_predefined = false);
+        void reset_macro_definitions();
+
+    // other options
+        void set_language(language_support enable);
+        language_support get_language() const;
+ void set_max_include_nesting_depth(size_t new_depth);
size_t get_max_include_nesting_depth() const;
+ // get the Wave version information + static std::string get_version(); + static std::string get_version_string(); + }; + +} // namespace wave +} // namespace boost
+

Template parameters

+

The boost::wave::context object has three template parameters to specify + the concrete behaviour of its operation. The following table describes these + with more detail.

+ + + + + + + + + + + + + + + + + + + + +
Template parameters required for the + boost::wave::context class
IteratorT

The type of the underlying iterator, + through which the input stream is accessed.
+ This should be at least an forward_iterator type iterator.

LexIteratorT

The type of the lexer type to be used by the Wave + library to identify tokens in the input stream.

InputPolicyT

The type of the input policy class, which allows + to customize the behaviour of the Wave library and the type of the iterators + to use, when it comes to including and opening an included file.

TracePolicyT

The type of the trace policy class, which allows + to customize the trace output generated while expanding macros.

+

For further information about the lexer type to use, please refer to the The + Lexer Interface .

+

If the template parameter InputPolicyT is omitted, the template wave::iteration_context_policies::load_file_to_string + is used. For further information about the input policy, please refer to the + topic The Input Policy.

+

If the template parameter TracePolicyT is omitted, the wave::macro_trace_policies::no_tracing + policy type is used, i.e. by default there is no tracing performed. For further + information about the tracing policy, please refer to the topic The + Tracing Policy.

+

Public Typedefs

+

The boost::wave::context template defines the following public typedefs, which may be useful while using this class:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Public typedef's defined by the boost::wave::context class
iterator_type

The IteratorT template parameter provided, while the context class was instantiated.

lex_type

The LexIteratorT template parameter provided, while the context class was instantiated.

token_type

The token type, which is returned by the context generated iterators. This type is taken from the LexIteratorT template parameter provided, whicle the context class was instantiated.

input_policy_type

The InputPolicyT template parameter provided, while the context class was instantiated.

trace_policy_type

The TracePolicyT template parameter provided, while the context class was instantiated.

position_type

The type of the position information contained in every returned token, which describes the point, at which the given token was recognised.

+

Member functions

+

Constructor

+
    context(IteratorT const &first, 
+        IteratorT const &last, 
+        char const *filename,
+        TracePolicyT &trace);
+
+

Constructs a context object on top of the input stream given by the pair + of auxilliary iterators [first, last). The iterators should + be at least forward_iterator type iterators. The filename parameter + is to be supplied for informational purposes only. This string is used for + indicating the token positions inside the input stream, it is not validated + against the file system. If the filename parameter is not given it defaults + to "<Unknown>". If the trace + parameter isn't supplied it defaults to a default constructed TracePolicyT + object.

+

Additionally the macro symbol table is filled with the predefined macros + and the current reference directory is set to the path of the given filename. + If this filename does not reference valid file system item, the current reference + directory is set to the current system directory. (The current reference directory + is the file system path, which is used as the target directory during the + processing of #include "..." directives),

+
+

Iterator interface

+

The pair of iterators returned by the context::begin and context::end + functions is the main interface for accessing the preprocessed tokens from the + preprocessor engine. While iterating over the given iterator range [begin, end) + there are returned the preprocessed C++ tokens, which are generated on the fly + from the underlying input stream. The returned iterators are conceptually of + forward_iterator type.

+

begin

+
    iterator_type begin();
+
+

Initializes and returns the starting iterator for the preprocessed token + stream.

+ +
+

end

+
    iterator_type end() const;
+
+

Initializes and returns the end of stream iterator to compare with for detecting + the end of the preprocessed token stream.

+
+

Maintain include paths

+

The Wave library maintains two separate search pathes for include + files. A search path for user include files and a search path for system include + files. Any directories specified with the add_include_path() + function before the function set_sysinclude_delimiter() + is called are searched only for the case of #include "..." + directives, they are not searched for #include <file> directives. + I.e. these directories are added to the user include search path.

+

If additional directories are specified with the add_include_path() + function after a call to the function set_sysinclude_delimiter(), + these directories are searched for all #include directives. I.e. these + directories are added to the system include search path.

+

In addition, a call to the function set_sysinclude_delimiter() + inhibits the use of the current reference directory as the first search directory + for #include "..." directives. Therefore, the current + reference directory is searched only, if it is requested explicitly with a call + to the function add_include_path("."). +

+

Callig both functions, the set_sysinclude_delimiter() + and add_include_path(".") allows you + to control precisely, which directories are searched before the current one + and which are searched after.

+

These functions are modelled after the command line behaviour implemented by + the popular gcc compiler.
+

+

add_include_path

+
    bool add_include_path(char const *path);
+
+
+

Adds the given file system path to the user include search paths. After a + call to the set_sysinclude_delimiter() + this function adds the given file system path to the system include search + paths. Note though, that the given path is validated against the file system. +

+

If the given path string does not form a name of a valid file system directory + item, the function returns false. If the given path was successfully + added to the include search paths in question, the function returns true.

+
+

add_sysinclude_path

+
    bool add_sysinclude_path(char const *path);
+
+

Adds the given file system path to the system include search paths. This + function operates on the system include search path regardless of the mode + of operation of the add_include_path(). Note + though, that the given path is validated against the file system.

+

If the given path string does not form a name of a valid file system directory + item, the function returns false. If the given path was successfully + added to the system include search paths, the function returns true.

+
+

set_sysinclude_delimiter

+
    void set_sysinclude_delimiter();
+
+

Switches the mode, how the add_include_path() + function operates. By default the given file system path is added to the user + include search paths. After calling this function a subsequent call to the + add_include_path() adds the given file system + path to the system include search paths. Additionally it inhibits the the + use of the current reference directory as the first search directory for #include "..." + directives.

+
+

get_iteration_depth

+
    size_t get_iteration_depth() const;
+
+

Returns the actual include iteration depth, i.e. the current number of include + levels to be poped from the include iteration context, before the main (topmost) + iteration context is reached.

+
+

Maintain defined macros

+

add_macro_definition

+
    bool add_macro_definition(
+        std::string macrostring, 
+        bool is_predefined); 
+
+
+

Adds a new macro definition to the macro symbol table. The parameter macrostring + should contain the macro to define in the command line format, i.e. something + like MACRO(x)=definition. The following table describes this format + in more detail. The parameter is_predefined should be true while + defining predefined macros, i.e. macros, which are not undefinable with an + #undef directive from inside the preprocessed input stream. If this + parameter is not given, it defaults to false.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Summary of possible formats for defining + macros
MACROdefine MACRO as 1
MACRO=define MACRO as nothing (empty)
MACRO=definitiondefine MACRO as definition
MACRO(x)define MACRO(x) as 1
MACRO(x)=define MACRO(x) as nothing (empty)
MACRO(x)=definitiondefine MACRO(x) as definition
+

The function returns false, if the macro to define already was defined + and the new definition is equivalent to the existing one, it returns true, + if the new macro was successfully added to the macro symbol table.

+

If the given macro definition resembles a redefinition and the new macro + is not identical to the already defined macro (in the sense defined by the + C++ Standard), the function throws a corresponding preprocess_exception.

+
+

is_defined_macro

+
    bool is_defined_macro(std::string const &name) const; 
+
+

Returns, if a macro with the given name is defined, i.e. if it is + contained in the macro symbol table.

+
+

remove_macro_definition

+
    bool remove_macro_definition(
+        std::string const &name, 
+        bool even_predefined); 
+
+

Removes the definition of the macro with the given name from the + macro symbol table. This operation is equivalent to an #undef directive + with this name executed from within the input stream. If the parameter + even_predefined is true, then the macro is removed from + the macro symbol table even, if it is defined as a predefined macro.

+

Note though, that the following macros are not undefinable in any + case: __FILE__, __LINE__, __DATE__, __TIME__, + __cplusplus, __STDC__. If the parameter even_predefined + is not given, it defaults to false.

+

The function returns false, if the macro to undefine was not defined + and returns true otherwise.

+

If the macro to remove may not be undefined (it is a predefined macro and + the parameter even_predefined is set to false or it is one + of the mentioned not undefinable macros above) the function throws a preprocess_exception.

+
+

reset_macro_definitions

+
    void reset_macro_definitions(); 
+
+

Resets the macro symbol table to it's initial state, i.e. undefines all user + defined macros and inserts the internal predefined macros as described here.

+
+

Get Version information

+

get_version

+
    static std::string get_version(); 
+
+

Returns a string containing the current Wave version formatted as 0xvvrsbbbb + (this is a string representation of the equivalent hexadecimal number), where + 'vv' is the version number, 'r' + the release number, 's' the subrelease number + and 'bbbb' the build number. A possible return + value looks like 0x00910454. The returned value + is the same as is inserted in the preprocessed token stream, when the predefined + macro __WAVE_VERSION__ is expanded.

+
+

get_version_str

+
    static std::string get_version_str(); 
+
+

Returns a string containing the current Wave version formatted as "v.rr.ss.bbbb", + where 'v' is the version number, 'rr' + the release number, 'ss' the subrelease number + and 'bbbb' the build number. A possible return + value looks like "0.9.1.454". The returned + value is the same as is inserted in the preprocessed token stream, when the + predefined macro __WAVE_VERSION_STR__ is expanded.

+
+

Control extended options

+

set_language
+ get_language

+
    void set_language(language_support language);
+    language_support get_language() const;
+
+

This functions allow to specify the language mode, in which the Wave + library should work. The possible language modes are defined by the enumerated + type language_support:

+
    enum language_support {
+    // support flags for C++98
+        support_normal = 0x01,
+        support_cpp = support_normal,
+    
+    // support flags for C99
+        support_variadics = 0x02,
+        support_c99 = support_variadics,
+    };
+

When used with support_variadics the support for variadics, placemarkers + and the operator _Pragma() is enabled in normal C++ mode. The support_c99 + switch to the C99 language support.

+
+

set_max_include_nesting_depth
+ g et_max_include_nesting_depth

+
    void set_max_include_nesting_depth(size_t new_depth); 
+    size_t get_max_include_nesting_depth() const;
+
+

This functions allow to set or to get the maximal possible include file nesting + depth supported by the Wave library. The initial value for this is + determined by the preprocessing constant WAVE_MAX_INCLUDE_LEVEL_DEPTH + (see here).

+
+ + + + + + + +
+
+ + + +

 

+ + diff --git a/doc/class_reference_contextpolicy.html b/doc/class_reference_contextpolicy.html new file mode 100644 index 000000000..1cea60636 --- /dev/null +++ b/doc/class_reference_contextpolicy.html @@ -0,0 +1,263 @@ + + + +The Context Policy + + + + + + + + + + + +

The + Context Policy
+
+ + + + + + + +
+
+

Introduction
+ Header 'wave/preprocessing_hooks.hpp' + synopsis
+ Member functions

+
+

Introduction

+

The context policy is used to provide callback hooks, which are called from inside the library into the user code, whenever

+
    +
  • a macro get's defined or undefind,
  • +
  • a macro is expanded or rescanned,
  • +
  • an include file is opened or left,
  • +
  • a pragma of the form 'wave option[(value)]' is recognised.
  • +
+

This policy type is used as a template parameter to the wave::context<> + object, where the default policy provides empty hooks functions only.

+

Header wave/preprocessing_hooks.hpp + synopsis

+
+namespace boost {
+namespace wave {
+namespace context_policies {
+ 
+    struct default_preprocessing_hooks {
+
+        // general control function
+        template <typename TokenT, typename ContainerT>
+        void expanding_function_like_macro(TokenT const &macrodef, 
+            std::vector<TokenT> const &formal_args, 
+            ContainerT const &definition, TokenT const &macrocall, 
+            std::vector<ContainerT> const &arguments);
+ 
+        template <typename TokenT, typename ContainerT>
+        void expanding_object_like_macro(TokenT const &macro, 
+            ContainerT const &definition, TokenT const &macrocall);
+ 
+        template <typename ContainerT>
+        void expanded_macro(ContainerT const &result);
+ 
+        template <typename ContainerT>
+        void rescanned_macro(ContainerT const &result);
+
+        // include file tracing functions
+        void opened_include_file(std::string const &filename, 
+            std::size_t include_depth, bool is_system_include); 
+
+        void returning_from_include_file();
+
+        // interpretation of #pragma's of the form 
+        // 'wave option[(value)]'
+        template <typename ContextT, typename ContainerT>
+		bool interpret_pragma(ContextT const &ctx, ContainerT &pending, 
+            typename ContextT::token_type const &option, 
+            ContainerT const &values, 
+            typename ContextT::token_type const &pragma_token);
+
+        // macro definition hooks
+        template <
+            typename TokenT, typename ParametersT, typename DefinitionT
+        >
+        void defined_macro(TokenT const &name, bool is_functionlike,
+            ParametersT const &parameters, DefinitionT const &definition,
+            bool is_predefined);
+
+        template <typename StringT>
+        void undefined_macro(StringT const &name);
+    };
+
+}}}   // namespace boost::wave::context_policies
+

Member functions

+

Macro expansion tracking functions

+

expanding_function_like_macro

+
    template <typename TokenT, typename ContainerT>
+    void expanding_function_like_macro(TokenT const &macrodef, 
+        std::vector<TokenT> const &formal_args, 
+        ContainerT const &definition, TokenT const &macrocall, 
+        std::vector<ContainerT> const &arguments);
+
+

The function expanding_function_like_macro is called, whenever a + function-like macro is to be expanded, i.e. before the actual expansion + starts.

+

The macroname parameter marks the position where the macro to expand + is defined. It contains the token which identifies the macro name used inside + the corresponding macro definition.

+

The formal_args parameter holds the formal arguments used during + the definition of the macro.

+

The definition parameter holds the macro definition for the macro + to trace. This is a standard STL container which holds the token sequence + identified during the macro definition as the macro replacement list.

+

The macrocall parameter marks the position where this macro is invoked. + It contains the token, which identifies the macro call inside the preprocessed + input stream.

+

The arguments parameter holds the macro arguments used during the + invocation of the macro. This is a vector of standard STL containers which + contain the token sequences identified at the position of the macro call as + the arguments to be used during the macro expansion.

+
+

expanding_object_like_macro

+
    template <typename TokenT, typename ContainerT>
+    void expanding_object_like_macro(TokenT const &macro, 
+        ContainerT const &definition, TokenT const &macrocall);
+
+
+

The function expanding_object_like_macro is called, whenever a object-like + macro is to be expanded, i.e. before the actual expansion starts.

+

The macroname parameter marks the position where the macro to expand + is defined. It contains the token which identifies the macro name used inside + the corresponding macro definition.

+

The definition parameter holds the macro definition for the macro + to trace. This is a standard STL container which holds the token sequence + identified during the macro definition as the macro replacement list.

+

The macrocall parameter marks the position where this macro is invoked. + It contains the token which identifies the macro call inside the preprocessed + input stream.

+
+

expanded_macro

+
    template <typename ContainerT>
+    void expanded_macro(ContainerT const &result);
+
+
+

The function expanded_macro is called whenever the expansion of + a macro is finished, the replacement list is completely scanned and the identified + macros herein are replaced by its corresponding expansion results, but before + the rescanning process starts.

+

The parameter result contains the the result of the macro expansion + so far. This is a standard STL container containing the generated token sequence.

+
+

rescanned_macro

+
    template <typename ContainerT>
+    void rescanned_macro(ContainerT const &result);
+
+
+

The function rescanned_macro is called whenever the rescanning + of a macro is finished, i.e. the macro expansion is complete.

+

The parameter result contains the the result of the whole macro + expansion. This is a standard STL container containing the generated token + sequence.

+
+

Include file tracing functions

+

opened_include_file

+
    void opened_include_file(std::string const &filename, 
+        std::size_t include_depth, bool is_system_include);
+
+
+

The function opened_include_file is called whenever a file referred + by an #include directive was successfully located and opened.

+

The parameter filename contains the full file system path of the + opened file.

+

The include_depth parameter contains the current include file depth. +

+

The is_system_include parameter denotes, if the given file was found + as a result of a #include <...> directive.

+
+

returning_from_include_file

+
    void returning_from_include_file();
+
+
+

The function returning_from_include_file is called whenever an + included file is about to be closed after it's processing is complete.

+
+

Interpretation of #pragma's

+

interpret_pragma

+
    template <typename Context, typename ContainerT>
+    bool interpret_pragma(ContextT const &ctx, ContainerT &pending, 
+        typename ContextT::token_type const &option, 
+        ContainerT const &values, 
+        typename ContextT::token_type const &pragma_token);
+
+
+

The function interpret_pragma is called whenever an unrecognized + #pragma wave ... or operator _Pragma("wave ...") + is found in the input stream.

+

The ctx parameter provides a reference to the context_type used during instantiation of the preprocessing iterators by the user.

+

The pending parameter may be used to push tokens back into the input + stream which are to be used as the replacement text for the whole #pragma wave() + directive. If this sequence is left empty, no replacement takes place, i.e. + the interpreted directive is removed from the generated token stream.

+

The option parameter contains the name of the interpreted pragma.

+

The values parameter holds the value of the parameter provided to + the pragma operator.

+

The pragma_token parameter contains the actual #pragma token which + may be used for extraction of the location information for some error output.

+

If the return value is 'false', the whole #pragma directive is interpreted + as unknown and a corresponding error message is issued. A return value of + 'true' signs a successful interpretation of the given #pragma.
+

+
+

Macro definition

+

defined_macro

+
    template <
+        typename TokenT, typename ParametersT, typename DefinitionT
+    >
+    void defined_macro(TokenT const &name, bool is_functionlike,
+        ParametersT const &parameters, DefinitionT const &definition,
+        bool is_predefined);
+
+

The function defined_macro is called whenever a macro was defined successfully.

+

The parameter name is a reference to the token holding the macro name.

+

The parameter is_functionlike is set to true whenever the newly + defined macro is defined as a function like macro.

+

The parameter parameters holds the parameter tokens for the macro + definition. If the macro has no parameters or if it is a object like + macro, then this container is empty.

+

The parameter definition contains the token sequence given as the + replacement sequence (definition part) of the newly defined macro.

+

The parameter is_predefined is set to true for all macros predefined + during the initialisation pahase of the library.
+

+
+

undefined_macro

+
    template <typename StringT>
+    void undefined_macro(StringT const &name);
+
+
+

The function undefined_macro is called whenever a macro definition + was removed successfully.

+

The parameter name holds the name of the macro which definition was removed.
+

+
+ + + + + + + +
+
+ + + + + diff --git a/doc/class_reference_fileposition.html b/doc/class_reference_fileposition.html new file mode 100644 index 000000000..c27a789f4 --- /dev/null +++ b/doc/class_reference_fileposition.html @@ -0,0 +1,119 @@ + + + +The File Position + + + + + + + + + + + +

The + File Position
+
+ + + + + + + +
+
+

Introduction
+ Header 'wave/util/file_position.hpp' + synopsis
+ Template parameters
+ Member functions

+
+

Introduction

+

The file position template is used to represent a concrete token position inside + the underlying input stream. This token position contains the corresponding + filename, the line number and the column number, where the token was recognized.

+

Header wave/util/file_position.hpp + synopsis

+
namespace boost {
+namespace wave {
+namespace util {
+
+    template <typename StringT = std::string>
+    class file_position {
+ 
+    public:
+        file_position();
+        explicit file_position(StringT const &file, 
+            int line_ = 1, int column_ = 1);
+
+    // accessors
+        StringT const &get_file() const;
+        int get_line() const;
+        int get_column() const;
+    
+        void set_file(StringT const &file);
+        void set_line(int line);
+        void set_column(int column);
+    };
+
+}   // namespace util
+}   // namespace wave
+}   // namespace boost
+

Template parameters

+

The file_position template may be instantiatet with one template parameter, + which gives the string type to use for storing the file name member of the file + position. If this parameter isn't given, it defaults to a std::string. + Please note, that the type given as the template parameter must be compatible + with a std::string.

+

Member functions

+

Constructors

+
        file_position();
+        explicit file_position(StringT const &file, 
+            int line_ = 1, int column_ = 1);
+
+
+

The constructors initialize a new instance of a file_position in + correspondence to the supplied parameters. The parameters default to an empty + filename and the line number and column number set to one.

+
+

get_file, get_line, get_column

+
        StringT const &get_file() const;
+        int get_line() const;
+        int get_column() const;
+
+
+

The get_... functions are used to access the current values of the + file position members: the filename (get_file), the line number (get_line) + and the column number (get_column).

+
+

set_file, set_line, set_column

+
        void set_file(StringT const &file);
+        void set_line(int line);
+        void set_column(int column);
+
+
+

The set_... functions are used to set new values to the file position + members: the filename (set_file), the line number (set_line) + and the column number (set_column).

+
+ + + + + + + +
+
+ + + + + diff --git a/doc/class_reference_inputpolicy.html b/doc/class_reference_inputpolicy.html new file mode 100644 index 000000000..ffafb543f --- /dev/null +++ b/doc/class_reference_inputpolicy.html @@ -0,0 +1,132 @@ + + + +The Input Policy + + + + + + + + + + + +

The + Input Policy
+
+ + + + + + + +
+ +
+

Introduction
+ Header 'wave/cpp_iteration_context.hpp' + synopsis
+ Template parameters
+ Member functions

+
+

Introduction

+

The input policy type may be specified as a template parameter to the wave::context + object and is used for customizing the way, how an included file is to be represented + by a pair of iterators pointing to the beginning and the end of the resulting + input sequence. If this template parameter is not given while instantiating + the context object, it defaults to the iteration_context_policies::load_file_to_string + type.

+

Header wave/iteration_context.hpp + synopsis

+

The following code listing does not show the required interface only, but for + brevity reasons the whole implementation of an input policy, which loads the + given file into a string variable and exposes the begin() and end() iterators + of this string to the Wave library.

+
namespace boost {
+namespace wave {
+namespace iteration_context_policies {
+
+    struct load_file_to_string {
+    
+        template <typename IterContextT>
+        class inner {
+        
+        public:
+            // expose the begin and end iterators for the
+            // included file
+            template <typename PositionT>
+            static 
+            void init_iterators(IterContextT &iter_ctx, 
+                PositionT const &act_pos)
+            {
+                typedef typename IterContextT::iterator_type iterator_type;
+                
+                std::ifstream instream(iter_ctx.filename.c_str());
+                if (!instream.is_open()) {
+                    CPP_THROW(preprocess_exception, bad_include_file, 
+                        iter_ctx.filename, act_pos);
+                }
+                
+                iter_ctx.instring = std::string(
+                    std::istreambuf_iterator(instream.rdbuf()),
+                    std::istreambuf_iterator());
+
+                iter_ctx.first = iterator_type(iter_ctx.instring.begin(), 
+                    iter_ctx.instring.end(), 
+                    PositionT(iter_ctx.filename));
+                iter_ctx.last = iterator_type();
+            }
+
+        private:
+            std::string instring;
+        };
+    };
+
+}   // namespace iteration_context_policies
+}   // namespace wave 
+}   // namespace boost   
+

As you can see, an input_policy for the wave::context object + should implement one function only, the init_iterators function. The policy + shown is implemented with the help of an embedded class to avoid the need for + template template parameters, which aren't implemented by all systems today. + This embedded class should have the name inner.

+

Template Parameters

+

The inner class is instantiated with one template parameter, the iteration + context type, from which the policy is a part of. The iterator type iterator_type + which is used to access the underlying input stream has to be derived through + a typedef as shown. The iterator pair to initialize (which is accessible as + iter_ctx.first and iter_ctx.last) has to initialized from + an abritrary iterator type, representing the actual input stream.

+

Member Functions

+

init_iterators

+
    template <typename PositionT>
+    static void init_iterators(
+        IterContextT iter_ctx, 
+        PositionT const &act_pos);
+ +

directive was found in the input token stream. The main rationale for this + function is to initialize the pair of iterators iter_ctx.first and + iter_ctx.last, which are to be used to access the input stream corresponding + to the include file to be inserted from inside the preprocessing engine.

+ + + + + + + + +
+
+ + + + + diff --git a/doc/class_reference_lexer.html b/doc/class_reference_lexer.html new file mode 100644 index 000000000..a44d34e1a --- /dev/null +++ b/doc/class_reference_lexer.html @@ -0,0 +1,104 @@ + + + +The Lexer Interface + + + + + + + + + + + +

The + Lexer Iterator Interface
+
+ + + + + + + +
+
+

Introduction
+ Wave Lexer + synopsis
+ Public Typedefs
+ Member functions

+
+

Introduction

+

Every lexer, which should be used in conjunction with the Wave library, has to return tokens formed from the input stream. These tokens should conform to the synopsis described in the topic The Token Type. The lexer type should expose an interface which conforms at least to a forward_iterator (in the sense defined by the the C++ Standard) returning the token type. The code sample below does not show the definition of this forward iterator interface because this is highly implementation defined.

+

Wave lexer + synopsis (header: wave/cpplexer/cpp_lexer_interface.hpp)

+
    struct lex_iterator
+    {
+        typedef boost::wave::lex_token<> token_type;
+
+    // Every lex_iterator should implement at least a complete 
+    // forward_iterator interface (not shown here)
+        typedef std::forward_iterator_tag iterator_category;
+
+    // additional requirements
+        lex_iterator();
+
+        template <typename IteratorT>
+        lex_iterator(IteratorT const &first, IteratorT const &last
+            typename token_type::position_type const &pos, 
+            boost::wave::language_support language)
+    };
+
+
+

Please note, that the lex_iterator defined in the library header wave/cpplexer/cpp_lexer_interface.hpp actually is a template class taking the token type to use as its template parameter. This is omitted in the synopsis above because it is an implementation detail of the Re2C lexer provided as part of the Wave library.

+

If you want to use Wave in conjunction with your own lexing component this will have to conform to the interface described above only.

+

Public Typedefs

+

Besides the typedefs mandated for a forward_iterator by the C++ standard every lexer to be used with the Wave library should define the following typedefs:

+ + + + + + + + +
Public typedef's defined by the boost::wave::context class
token_type

The token type returned by the lexer. This is type is used as the return value of the main iterators provided by the boost::wave:.context object too.

+

Member functions

+

Besides the functions, which should be provided for forward_iterators as mandated by the C++ Standard, every lexer must implement the following functions to be used with the Wave library:

+

constructor

+
    lex_iterator();
+
+

The default constructor should construct a lexer iterator, which may be used as the end iterator of the provided iterator range.

+
+
+    template <typename IteratorT>
+    lex_iterator(IteratorT const &first, IteratorT const &last,
+        typename token_type::position_type const &pos, 
+        boost::wave::language_support language);
+
+

The second constructor should construct a lexer iterator, which may be used as a iterator traversing over the token sequence, generated by the lexer class.

+

The pair of iterators first and last should represent the input stream to be tokenized by the given lexer class.

+

The parameter pos contains the initial position information to be used for token generation.

+

The parameter language controls the reuqired mode with which the lexer should be initialised.

+
+ + + + + + + +
+
+ + + + + diff --git a/doc/class_reference_tokentype.html b/doc/class_reference_tokentype.html new file mode 100644 index 000000000..1c28bf8f5 --- /dev/null +++ b/doc/class_reference_tokentype.html @@ -0,0 +1,176 @@ + + + +The Token Type + + + + + + + + + + +

The + Token Type
+
+ + + + + + + +
+
+

Introduction
+ Header 'wave/context.hpp' + synopsis
+ Template parameters
+ Member functions

+
+

Introduction

+

The token type in Wave is the main carrier of information. It is returned + by dereferencing the iterators exposed by the lexing component and the iterator exposed by the preprocessor component. The tokens are originally generated by the + lexer ("An entity that lexically transforms the subject of parsing to a + sequence of objects (called tokens) more suitable for subsequent parsing."). + The Wave library contains two different, interchangable C++ lexers, which may + be used as a starting point during developing your own application. The lexer + generated tokens are transformed by the preprocessing engine (macro expansion, + include file processing etc.) and after this returned to the user of the Wave + library.

+

You can use arbitrary token types in conjunction with your own lexer as long + as these implement some required interface. The required token type interface + is described below and is implemented by the wave::cpplexer::lex_token + template, the required lexer interface is described here. +

+

In the following is described the token type predefined inside the Wave + library, which is used in conjunction with the two predefined C++ lexers contained + in the Wave library too. If you need to use your own token type, it + is required to implement the interafce described below.

+

Header wave/cpplexer/cpp_lex_token.hpp + synopsis

+
namespace boost {
+namespace wave {
+namespace cpplexer {
+
+    template <typename PositionT>
+    class lex_token 
+    {
+    public:
+        typedef std::basic_string<char> string_type;
+        typedef PositionT               position_type;
+    
+        lex_token();
+        lex_token(token_id id, string_type const &value, 
+            PositionT const &pos);
+
+    // accessors
+        operator token_id() const;
+        string_type const &get_value() const;
+        position_type const &get_position() const;
+        void set_token_id (token_id id);
+        void set_value (string_type const &newval);
+        void set_position (position_type const &pos);
+    };
+
+}   // namespace cpplexer
+}   // namespace wave
+}   // namespace boost
+
+

Template parameters

+

The predefined token type uses a template parameter PositionT, which + allows to specify the type to be used to carry the file position information + contained inside the generated tokens. This type should contain at least the + filename, the line number and the column number of the position, where the token + was recognized. It defaults to a simple file_position template class described + here.

+

Member functions

+

Constructors

+
    lex_token();
+
+    lex_token(token_id id, 
+        string_t const &value, 
+        PositionT const &pos);
+
+

The first (default) constructor is for generating an end of stream token, + which is used for indicating the end of the underlying input stream.

+

The second constructor initializes the newly created token object with its + token id (for a list of valid token id's please look here), + the string representation of its value and the file position, describing the + position inside the input stream , where this token was recognized.

+
+

Accessor functions

+

operator token_id

+
    operator token_id() const;
+
+

Allows the access to the token id of the token. This access function is implemented + as an implicit conversion function to allow the operation of Spirit + parsers directly on top + + + top of a token stream. The possible token id's are described + + here.

+

This function does not throw in any case.

+
+

get_value

+
    string_t const &get_value() const;
+
+

Returns the value of the token, as it was recognized in the input stream. + Even for constant tokens (as keywords or operators etc.) the returned value + reflects the character sequence as found in the input stream.

+

This function does not throw in any case.

+
+

get_position

+
    PositionT const &get_position() const;
+
+

Returns the position of the token in the input stream, where it was recognized. + The position contains information about the filename, the line number and + the column number of the token. By default the Wave library uses + a file_position template for this purpose, which is described in more detail + here.

+

This function does not throw in any case.

+
+

set_token_id

+
    void set_token_id(token_id id);
+
+

Changes the token id of the token to the new value. The possible token id's + are described here. Propably this function is + of little value for the library user, but it is required under certain circumstances + for correct operation of the preprocessing engine.

+

This function does not throw in any case.

+
+

set_value

+
    void set_value(string_t const &newval);
+
+

Changes the value stored inside the token to the new value. Propably this + function is of little value for the library user, but it is required under + certain circumstances for correct operation of the preprocessing engine.

+
+

set_position

+
    void set_position(PositionT const &newpos);
+
+

Changes the position stored inside the token to the new value. This is used + for instance for implementing the functionality required for to implement + the #line directive.

+
+ + + + + + + +
+
+ + + + + diff --git a/doc/compiletime_config.html b/doc/compiletime_config.html new file mode 100644 index 000000000..a9c8f5a5b --- /dev/null +++ b/doc/compiletime_config.html @@ -0,0 +1,203 @@ + + + +Compile Time Configuration + + + + + + + + + + + +

Compile + Time Configuration
+
+ + + + + + + +
+

Library compile time configuration

+

The C++ preprocessor iterator library may be configured at compile + time by specifying different preprocessor constants to include different additional + features. The possible preprocessor constants are described in the following + table.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Summary of possible preprocessor constants + for
+ library configuration
BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE

Support the #warning directive

BOOST_WAVE_SUPPORT_MS_EXTENSIONS

Support several MS specific language + extensions (i.e. __int8 et.al.)

BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY

Enable the preprocessing of the message bodies + of #error and #warning + directives.

BOOST_WAVE_RETURN_PRAGMA_DIRECTIVES

If defined, then the #pragma + directives are returned as a token sequence to the caller, if not defined, + the whole #pragma directive is skipped.

BOOST_WAVE_PREPROCESS_PRAGMA_BODY

Enable the preprocessing of the bodies of + #pragma directives.
+ Note though, that the body of an operator _Pragma() is preprocessed + always, as required by the C99 Standard [2]. +

BOOST_WAVE_ENABLE_COMMANDLINE_MACROS

Enable the functionality required to define macros + with the command line syntax (-DMACRO(x)=definition)

BOOST_WAVE_STRINGTYPE

The tokens generated by the Wave library + contain the token data and the file position, where this token was found + in the input stream.
+ This constant may be used to redefine the data type, which is used to + hold the token data and the corresponding file name. If this isn't defined + it defaults to std::string. (The here defined data type should be compatible + to the std::string type)

BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS

If defined, then the preprocessor library supports + variadics and placemarkers. Note, to support C99 mode, this constant must + be defined too.

BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH

If defined, it will determine the initial maximal + possible include file nesting depth supported. It defaults to 1024.

BOOST_WAVE_SUPPORT_PRAGMA_ONCE

If defined, then the #pragma once directive is supported by Wave. This specifies that the file, in which the pragma resides, will be included + (opened) only once by the compiler in a build.

BOOST_WAVE_SUPPORT_INCLUDE_NEXT

If defined, then the #include_next directive is supported by Wave. This is syntactically equivalent to the #include directives, but may be used to inherit a header file (i.e. to include a file, which is named as the current file containing the #include_next).

+

Using a different token type or lexer type in conjunction with Wave

+

It is possible to use the Wave library while using your own token and/or lexer types. This may be achieved by providing your lexer type as the second template parameter while instantiating the boost::wave::context<> object. The token type used by the library is derived from the token_type typedef to be provided by the lexer type. If you want to provide your own token type only, you may use the boost::wave::lex_iterator<> type contained with the library. This type needs to be parametrized with the token type to use.

+

To show, how this may be done, the Wave library contains several samples illustrating this possibility. The cpp_tokens sample shows the usage of a custom lexer and a custom token types. The lexer type used is functionally fully compatible to the re2c [3] based lexer used by default. It is implemented based on the SLex [5] lexer example written by Dan Nuffer. The used theiring token type is functionally equivalent to the default token type except for an additional operator<< used for dumping the information carried bz the token.

+

Separation and inclusion compilation + models

+

The Wave C++ preprocessor iterator library is build almost + completely as a header only library (except for the re2c based lexer). If you're + trying to include all required files at once you will mention, that the resulting + compilation times are very large (up to an hour - depending on your system configuration). + This straightforward method we'll call the inclusion compilation model. If you + do not pay attention to compilation times, that's the way to go, no special + handling is needed.

+

If you're interested in decreasing compilation times, the following + method is to be used. This we will call it the separation compilation model. + The trick is to separate the different objects such, that they are compilable + separately. The function, which instantiates the templated object in question + is factored out such, that its definition is visible to only one translation + unit. To simplify this further this creation function is packaged into a small + generator template structure.

+

There are two levels of separation implemented: the separation of + the compilation of the C++ lexer and the separation of the compilation of the + different Spirit grammars used. To use these separations you will have to define + two preprocessor constants while compiling the whole application and you will + have to explicitely instantiate some helper templates. The following tables + shows these constants in detail.

+ + + + + + + + + + + + + + + + +
Summary of possible compilation constants + required
+ to enable the separation compilation model
Separate

Preprocessor + constant

C++ lexer

BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION

Spirit grammars

BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION

+

The following table shows the explicit template instantiations required, + if you want to use the separation compilation model. The TokenT placeholder + type has to be replaced with your token type to use and the LexIteratorT placeholder type has to be replaced with your lex iterator type you've used while instantiation of the boost::wave::context<> object. You will achieve the best + results, if you place these into separate compilation units each. The IteratorT + placeholder should be replaced by the iterator type, which was used to instantiate + the boost::wave::context<> object.

+ + + + + + + + + + + + + + + + +
Summary of required explicit template + instantiations
+ required when using the separation compilation model
Separate

Templates + to explicitly instantiate

C++ lexer template + cpplexer::re2clex::new_lexer_gen<IteratorT>;
Spirit grammars

template wave::grammars::expression_grammar_gen<TokenT>;
+ template wave::grammars::intlit_grammar_gen<TokenT>;
+ template wave::grammars::chlit_grammar_gen<TokenT>;
+ template wave::grammars::cpp_grammar_gen<LexIteratorT>;
+
template
wave::grammars::predefined_macros_grammar_gen<LexIteratorT>;
+ template wave::grammars::defined_grammar_gen<LexIteratorT>;

+

To see an example of this you can look at the Wave driver program + included as an acompanion sample to the C++ preprocessor iterator library. The + corresponding files are named obviously "instantiate_...something.cpp", + where the '...somthing' is a hint, which grammars + are explicitely instantiated inside. By using the separation model the compilation + times required to build the Wave example are dropped by up to 90%.

+ + + + + + + +
+
+ + + + + diff --git a/doc/introduction.html b/doc/introduction.html new file mode 100644 index 000000000..b87d037b3 --- /dev/null +++ b/doc/introduction.html @@ -0,0 +1,93 @@ + + + +Introduction + + + + + + + + + + + +

Introduction
+
+ + + + + + + +
+

The Wave C++ preprocessor library is a Standards conformant + implementation of the mandated C99/C++ preprocessor functionality packed behind + a simple to use interface, which integrates well with the well known idioms + of the Standard Template Library (STL).

+

The Wave C++ preprocessor is not a monolitic 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 + the 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 fed by a C++ lexer iterator, + which implements an abstract interface. The C++ lexers packaged with the + Wave library may be used standalone, too, and are not tied to the C++ + preprocessor iterator at all.

+

To make the C++ preprocessing library modular, the C++ lexer is held + completely separate and independent from the preprocessor. To prove this concept, + two different, but functionally identical C++ lexers were +implemented. Additionally there is implemented a IDL lexer, which allows to use the preprocessor library as the lexing component of a IDL oriented tool. All these lexers implement the mentioned abstract interface, + so that the C++ preprocessor iterator may be used with all of them. The abstraction + of the lexer from the preprocessor iterator library was done to allow + plugging in different lexers without the need to reimplement the preprocessor. + This will allow for benchmarking and specific fine tuning of the process of preprocessing + itself.

+

The first of these C++ lexers is implemented with the help of the + well known Re2C [3] tool, which generates + C code from given regular expressions. The lexers generated with Re2C + are known to be very fast, because they are not table driven but directly code the token building logic +(very similar to hand coded lexers). +

+

The second of these C++ lexers is built around a table driven lexer, + where the DFA tables (discrete finite automaton tables) are generated from regular expressions with the help of + a Spirit-based lexer generating framework named Slex [5]. + The Slex is fed during runtime with the token definitions (regular + expressions) and generates the resulting DFA table. This table is used to combine + the input characters into corresponding lexemes (tokens). The generated DFA table + can be saved to disk to avoid the generation process at program startup.

+

Wave may be used for preprocessing IDL files too, since the token set needed for the IDL language is very similar to the C++ token set. That's the reason, why the Wave preprocessor library contains also an IDL lexer. The IDL lexer is also based on the Re2C tool, but recognizes a different set of tokens. So this lexer does not recognize any keywords (except true and false, which are needed by the preprocessor itself). This is needed because there exist different IDL language flavours, where identifiers of one flavour may be keywords of others - Ok, this requires postponement of keyword identification until after the +preprocessing, but allows to use Wave for all of the IDL derivatives.

+

It is possible to build other C++ lexers if needed. Currently there + are plans to adapt the Spirit C++ lexer example cpplexer [6], + which is completely based on static Spirit[4] + grammars.

+

Both of the included lexers and the library itself are able + to act in a C99 compliant mode. In this mode the lexers reject C++-only tokens + ('::', '->*', '.*' and the alternate keywords + such as 'and', etc.). The preprocessor additionally handles placemarkers + (empty macro arguments) and variadics (macros with variable parameter counts). + As an extension to the C++ Standard, the library can be enabled to handle placemarkers + and variadics in C++ mode too.

+ + + + + + + +
+
+ + + + + diff --git a/doc/macro_expansion_process.html b/doc/macro_expansion_process.html new file mode 100644 index 000000000..695188ff7 --- /dev/null +++ b/doc/macro_expansion_process.html @@ -0,0 +1,101 @@ + + + +The Macro Expansion Process + + + + + + + + + + + +

The + Macro Expansion Process
+
+ + + + + + + +
+

The macro expansion process described here was initially developed by Paul + Mensonides and is implemented in Wave. It is much more understandable + as the description of the desired macro expansion algorithm provided in the + C++ Standard [1].

+

Macro replacement proceeds left-to-right.

+

If, during scanning (or rescanning) an identifier is found, it is looked up + in the symbol table. If the identifier is not found in the symbol table, it + is not a macro and scanning continues.

+

If the identifier is found, the value of a flag associated with the identifier + is used to determine if the identifier is available for expansion. If it is + not, the specific token (i.e. the specific instance of the identifier) is marked + as disabled and is not expanded. If the identifier is available for expansion, + the value of a different flag associated with the identifier in the symbol table + is used to determine if the identifier is an object-like or function-like macro. + If it is an object-like macro, it is expanded. If it is a function-like macro, + it is only expanded if the next token is an left parenthesis.
+ An identifier is available for expansion if it is not marked as disabled and + if the the value of the flag associated with the identifier is not set, which + is used to determine if the identifier is available for expansion.

+

(If a macro is an object-like macro, skip past the next two paragraphs.)

+

If a macro to be expanded is a function-like macro, it must have the exact + number of actual arguments as the number of formal parameters required by the + definition of the macro. Each argument is recursively scanned and expanded. + Each parameter name found in the replacement list is replaced by the expanded + actual argument after leading and trailing whitespace and all placeholder tokens + are removed unless the parameter name immediately follows the stringizing operator + ('#') or is adjacent to the token-pasting operator ('##').

+

If the parameter name immediately follows the stringizing operator ('#'), + a stringized version of the unexpanded actual argument is inserted. If the parameter + name is adjacent to the token-pasting operator ('##'), the unexpanded + actual argument is inserted after all placeholder tokens are removed.

+

All concatenation takes place in the replacement list. (If a single concatenation + yields multiple tokens, the behavior is undefined. Moreover, Wave in + normal C++98 and C99 modes issues an error, if more then one token is produced + as the result of the concatenation. In C++0x mode Wave treats token-pasting + of unrelated tokens as well defined and inserts the reparsed string representation + of the concatenated tokens into the replacement list.).

+

The flag in the symbol table entry associated with the name of the macro being + expanded is set to indicate the that the macro is not available for expansion.

+

The replacement list is rescanned for further macro expansion. All leading + and trailing whitespace tokens in the replacement list are removed (the placeholder + tokens are left intact).

+

After rescanning completes, the flag in the symbol table entry associated with + the name of macro being expanded is cleared to indicate that the macro is again + available for expansion, and the sequence of tokens that constitutes the rescanned + replacement list is returned to the point of invocation of the macro.

+

If this sequence of tokens is empty, it is replaced by a placeholder token. + If a placeholder is found during scanning (or rescanning) it is ignored. (Also, + if the only thing separating a parameter from the stringizing operator or token-pasting + operator is placeholder, it is also ignored in that context.)

+

This sequence of tokens is inserted at the original point that the macro was + invoked, and scanning continues starting with the last token of the newly inserted + sequence of tokens. I.e. scanning looks back a single token (possibly a placeholder + token) and continues.
+

+ + + + + + + +
+
+ + + +

 

+ + diff --git a/doc/predefined_macros.html b/doc/predefined_macros.html new file mode 100644 index 000000000..dcc89fd6a --- /dev/null +++ b/doc/predefined_macros.html @@ -0,0 +1,154 @@ + + + +Predefined Macros + + + + + + + + + + + +

Predefined + Macros
+
+ + + + + + + +
+

The following table lists the macros, which are predefined by the + Wave library. Some of these (all except the __LINE__, + __FILE__, __BASE_FILE__, __DATE__, + __TIME__, __STDC__, __INCLUDE_LEVEL__ + and __cplusplus macros) may be undefined from the command line of the driver executable + (see the -U option) or through the function remove_macro_definition().

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Summary of predefined macros
Name

Value

Undefinable
__STDC__

1 (a decimal constant)

yes

__cplusplus

199711L (a decimal constant), this + is defined in C++ mode only (C99 mode is off)
+ In the C++0x mode this decimal constant is guaranteed to be larger than + 199711L (the concrete value is to be defined by the C++ committee).

no

__LINE__

The line number of the current source line (a decimal + constant)

no

__FILE__

The presumed name of the source file (a character string literal)

no

__BASE_FILE__

This macro expands to the name of the main input file (a character string literal). This is the source file that was specified during construction of the wave::context template.

no

__DATE__

The date of translation of the source file (a character + string literal of the form
+ "Mmm dd yyyy", where the names of the months are the same as + those generated by the asctime function, and the first character of dd + is a space character if the value is less than 10).

no

__TIME__

The time of translation of the source file (a character + string literal of the form "hh:mm:ss"
+ as in the time generated by the asctime function).

no

__INCLUDE_LEVEL__

A decimal integer constant that represents the + depth of nesting in include
+ files. The value of this macro is incremented on every #include + directive
+ and decremented at every end of file.

no

__WAVE__
__SPIRIT_PP__

The version of the driver program (a hexadecinal + constant of the form 0xMmrr, where 'M' is + the major version number, 'm' the minor version + number and 'rr' the release number).

yes

__WAVE_VERSION__
__SPIRIT_PP_VERSION__

The full version number of the driver program (a + hexadecimal constant of the form 0xMmrrbbbb, where 'M' + is the major version number, 'm' the minor + version number, 'rr' the release number and + 'bbbb' the build number).

yes

__WAVE_VERSION_STR__
__SPIRIT_PP_VERSION_STR__

The full version number of the driver program (a + character string literal of the form "M.m.rr.bbbb", + where 'M' is the major version number, 'm' + the minor version number, 'rr' the release + number and 'bbbb' the build number).

yes

__STDC_VERSION__

199901L (a decimal constant), this is defined in + C99 mode only

yes

__WAVE_HAS_VARIADICS__

1 (a decimal constant), this is defined in C++ + mode only, if variadics and placemarkers are enabled, further it is defined + in the C99 mode

no

+
+ + + + + + + +
+
+ + + + + diff --git a/doc/preface.html b/doc/preface.html new file mode 100644 index 000000000..29950b765 --- /dev/null +++ b/doc/preface.html @@ -0,0 +1,110 @@ + + + +Preface + + + + + + + + + + + +

Preface
+
+ + + + + + + +
+

During the last time many new features were developed as additions to the Spirit + [4] parser construction framework and we + felt more and more, that it would be very helpful, to have a 'real world' example, + which could be used as a sandbox for testing the usability of certain features. + Additionally a recent discussion on the Boost mailing list showed the widespread + interest of developers to have a modern, open source C++ preprocessor library + to play with.  So we had the idea to implement a C++ preprocessor to fit + this needs - Wave was born.

+

The Wave C++ preprocessor library uses the + Spirit[4] parser construction + library to implement a C++ lexer with ISO/ANSI Standards conformant preprocessing + capabilities. It exposes an iterator interface, which returns the current preprocessed + token from the input stream. This preprocessed token is generated on the fly + while iterating over the preprocessor iterator sequence (in the terminology + of the STL these iterators are forward iterators).

+

The C++ preprocessor is a macro processor that under normal + circumstances is used automatically by your C++ compiler to transform your program + before 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 [7] + 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 bugfree 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 standardese dialect of English used to describe it.

+

So the main goals for the Wave project are:

+
+

 full + conformance with the C++ standard (ISO/IEC 14882:1998) [1] + and with the C99 standard (INCITS/ISO/IEC 9899:1999) [2]
+  usage of Spirit[4] + for the parsing parts of the game (certainly :-)
+  maximal usage + of STL and/or Boost libraries (for compactness and maintainability)
+  straightforward + extendability for the implementation of additional features
+  building a + flexible library for different C++ lexing and preprocessing needs

+
+

At the first steps it is not planned to make a very high performance or very + small C++ preprocessor. If you are looking for these objectives you probably + have to look at other places. Although our C++ preprocessor iterator works as expected and is usable as a reference implementation, for instance + for testing of other preprocessor oriented libraries as the Boost Preprocessor + library [7] et.al. Nevertheless recent work has lead to surprising performance enhancements (if compared + with earlier versions). Wave is still somewhat slower as for instance EDG + based preprocessors (Intel, Comeau) on simple input files, however, as + complexity increases, time dilates expontentially on EDG. Preprocessing time + dilates linearly under Wave, which causes it to easily outperform EDG based +preprocessors when complexity increases.

+

As tests showed, the Wave library is very conformant to the C++ Standard, + such that it compiles several strict conformant macro definitions, which are + not even compilable with EDG based preprocessors (i.e. Comeau or Intel). The only preprocessor known to have similar Standards conformance +today is the preprocessor of the gcc C/C++ compiler.

+ + + + + + + +
+
+ + + + + diff --git a/doc/quickstart.html b/doc/quickstart.html new file mode 100644 index 000000000..eb1fb82f9 --- /dev/null +++ b/doc/quickstart.html @@ -0,0 +1,121 @@ + + + +Quick Start + + + + + + + + + + + +

Quick + Start
+
+ + + + + + + +
+

Preprocessing with Wave is highly configurable. You must +define a few options to control it. Here are a few of the +options you can define:

+
+

 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
+  whether to enable any of several extensions to the C++ +Standard (such as for variadics and placemarkers)
+

+
+

You can access all these processing parameters through the boost::wave::context + object. So you must instantiate one object of this type to use the Wave + library. (For more information about the context template class, please refer + to the class reference here.) To instantiate + the boost::wave::context object you have to supply at least two template parameters: + the iterator type of the underlying input stream to use and the type of the lexer iterator to be used as the token source for the preprocessing engine.

+

Do not instantiate the main preprocessing iterators yourself. +Get them from the wave::context object instead.
+The following code snippet is taken from the quick_start sample, which shows a minimal usage scenario for Wave.

+
    // The following preprocesses a given input file.
+    // 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 boost::wave::cpplexer::lex_token<> is the  
+    // 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 some 
+    // of the public classes and templates and it is returned 
+    // from the iterators.
+    // The template boost::wave::cpplexer::lex_iterator<> is
+    // the lexer iterator to use as the token source for the
+    // preprocessing engine. In this case this is parametrized
+    // with the token type.
+    typedef boost::wave::cpplexer::lex_iterator<
+            boost::wave::cpplexer::lex_token<> >
+        lex_iterator_type;
+    typedef boost::wave::context<
+            std::string::iterator, lex_iterator_type>
+        context_type;
+
+    context_type ctx(input.begin(), input.end(), "input.cpp");
+
+    // At this point you may want to set the parameters of the
+    // preprocessing as include pathes and/or predefined macros.
+        ctx.add_include_path("...");
+        ctx.add_macro_definition(...);
+
+    // Get the preprocessor iterators and use them to generate 
+    // the token sequence.
+    context_type::iterator_type first = ctx.begin();
+    context_type::iterator_type last = ctx.end();
+
+    // The input stream is preprocessed for you during iteration
// over [first, last)
while (first != last) { + std::cout << (*first).get_value(); + ++first; + } + +
+

The constructor of the boost::wave::context object can + take a pair of arbitrary iterator types (at least input_iterator type + iterators) to the input stream, which must supply the data to be processed. + The third parameter supplies a filename, filename, which is reported in the preprocessor output to +indicate the current context. +Note though, that this filename is used + only as long as no #include or #line directives are encountered, + which in turn will alter the current filename reported.

+

The iteration over the preprocessed tokens is relativley straightforward. Just get the starting and the ending iterators from the context object + (maybe after initializing some include search paths) and you are done! Dereferencing + the iterator will return the preprocessed tokens, which are generated on + the fly from the input stream. (To get further information about the token type, + you may want to look here.)

+ + + + + + + +
+
+ + + + + diff --git a/doc/references.html b/doc/references.html new file mode 100644 index 000000000..ba0cd6064 --- /dev/null +++ b/doc/references.html @@ -0,0 +1,100 @@ + + + +References + + + + + + + + + + + +

References
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1. ISO/IEC "Programming + languages - C++"
+ ISO/IEC 14882:1998
2. INCITS/ISO/IEC "Programming + languages - C"
+ INCITS/ISO/IEC 9899:1999
3. Peter Bumbulis and
+ Donald D. Cowan
Re2c + V0.9.1
+ A tool for generating C-based recognizers from regular expressions
4.Joel de Guzman et.al.Spirit v1.8.2 + documentation
5.Daniel C. NufferThe + Spirit Slex example
6.Juan Carlos Arevalo-BaezaThe + Spirit cpplexer example
7.Vesa Karvonen and
+ Paul Mensonides
The + Boost Library Preprocessor Subset for C/C++
8.boost.orgThe Boost Libraries + Documentation.
+
+ + + + + + + +
+
+ + + + + diff --git a/doc/samples.html b/doc/samples.html new file mode 100644 index 000000000..914b5d284 --- /dev/null +++ b/doc/samples.html @@ -0,0 +1,94 @@ + + + +Samples + + + + + + + + + + + +
+

Samples
+
+ + + + + + + +
+

The Wave library contains several samples illustrating how to use the different features. This section describes these samples and its main characteristics.

+

The quick_start sample

+

The quick_start sample shows a minimal way to use the Wave preprocessor library. It simply opens the file given as the first command line argument, preprocesses it assuming that there aren't any additional include pathes or macros defined and outputs the textual representation of the tokens generated from the given input file. This sample may be used to introduce yourself to Wave, because it does not contain all the potential additional complexity exposed by more complex samples.

+

The cpp_tokens sample

+

The cpp_tokens sample dumps out the information contained within the tokens returned from the iterator supplied by the Wave library. It shows, how to use the Wave library in conjunction with custom lexer and custom token types. The lexer used within this sample is SLex [5] based, i.e. it is feeded during runtime (at startup) with the token definitions (regular expressions) and generates a resulting DFA table. This table is used for token identification and is saved to disc afterwards to avoid the table generation process at the next program startup. The name of the file to which the DFA table is saved is wave_slex_lexer.dfa.

+

The main advantage of this SLex based lexer if compared to the default Re2C [3] generated lexer is, that it provides not only the line information, where a particular token was recognized, but also the related column position. Otherwise the SLex based lexer is functionally fully compatible to the Re2C based one, i.e. you always may switch your application to use it, if you additionally need to get the column information back from the preprocessing.

+

Since no additional command line parameters are supported by this sample, it won't work well with include files, which aren't located in the same directory as the inspected input file. The command line syntax is straight forward:

+
    cpp_tokens input_file
+

The list_includes sample

+

The list_includes sample shows how the Wave library may be used to generate a include file dependency list for a particular input file. It completely depends on the default library configuration. The command line syntax for this sample is given below:

+
    Usage: list_includes [options] file ...:
+        -h [ --help ]        : print out program usage (this message)
+        -v [ --version ]     : print the version number
+        -I [ --path ] dir    : specify additional include directory
+        -S [ --syspath ] dir : specify additional system include directory
+
+

Please note though, that this sample will output only those include file names, which are visible to the preprocessor, i.e. given the following code snippet, only one of the two include file directives is triggered during preprocessing and for this reason only the corresponding file name is reported by the list_includes sample: +

    #if defined(INCLUDE_FILE_A)
+    #  include "file_a.h" 
+    #else
+    #  include "file_b.h"
+    #endif
+

The wave sample

+

Because of its general usefulness the wave sample is not located in the sample directory of the library, but inside the tools directory of Boost. The wave sample is usable as a full fledged preprocessor executable + on top of any other C++ compiler. It outputs the textual representation of the +preprocessed tokens generated from a given input file. It is described in more details here.

+

The waveidl sample

+

The main point of the waveidl sample is to show, how a completely independent lexer type may be used in conjunction with the default token type of the Wave library. The lexer used in this sample is supposed to be used for an IDL language based preprocessor. It is based on the Re2C tool too, but recognizes a different set of tokens as the default C++ lexer contained within the Wave library. So this lexer does not recognize any keywords (except true and false, which are needed by the preprocessor itself). This is needed because there exist different IDL languages, where identifiers of one language may be keywords of others. Certainly this implies to postpone keyword identification after the preprocessing, but allows to use Wave for all of the IDL derivatives.

+

It is only possible to use the Wave library to write an IDL preprocessor, because the token sets for both languages are very similar. The tokens to be recognized by the waveidl IDL language preprocessor is nearly a complete subset of the full C++ token set.

+

The command line syntax usable for this sample is shown below:

+
  Usage: waveidl [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
+      -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
+
+ + + + + + + +
+
+ + + +

 

+ + diff --git a/doc/supported_pragmas.html b/doc/supported_pragmas.html new file mode 100644 index 000000000..90336cefe --- /dev/null +++ b/doc/supported_pragmas.html @@ -0,0 +1,128 @@ + + + +Supported Pragma Directives + + + + + + + + + + + +

Supported + Pragma Directives
+
+ + + + + + + +
+

The Wave preprocessor library supports a couple of specific #pragma + directives, which may be used to control some of the library features. All directives + described here are usable as conventional #pragma directives and as + operator _Pragma (if variadics are enabled). So for instance the + following directives are functionally identical:

+
    #pragma wave trace(enable)  
+

and

+
    _Pragma("wave trace(enable)")
+

All Wave specific pragma's must have the general form 'wave option[(value)]', + where 'wave' is the specific keyword, 'option' is the concrete + pragma functionality to trigger and 'value' is an optional value to + be supplied to the 'option' functionality. The following table lists + all possible pragma functions supported by the Wave library. For all recognised pragmas of this general form the interpret_pragma hook function from inside the context_policies are call, so that the user of the library is responsible for

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Supported pragma's

pragma option

pragma value

description

supported by

trace

enable/on/1
+ disable/off/0

Enable or disable the tracing of the + macro expansion process. This is needed, even if there is given the --trace + command line option, because the trace output is generated only, if there + is at least one trace(enable) pragma found.

Wave driver

stop

message

Stop the execution of Wave and print out + the given message. This is very helpful for direct debugging purposes.

Wave driver

system

command

Try to spawn the 'command' as a new operating system + command and intercept the generated stdout and stderr. The stdout output + of this command (if any) is retokenized and used as the replacement text + for the whole pragma, the stderr output is ignored. The command is considered + to be successful, if/when the return value is zero, otherwise an error + is reported.
+

Wave driver

timer

restart/0
+ <no value>
+ suspend
+ resume

The value restart set the current elapsed + time to 0 and restarts the timer.
+ If no value is provided, the current elpsed time is printed to the std::cerr + stream.
+ The values suspend and resume allow to temporarily stop + the timing.

Wave driver

+

All pragma's not listed here but flagged as 'wave' are reported as + errors. The handling of all remaining pragma's depends on the compilation constant + WAVE_RETURN_PRAGMA_DIRECTIVES, which allows to specify, + if those pragmas are left unchanged in the output stream or not. Please note, + that the operator _Pragma variant is always subject to full preprocessing, before + the pragma itself is evaluated. The #pragma variant is subject to preprocessing + only, if the WAVE_PREPROCESS_PRAGMA_BODY compilation constant + was specified during compilation. For more information about the possible compilation + constants look here.

+

Additionally the Wave preprocessor supports the #pragma once directive, + which specifies that the file, in which the pragma resides, will be included + (opened) only once by the compiler in a build. This may be used to optimize + the preprocessing of larger compilation units, which include a lot of files. Note though, that the #pragma once directive is supported only, if the compile time constant WAVE_SUPPORT_PRAGMA_ONCE was given during compilation of the library.

+

It is fairly easy to implement your own #pragma wave ... directives. All you have to do is to implement your own interpret_pragma function (see here) which should the handle additional directives. For an example of how to do it, you may have a look at the Wave driver application, which implements the #pragma wave timer() directive with the help of a supplied interpret_pragma function.

+ + + + + + + +
+
+ + + +

 

+ + diff --git a/doc/theme/bkd.gif b/doc/theme/bkd.gif new file mode 100644 index 000000000..dcabcb806 Binary files /dev/null and b/doc/theme/bkd.gif differ diff --git a/doc/theme/bkd2.gif b/doc/theme/bkd2.gif new file mode 100644 index 000000000..b03d9ba97 Binary files /dev/null and b/doc/theme/bkd2.gif differ diff --git a/doc/theme/bullet.gif b/doc/theme/bullet.gif new file mode 100644 index 000000000..da787e2ef Binary files /dev/null and b/doc/theme/bullet.gif differ diff --git a/doc/theme/l_arr.gif b/doc/theme/l_arr.gif new file mode 100644 index 000000000..5b3cb1cbf Binary files /dev/null and b/doc/theme/l_arr.gif differ diff --git a/doc/theme/l_arr_disabled.gif b/doc/theme/l_arr_disabled.gif new file mode 100644 index 000000000..ed58a605a Binary files /dev/null and b/doc/theme/l_arr_disabled.gif differ diff --git a/doc/theme/r_arr.gif b/doc/theme/r_arr.gif new file mode 100644 index 000000000..2dcdad117 Binary files /dev/null and b/doc/theme/r_arr.gif differ diff --git a/doc/theme/r_arr_disabled.gif b/doc/theme/r_arr_disabled.gif new file mode 100644 index 000000000..2100f78bf Binary files /dev/null and b/doc/theme/r_arr_disabled.gif differ diff --git a/doc/theme/style.css b/doc/theme/style.css new file mode 100644 index 000000000..4ffecb9b5 --- /dev/null +++ b/doc/theme/style.css @@ -0,0 +1,179 @@ +/* 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) + */ +body +{ + background-image: url(bkd.gif); + background-color: #FFFFFF; + margin: 1em 2em 1em 2em; +} + +h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; text-align: left; } +h2 { font: 140% sans-serif; font-weight: bold; text-align: left; } +h3 { font: 120% sans-serif; font-weight: bold; text-align: left; } +h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left; } +h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left; } +h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left; } + +pre +{ + border-top: gray 1pt solid; + border-right: gray 1pt solid; + border-left: gray 1pt solid; + border-bottom: gray 1pt solid; + + padding-top: 2pt; + padding-right: 2pt; + padding-left: 2pt; + padding-bottom: 2pt; + + display: block; + font-family: "courier new", courier, mono; + background-color: #eeeeee; font-size: small +} + +code +{ + font-family: "Courier New", Courier, mono; + font-size: small +} + +tt +{ + display: inline; + font-family: "Courier New", Courier, mono; + color: #000099; + font-size: small +} + +p +{ + text-align: justify; + font-family: Georgia, "Times New Roman", Times, serif +} + +ul +{ + list-style-image: url(bullet.gif); + font-family: Georgia, "Times New Roman", Times, serif +} + +ol +{ + font-family: Georgia, "Times New Roman", Times, serif +} + +a +{ + font-weight: bold; + color: #003366; + text-decoration: none; +} + +a:hover { color: #8080FF; } + +.literal { color: #666666; font-style: italic} +.keyword { color: #000099} +.identifier {} +.comment { font-style: italic; color: #990000} +.special { color: #800040} +.preprocessor { color: #990099} +.string { font-style: italic; color: #666666} +.copyright { color: #666666; font-size: small} +.white_bkd { background-color: #FFFFFF} +.dk_grey_bkd { background-color: #999999} +.quotes { color: #666666; font-style: italic; font-weight: bold} + +.note_box +{ + display: block; + + border-top: gray 1pt solid; + border-right: gray 1pt solid; + border-left: gray 1pt solid; + border-bottom: gray 1pt solid; + + padding-right: 12pt; + padding-left: 12pt; + padding-bottom: 12pt; + padding-top: 12pt; + + font-family: Arial, Helvetica, sans-serif; + background-color: #E2E9EF; + font-size: small; text-align: justify +} + +.table_title +{ + background-color: #648CCA; + + font-family: Verdana, Arial, Helvetica, sans-serif; color: #FFFFFF; + font-weight: bold +; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px +} + +.table_cells +{ + background-color: #E2E9EF; + + font-family: Geneva, Arial, Helvetica, san-serif; + font-size: small +; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px +} + +.toc +{ + DISPLAY: block; + background-color: #E2E9EF + font-family: Arial, Helvetica, sans-serif; + + border-top: gray 1pt solid; + border-left: gray 1pt solid; + border-bottom: gray 1pt solid; + border-right: gray 1pt solid; + + padding-top: 24pt; + padding-right: 24pt; + padding-left: 24pt; + padding-bottom: 24pt; +} + +.toc_title +{ + background-color: #648CCA; + padding-top: 4px; + padding-right: 4px; + padding-bottom: 4px; + padding-left: 4px; + font-family: Geneva, Arial, Helvetica, san-serif; + color: #FFFFFF; + font-weight: bold +} + +.toc_cells +{ + background-color: #E2E9EF; + padding-top: 4px; + padding-right: 4px; + padding-bottom: 4px; + padding-left: 4px; + font-family: Geneva, Arial, Helvetica, san-serif; + font-size: small +} + +div.logo +{ + float: right; +} + +.toc_cells_L0 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.toc_cells_L1 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 44px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.toc_cells_L2 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 88px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.toc_cells_L3 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 122px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.toc_cells_L4 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 166px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.updated { + font-size: x-small; + color: #666666; + font-style: italic; +} diff --git a/doc/theme/u_arr.gif b/doc/theme/u_arr.gif new file mode 100644 index 000000000..ada3d6e04 Binary files /dev/null and b/doc/theme/u_arr.gif differ diff --git a/doc/theme/uc.gif b/doc/theme/uc.gif new file mode 100644 index 000000000..7575b3998 Binary files /dev/null and b/doc/theme/uc.gif differ diff --git a/doc/theme/wave.gif b/doc/theme/wave.gif new file mode 100644 index 000000000..7dfe5fde5 Binary files /dev/null and b/doc/theme/wave.gif differ diff --git a/doc/token_ids.html b/doc/token_ids.html new file mode 100644 index 000000000..16f12e30b --- /dev/null +++ b/doc/token_ids.html @@ -0,0 +1,972 @@ + + + +The Token Identifiers + + + + + + + + + + +

The + Token Identifiers
+
+ + + + + + + +
+
+

Table of literal token identifiers
+ Table of white token identifiers
+ Table of keyword token identifiers
+ Table of operator token identifiers
+ Table of preprocessor token identifiers

+
+

The following tables contain all those tokens, which should be recognized by + a C++ lexer, which is to be used in conjunction with the Wave preprocessing + engine. The tokens are grouped into categories to simplify some internal logic + and eventually the driver programs. The token identifiers are defined as an + enum, and it is recommended to reuse this definition for your own lexer + implementations.

+

Note though, that the preprocessor engine does some token transformation, so + that not all of the listet here token identifiers may occur inside tokens, returned + from the preprocessing iterator.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

List of literal token id's

Token identifier

Token category

Token value

T_CHARLIT 

CharacterLiteralTokenType

'a', '\t', '\u0057'

T_FLOATLIT

FloatingLiteralTokenType

-1.23456e78

T_IDENTIFIER

IdentifierTokenType

C++ identifier

T_OCTALINT

IntegerLiteralTokenType

007

T_DECIMALINT

IntegerLiteralTokenType

10

T_HEXAINT

IntegerLiteralTokenType

0x1234

T_INTLIT

IntegerLiteralTokenType

T_OCTALINT, T_DECIMALINT or T_HEXAINT

T_STRINGLIT

StringLiteralTokenType

"abc"

T_FALSE

BoolLiteralTokenType

false

T_TRUE

BoolLiteralTokenType

true
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

List of whitespace token id's

Token identifier

Token category

Token value

T_ANY

UnknownTokenType

any value not matched otherwise

T_CCOMMENT

WhiteSpaceTokenType

/* ... */

T_CPPCOMMENT

WhiteSpaceTokenType

// ... \n

T_SPACE

WhiteSpaceTokenType

blank or '\t'

T_SPACE2

WhiteSpaceTokenType

'\v' or '\f'

T_EOF

EOFTokenType

end of input

T_CONTLINE

EOLTokenType

'\\' followed by '\n'

T_NEWLINE

EOLTokenType

'\n'
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

List of keyword token id's

Token identifier

Token category

Token value

T_ASM

KeywordTokenType

asm

T_AUTO

KeywordTokenType

auto

T_BOOL

KeywordTokenType

bool

T_BREAK

KeywordTokenType

break

T_CASE

KeywordTokenType

case

T_CATCH

KeywordTokenType

catch

T_CHAR

KeywordTokenType

char

T_CLASS

KeywordTokenType

class

T_CONST

KeywordTokenType

const

T_CONSTCAST

KeywordTokenType

const_cast

T_CONTINUE

KeywordTokenType

continue

T_DEFAULT

KeywordTokenType

default

T_DEFINED

KeywordTokenType

defined

T_DELETE

KeywordTokenType

delete

T_DO

KeywordTokenType

do

T_DOUBLE

KeywordTokenType

double

T_DYNAMICCAST

KeywordTokenType

dynamic_cast

T_ELSE

KeywordTokenType

else

T_ENUM

KeywordTokenType

enum

T_EXPLICIT

KeywordTokenType

explicit

T_EXPORT

KeywordTokenType

export

T_EXTERN

KeywordTokenType

extern

T_FLOAT

KeywordTokenType

float

T_FOR

KeywordTokenType

for

T_FRIEND

KeywordTokenType

friend

T_GOTO

KeywordTokenType

goto

T_IF

KeywordTokenType

if

T_INLINE

KeywordTokenType

inline

T_INT

KeywordTokenType

int

T_LONG

KeywordTokenType

long

T_MUTABLE

KeywordTokenType

mutable

T_NAMESPACE

KeywordTokenType

namespace

T_NEW

KeywordTokenType

new

T_OPERATOR

KeywordTokenType

operator

T_PRIVATE

KeywordTokenType

private

T_PROTECTED

KeywordTokenType

protected

T_PUBLIC

KeywordTokenType

public

T_REGISTER

KeywordTokenType

register

T_REINTERPRETCAST

KeywordTokenType

reinterpret_cast

T_RETURN

KeywordTokenType

return

T_SHORT

KeywordTokenType

short

T_SIGNED

KeywordTokenType

signed

T_SIZEOF

KeywordTokenType

sizeof

T_STATIC

KeywordTokenType

static

T_STATICCAST

KeywordTokenType

static_cast

T_STRUCT

KeywordTokenType

struct

T_SWITCH

KeywordTokenType

switch

T_TEMPLATE

KeywordTokenType

template

T_THIS

KeywordTokenType

this

T_THROW

KeywordTokenType

throw

T_TRY

KeywordTokenType

try

T_TYPEDEF

KeywordTokenType

typedef

T_TYPEID

KeywordTokenType

typeid

T_TYPENAME

KeywordTokenType

typename

T_UNION

KeywordTokenType

union

T_UNSIGNED

KeywordTokenType

unsigned

T_USING

KeywordTokenType

using

T_VIRTUAL

KeywordTokenType

virtual

T_VOID

KeywordTokenType

void

T_VOLATILE

KeywordTokenType

volatile

T_WCHART

KeywordTokenType

wchar_t

T_WHILE

KeywordTokenType

while
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

List of operator token id's

Token identifier

Token category

Token value

T_AND

OperatorTokenType

&

T_ANDAND

OperatorTokenType

&&

T_ASSIGN

OperatorTokenType

=

T_ANDASSIGN

OperatorTokenType

&=

T_OR

OperatorTokenType

|

T_ORASSIGN

OperatorTokenType

|=

T_XOR

OperatorTokenType

^

T_XORASSIGN

OperatorTokenType

^=

T_COMMA

OperatorTokenType

,

T_COLON

OperatorTokenType

:

T_DIVIDE

OperatorTokenType

/

T_DIVIDEASSIGN

OperatorTokenType

/=

T_DOT

OperatorTokenType

.

T_DOTSTAR

OperatorTokenType

.*

T_ELLIPSIS

OperatorTokenType

...

T_EQUAL

OperatorTokenType

==

T_GREATER

OperatorTokenType

>

T_GREATEREQUAL

OperatorTokenType

>=

T_LEFTBRACE

OperatorTokenType

{

T_LESS

OperatorTokenType

<

T_LESSEQUAL

OperatorTokenType

<=

T_LEFTPAREN

OperatorTokenType

(

T_LEFTBRACKET

OperatorTokenType

[

T_MINUS

OperatorTokenType

-

T_MINUSASSIGN

OperatorTokenType

-=

T_MINUSMINUS

OperatorTokenType

--

T_PERCENT

OperatorTokenType

%

T_PERCENTASSIGN

OperatorTokenType

%=

T_NOT

OperatorTokenType

!

T_NOTEQUAL

OperatorTokenType

!=

T_OROR

OperatorTokenType

||

T_PLUS

OperatorTokenType

+

T_PLUSASSIGN

OperatorTokenType

+=

T_PLUSPLUS

OperatorTokenType

++

T_ARROW

OperatorTokenType

->

T_ARROWSTAR

OperatorTokenType

->*

T_QUESTION_MARK

OperatorTokenType

?

T_RIGHTBRACE

OperatorTokenType

}

T_RIGHTPAREN

OperatorTokenType

)

T_RIGHTBRACKET

OperatorTokenType

]

T_COLON_COLON

OperatorTokenType

::

T_SEMICOLON

OperatorTokenType

;

T_SHIFTLEFT

OperatorTokenType

<<

T_SHIFTLEFTASSIGN

OperatorTokenType

<<=

T_SHIFTRIGHT

OperatorTokenType

>>

T_SHIFTRIGHTASSIGN

OperatorTokenType

>>=

T_STAR

OperatorTokenType

*

T_COMPL

OperatorTokenType

~

T_STARASSIGN

OperatorTokenType

*=

T_POUND_POUND

OperatorTokenType

##

T_POUND

OperatorTokenType

#

T_AND_ALT

OperatorTokenType | AltTokenType

bitand

T_ANDASSIGN_ALT

OperatorTokenType | AltTokenType

and_eq

T_OR_ALT

OperatorTokenType | AltTokenType

or

T_ORASSIGN_ALT

OperatorTokenType | AltTokenType

or_eq

T_XOR_ALT

OperatorTokenType | AltTokenType

xor

T_XORASSIGN_ALT

OperatorTokenType | AltTokenType

xor_eq

T_LEFTBRACE_ALT

OperatorTokenType | AltTokenType

<%

T_LEFTBRACKET_ALT

OperatorTokenType | AltTokenType

<:

T_NOT_ALT

OperatorTokenType | AltTokenType

not

T_NOTEQUAL_ALT

OperatorTokenType | AltTokenType

not_eq

T_RIGHTBRACE_ALT

OperatorTokenType | AltTokenType

%>

T_RIGHTBRACKET_ALT

OperatorTokenType | AltTokenType

:>

T_COMPL_ALT

OperatorTokenType | AltTokenType

compl

T_POUND_POUND_ALT

OperatorTokenType | AltTokenType

%:%:

T_POUND_ALT

OperatorTokenType | AltTokenType

%:

T_OR_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??!

T_XOR_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??'

T_LEFTBRACE_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??<

T_LEFTBRACKET_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??(

T_RIGHTBRACE_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??>

T_RIGHTBRACKET_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??)

T_COMPL_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??-

T_POUND_POUND_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??=??=

T_POUND_TRIGRAPH

OperatorTokenType | TriGraphTokenType

??=
+


+ The preprocessor tokens listet in the following + table are returned by the C++ lexer only. The preprocessor naturally acts on + these tokens and they are not returned by dereferencing the preprocessing iterators.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

List of preprocessor token id's

Token identifier

Token category

Token value

T_PP_DEFINE

PPTokenType

#define

T_PP_IF

PPTokenType

#if

T_PP_IFDEF

PPTokenType

#ifdef

T_PP_IFNDEF

PPTokenType

#ifndef

T_PP_ELSE

PPTokenType

#else

T_PP_ELIF

PPTokenType

#elif

T_PP_ENDIF

PPTokenType

#endif

T_PP_ERROR

PPTokenType

#error

T_PP_LINE

PPTokenType

#line

T_PP_PRAGMA

PPTokenType

#pragma

T_PP_UNDEF

PPTokenType

#undef

T_PP_WARNING

PPTokenType

#warning

T_PP_INCLUDE

PPTokenType

#include "..."

T_PP_QHEADER

PPTokenType

#include <...>

T_PP_HHEADER

PPTokenType

#include ...
+
+ + + + + + + +
+
+ + + + + diff --git a/doc/tracing_facility.html b/doc/tracing_facility.html new file mode 100644 index 000000000..a96631dce --- /dev/null +++ b/doc/tracing_facility.html @@ -0,0 +1,163 @@ + + + +The Tracing Facility + + + + + + + + + + + +

The + 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 explicitely enable/disable the tracing for the + macro in question only. This may be done with the help of a special, Wave + specific #pragma:

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

In C99 mode or when specifying the --variadics command line option + you may additionally use the operator _Pragma() variant to enable/disable + the tracing output:

+
    #define CONCAT(x, y) \
+        _Pragma("wave trace(enable)") \
+        x \
+        _Pragma("wave trace(disable)") \
+        ## y
+

This way you have the possibility to enable the tracing during the expansion + of a part of a macro only. In the sample shown there is traced the expansion + of the macro argument 'x' only. Note, that the operator _Pragma() + directives expand to nothing inside the macro expansion result.

+

To see, what the Wave driver generates while expanding a simple macro, + let's have a look at the tracing output for the following example:

+
    // 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)
+

When preprocessed with 'wave -t test.trace test.cpp' the Wave + driver generates a file test.trace, which contains (without the line + numbers in front of the lines):

+
  1: test.cpp(8): CONCAT(X(1), Y())
+  2:   test.cpp(5): see macro definition: CONCAT(x, y)
+  3:   invoked with
+  4:   [
+  5:     x = X(1)
+  6:     y = Y()
+  7:   ]
+  8:   [
+  9:     test.cpp(2): see macro definition: X(x)
+ 10:     invoked with
+ 11:     [
+ 12:       x = 1
+ 13:     ]
+ 14:     [
+ 15:       1
+ 16:       rescanning
+ 17:       [
+ 18:         1
+ 19:       ]
+ 20:     ]
+ 21:     test.cpp(3): see macro definition: Y()
+ 22:     [
+ 23:       2
+ 24:       rescanning
+ 25:       [
+ 26:         2
+ 27:       ]
+ 28:     ]
+ 29:     CONCAT_(1, 2)
+ 30:     rescanning
+ 31:     [
+ 32:       test.cpp(4): see macro definition: CONCAT_(x, y)
+ 33:       invoked with
+ 34:       [
+ 35:         x = 1
+ 36:         y = 2
+ 37:       ]
+ 38:       [
+ 39:         12
+ 40:         rescanning
+ 41:         [
+ 42:           12
+ 43:         ]
+ 44:       ]
+ 45:       12
+ 46:     ]
+ 47:   ]
+
+

The generated trace output is very verbose, but allows to follow every step + of the actual macro expansion process. The first line in this tracing example + contains the reference to the position, from where the macro expansion was initiated. + Additionally the following information is contained for every single macro expansion:

+
    +
  • The reference to the position, where the macro to expand was defined first + (see lines 2, 9, 21 and 32).
  • +
  • The real parameters supplied for this macro expansion (see lines 3, 10 and + 33), this information is traced inside the invoked with block, where + the corresponding formal and actual parameters are listed.
  • +
  • The expansion of the given arguments (if any and if these are defined as + macros). This repeats the full tracing information for the argument macro + expansion, only intended by one level. Note though, that the macro expansion + of the actual arguments is traced, regardless of the fact, if this argument + is really to be inserted into the replacement list only after its expansion + or as it was initially supplied (see C++ Standard [16.3.1.1]: "A parameter + in the replacement list, unless preceded by a # or ## preprocessing + token or followed by a ## preprocessing token, is replaced by the + corresponding argument after all macros contained therein have been expanded" + [1]).
  • +
  • The result of the argument substitution (see lines 15, 23, 29 and 39), i.e. + the substituted replacement list.
  • +
  • The rescanning process, which again includes the full subsequent macro expansion + process of all found macros (see C++ Standard [16.3.4.1]: "After all + parameters in the replacement list have been substituted, the resulting preprocessing + token sequence is rescanned with all subsequent preprocessing tokens of the + source file for more macro names to replace." [1]).
  • +
  • The result of the actual macro expansion (this is the last line inside the + corresponding rescanning block - see lines 18, 26, 42 and 45).
  • +
+

Every found macro to expand will add an additional indentation level inside + the trace output.

+ + + + + + + +
+
+ + + + + + +Wednesday, February 9, 2005 23:37 \ No newline at end of file diff --git a/doc/wave_driver.html b/doc/wave_driver.html new file mode 100644 index 000000000..eb2b2b5a2 --- /dev/null +++ b/doc/wave_driver.html @@ -0,0 +1,219 @@ + + + +The Wave Driver + + + + + + + + + + + +

The + Wave Driver
+
+ + + + + + + +
+

There is implemented a driver program for the Wave library, which + utilizes nearly all 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
+    --variadics:            enable variadics and placemarkers in C++ mode
+    --c99:                  enable C99 mode (implies variadics and placemarkers)
+
+
+

The possible options are straightforward and self explanatory. The + following describes some of these options in more detail. Please note, that + the extended options (--c99 and --variadics) are available only, if the driver + was compiled with the constant WAVE_SUPPORT_VARIADICS_PLACEMARKERS + defined.

+

-o [--output] path

+
+

Specify a filename to be used for the generated preprocessed output + stream. If this option is not given, then the standard output is used (stdout).

+
+

-I [--include] option

+
+

Add the given directory to the head of the list of directories + to be searched for header files. This can be used to override a system header + file, substituting your own version, since these directories are searched + before the system header file directories. If you use more than one '-I' option, the directories are scanned in left-to-right order, the system directories + come after.

+
+

-I- [--include-] option

+
+

The Wave library maintains two separate search pathes + for include files. A search path for user include files and a search path + for system include files. Any directories specified with '-I' options before + an eventually given '-I-' option are searched only for the case of '#include "file"' + (user include files), they are not searched for '#include <file>' + directives (system include files). If additional directories are specified + with '-I' options after a '-I-' option was given, these directories are searched + for all '#include' directives. In addition, the '-I-' option inhibits the + use of the current directory as the first search directory for '#include "file"' + directives. Therefore, the current directory is searched only if it is requested + explicitly with a '-I.' option. Specifying both '-I-' and '-I.' allows to + control precisely which directories are searched before the current one and + which are searched after.

+
+

-S [--sysinclude] option

+
+

Add the given directory to the head of the list of directories + to be searched for system header files. If you use more than one '-S' option, + the directories are scanned in left-to-right order. This option is most useful + in the wave.cfg configuration file to specify, where the system include files + are to be searched.

+
+

-F [--forceinclude] option

+
+

Process the given file as normal input and include all the resulting + output before the processing the regular input file starts. If more than one + such option is given, the files are pre-included in the sequence of its occurance + on the command line.

+
+

-D [--define] macro[=definition]
-P [--predefine] macro[=definition]

+
+

This option allows to define ('-D') or predefine ('-P') a macro + from the command line. The string given in conjunction with the '-D' or '-P' + option should conform to the usual syntax MACRO(x)=definition as is described + in more detail here.

+

The only difference between the '-D' and the '-P' options is, + that the latter predefines a macro such, that it is not undefinable + through an #undef directive from inside the preprocessed program.

+
+

-U [--undefine] option

+
+

This allows to undefine some of the automatically predefined macros + of the Wave library (see Predefined macros). The only exception are + the __LINE__, __FILE__, + __DATE__, __TIME__, + __STDC__ and __cplusplus + predefined macros, which are not undefinable. If -U and -D are both specified + for one name, the name is not predefined.

+
+

-n [--nesting] depth

+
+

Specify a new maximal include nesting depth. If the preprocessing + reaches this include file nesting depth, it aborts the preprocessing after + emitting an error message. The default include file nesting depth is 1024.

+
+

-t [--traceto] path

+
+

Enable the tracing facility build into the Wave library. + The path specifies the filename to use for the output of the generated trace + log. If the filename given equals to '-' (without the quotes), the + trace log is put into the standard error stream (stderr).

+
+

--timer

+
+

Enable to track the overall elapsed computing time required for + the given input file. The elapsed time is printed to stdout after the compilation + is completed.

+
+

--variadics

+
+

Enables support for variadics (macros with variable parameter lists), + placemarkers (empty macro arguments) and operator _Pragma in + normal C++ mode. This option predefines a special predefined macro __WAVE_HAS_VARIADICS__.

+
+

--c99

+
+

Enable the C99 mode. This mode enables certain C99 specific features + as variadics (macros with variable parameter lists), placemarkers (empty macro + arguments) and operator _Pragma support and disables some C++ + specific token types as for instance '::', '->*' and '->.'. + Several predefined macros are different for this mode, for more information + about predefined macros you may look here. +

+
+

@ [--config-file] option

+
+

Some of the possible command line options may be specified inside + of special configuration files. This is very useful, as a shorthand for different + global configurations. A config file may contain additional options (-I, -S, + -F, -U, -D and -P options), one option per line. Empty lines and lines beginning + with a '#' character are ignored (are treated as a comment lines). Note that + the '#' character is treated as the beginning of a comment only, if it is + the first non-whitespace character on a line. Here is a small sample illustrating the supported configuration file syntax:

+
    # 
+    # enable variadics et.al. in C++ mode
+    #
+    --variadics
+    #
+    # enable timer support
+    #
+    --timer
+    #
+    # emulate gcc V3.3.2
+    #
+    -D__GNUC__=3
+    -D__GNUC_MINOR__=3
+    -D__GNUC_PATCHLEVEL__=2
+    -D__GNUG__
+    # 
+    # add Boost to the system include search paths
+    #
+    -S/usr/local/boost
+

There is a shorthand for specifying a configuration file on the + command line: simply use the '@' character immediatly before the corresponding + file name.

+

The options found in a configuration file are interpreted, as + if they were place instead of the configuration file option on the command + line.

+
+

The Wave driver program looks at startup for a configuration + file named 'wave.cfg' in the same directory, where it was started from (where + is located the driver executable). If this file exists, it is treated as a normal + configuration file and the specified herein options are interpreted as if they + were given as the first options on the command line. This feature is very useful + for defining a global environment for the Wave preprocessor driver.

+ + + + + + + +
+
+ + + + + diff --git a/include/boost/wave.hpp b/include/boost/wave.hpp new file mode 100644 index 000000000..80510cc5e --- /dev/null +++ b/include/boost/wave.hpp @@ -0,0 +1,21 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(WAVE_HPP_DCA0EA51_EF5B_4BF1_88A8_461DBC5F292B_INCLUDED) +#define WAVE_HPP_DCA0EA51_EF5B_4BF1_88A8_461DBC5F292B_INCLUDED + +#include +#include +#include + +#include +#include + +#endif // !defined(WAVE_HPP_DCA0EA51_EF5B_4BF1_88A8_461DBC5F292B_INCLUDED) diff --git a/include/boost/wave/cpp_context.hpp b/include/boost/wave/cpp_context.hpp new file mode 100644 index 000000000..a73956566 --- /dev/null +++ b/include/boost/wave/cpp_context.hpp @@ -0,0 +1,300 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + Definition of the preprocessor context + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED) +#define CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +/////////////////////////////////////////////////////////////////////////////// +// +// The C preprocessor context template class +// +// The boost::wave::context template is the main interface class to +// control the behaviour of the preprocessing engine. +// +// The following template parameters has to be supplied: +// +// IteratorT The iterator type of the underlying input stream +// LexIteratorT The lexer iterator type to use as the token factory +// InputPolicyT The input policy type to use for loading the files +// to be included. This template parameter is optional and +// defaults to the +// iteration_context_policies::load_file_to_string +// type +// TraceT The trace policy to use for trace and include file +// notification callback. +// +/////////////////////////////////////////////////////////////////////////////// + +template < + typename IteratorT, + typename LexIteratorT, + typename InputPolicyT = iteration_context_policies::load_file_to_string, + typename TraceT = context_policies::default_preprocessing_hooks +> +class context { + +public: + +// concept checks +// the given iterator shall be at least a forward iterator type + BOOST_CLASS_REQUIRE(IteratorT, boost, ForwardIteratorConcept); + +// public typedefs + typedef typename LexIteratorT::token_type token_type; + typedef context + self_type; + + typedef IteratorT target_iterator_type; + typedef LexIteratorT lexer_type; + typedef pp_iterator iterator_type; + + typedef InputPolicyT input_policy_type; + typedef typename token_type::position_type position_type; + +// type of a token sequence + typedef std::list > + token_sequence_type; + +// types of the policies + typedef TraceT trace_policy_type; + +private: +// stack of shared_ptr's to the pending iteration contexts + typedef boost::shared_ptr > + iteration_ptr_type; + typedef boost::wave::util::iteration_context_stack + iteration_context_stack_type; + typedef typename iteration_context_stack_type::size_type iter_size_type; + +public: + context(target_iterator_type const &first_, target_iterator_type const &last_, + char const *fname = "", TraceT const &trace_ = TraceT()) + : first(first_), last(last_), filename(fname) +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + , current_filename(fname) +#endif + , macros(*this), language(boost::wave::support_cpp), trace(trace_) + { + macros.init_predefined_macros(fname); + includes.init_initial_path(); + includes.set_current_directory(filename.c_str()); + } + +// iterator interface + iterator_type begin() + { + return iterator_type(*this, first, last, position_type(filename.c_str()), + get_language()); + } + iterator_type end() const + { return iterator_type(); } + +// maintain include paths + bool add_include_path(char const *path_) + { return includes.add_include_path(path_, false);} + bool add_sysinclude_path(char const *path_) + { return includes.add_include_path(path_, true);} + void set_sysinclude_delimiter() { includes.set_sys_include_delimiter(); } + typename iteration_context_stack_type::size_type get_iteration_depth() const + { return iter_ctxs.size(); } + +// maintain defined macros +#if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 + bool add_macro_definition(std::string macrostring, + bool is_predefined = false) + { return boost::wave::util::add_macro_definition(*this, macrostring, + is_predefined, get_language()); } +#endif + bool add_macro_definition(token_type const &name, bool has_params, + std::vector ¶meters, token_sequence_type &definition, + bool is_predefined = false) + { return macros.add_macro(name, has_params, parameters, definition, + is_predefined); } + template + bool is_defined_macro(IteratorT2 const &begin, IteratorT2 const &end) + { return macros.is_defined(begin, end); } + bool remove_macro_definition(typename token_type::string_type const &name, + bool even_predefined = false) + { return macros.remove_macro(name, even_predefined); } + void reset_macro_definitions() + { macros.reset_macromap(); macros.init_predefined_macros(); } + +// get the pp-iterator version information + static std::string get_version() + { return boost::wave::util::predefined_macros::get_fullversion(false); } + static std::string get_version_string() + { return boost::wave::util::predefined_macros::get_versionstr(false); } + + void set_language(boost::wave::language_support language_) + { + language = language_; + reset_macro_definitions(); + } + boost::wave::language_support get_language() const { return language; } + +// change and ask for maximal possible include nesting depth + void set_max_include_nesting_depth(iter_size_type new_depth) + { iter_ctxs.set_max_include_nesting_depth(new_depth); } + iter_size_type get_max_include_nesting_depth() const + { return iter_ctxs.get_max_include_nesting_depth(); } + +// access the trace policy + trace_policy_type &get_trace_policy() + { return trace; } + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) +protected: + friend class boost::wave::pp_iterator< + boost::wave::context >; + friend class boost::wave::impl::pp_iterator_functor< + boost::wave::context >; +#endif + +// maintain include pathes (helper functions) + bool find_include_file (std::string &s, bool is_system, + char const *current_file) const + { return includes.find_include_file(s, is_system, current_file); } + void set_current_directory(char const *path_) + { includes.set_current_directory(path_); } + +// conditional compilation contexts + bool get_if_block_status() const { return ifblocks.get_status(); } + void enter_if_block(bool new_status) + { ifblocks.enter_if_block(new_status); } + bool enter_elif_block(bool new_status) + { return ifblocks.enter_elif_block(new_status); } + bool enter_else_block() { return ifblocks.enter_else_block(); } + bool exit_if_block() { return ifblocks.exit_if_block(); } + typename boost::wave::util::if_block_stack::size_type get_if_block_depth() const + { return ifblocks.get_if_block_depth(); } + +// stack of iteration contexts + iteration_ptr_type pop_iteration_context() + { iteration_ptr_type top = iter_ctxs.top(); iter_ctxs.pop(); return top; } + void push_iteration_context(position_type const &act_pos, iteration_ptr_type iter_ctx) + { iter_ctxs.push(act_pos, iter_ctx); } + + position_type &get_main_pos() { return macros.get_main_pos(); } + +/////////////////////////////////////////////////////////////////////////////// +// +// expand_tokensequence(): +// expands all macros contained in a given token sequence, handles '##' +// and '#' pp operators and re-scans the resulting sequence +// (essentially preprocesses the token sequence). +// +// The expand_undefined parameter is true during macro expansion inside +// a C++ expression given for a #if or #elif statement. +// +/////////////////////////////////////////////////////////////////////////////// + template + token_type expand_tokensequence(IteratorT2 &first, IteratorT2 const &last, + token_sequence_type &pending, token_sequence_type &expanded, + bool expand_undefined = false) + { + return macros.expand_tokensequence(first, last, pending, expanded, + expand_undefined); + } + + template + void expand_whole_tokensequence(IteratorT2 &first, IteratorT2 const &last, + token_sequence_type &expanded, bool expand_undefined = true) + { + macros.expand_whole_tokensequence(expanded, first, last, + expand_undefined); + + // remove any contained placeholder + boost::wave::util::impl::remove_placeholders(expanded); + } + +public: +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +// support for #pragma once +// maintain the real name of the current preprocessed file + void set_current_filename(char const *real_name) + { current_filename = real_name; } + std::string const &get_current_filename() const + { return current_filename; } + +// maintain the list of known headers containing #pragma once + bool has_pragma_once(std::string const &filename) + { return includes.has_pragma_once(filename); } + bool add_pragma_once_header(std::string const &filename) + { return includes.add_pragma_once_header(filename); } +#endif + +// forwarding functions for the context policy hooks + template + bool interpret_pragma(ContainerT &pending, token_type const &option, + ContainerT const &values, token_type const &act_token) + { + return trace.interpret_pragma(*this, pending, option, values, + act_token); + } + template + void defined_macro(token_type const &name, bool is_functionlike, + ParametersT const ¶meters, DefinitionT const &definition, + bool is_predefined) + { + trace.defined_macro(name, is_functionlike, parameters, definition, + is_predefined); + } + void undefined_macro(typename token_type::string_type const &name) + { + trace.undefined_macro(name); + } + +private: +// the main input stream + target_iterator_type first; // underlying input stream + target_iterator_type last; + std::string filename; // associated main filename +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + std::string current_filename; // real name of current preprocessed file +#endif + + boost::wave::util::if_block_stack ifblocks; // conditional compilation contexts + boost::wave::util::include_pathes includes; // lists of include directories to search + iteration_context_stack_type iter_ctxs; // iteration contexts + boost::wave::util::macromap macros; // map of defined macros + boost::wave::language_support language; // supported language/extensions + trace_policy_type trace; // trace policy instance +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED) diff --git a/include/boost/wave/cpp_exceptions.hpp b/include/boost/wave/cpp_exceptions.hpp new file mode 100644 index 000000000..0aa4c9adb --- /dev/null +++ b/include/boost/wave/cpp_exceptions.hpp @@ -0,0 +1,282 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED) +#define CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED + +#include +#include + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +// helper macro for throwing exceptions +#if !defined(BOOST_WAVE_THROW) +#ifdef BOOST_NO_STRINGSTREAM +#include +#define BOOST_WAVE_THROW(cls, code, msg, act_pos) \ + { \ + using namespace boost::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 +#define BOOST_WAVE_THROW(cls, code, msg, act_pos) \ + { \ + using namespace boost::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 +#endif // BOOST_WAVE_THROW + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +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, + alreadydefined_name, + undefined_macroname, + invalid_macroname, + unexpected_qualified_name, + division_by_zero + }; + + 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 "boost::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 + "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", // invalid_macroname + "qualified names are supported in C++0x mode only", // unexpected_qualified_name + "division by zero in preprocessor expression" // division_by_zero + }; + BOOST_ASSERT(unexpected_error <= code && + code <= division_by_zero); + 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, // alreadydefined_name + util::severity_error, // undefined_macroname + util::severity_error, // invalid_macroname + util::severity_error, // unexpected_qualified_name + util::severity_fatal // division_by_zero + }; + BOOST_ASSERT(unexpected_error <= code && + code <= division_by_zero); + 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 +} // namespace boost + +#endif // !defined(CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED) diff --git a/include/boost/wave/cpp_iteration_context.hpp b/include/boost/wave/cpp_iteration_context.hpp new file mode 100644 index 000000000..c851923a2 --- /dev/null +++ b/include/boost/wave/cpp_iteration_context.hpp @@ -0,0 +1,193 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + Definition of the preprocessor context + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED) +#define CPP_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED + +#include +#include +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) +#include +#endif + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace iteration_context_policies { + +/////////////////////////////////////////////////////////////////////////////// +// +// The iteration_context_policies templates are policies for the +// boost::wave::iteration_context which allows to control, how a given input file +// is to be represented by a pair of iterators pointing to the begin and +// the end of the resulting input sequence. +// +/////////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + // + // load_file_to_string + // + // Loads a file into a string and returns the iterators pointing to + // the beginning and the end of the loaded string. + // + /////////////////////////////////////////////////////////////////////////// + struct load_file_to_string { + + template + class inner { + + public: + template + static + void init_iterators(IterContextT &iter_ctx, + PositionT const &act_pos) + { + typedef typename IterContextT::iterator_type iterator_type; + + std::ifstream instream(iter_ctx.filename.c_str()); + if (!instream.is_open()) { + BOOST_WAVE_THROW(preprocess_exception, bad_include_file, + iter_ctx.filename, act_pos); + } + instream.unsetf(std::ios::skipws); + +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) + // this is known to be very slow for large files on some systems + std::copy (istream_iterator(instream), + istream_iterator(), + std::inserter(iter_ctx.instring, iter_ctx.instring.end())); +#else + iter_ctx.instring = std::string( + std::istreambuf_iterator(instream.rdbuf()), + std::istreambuf_iterator()); +#endif // defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) + + iter_ctx.first = iterator_type(iter_ctx.instring.begin(), + iter_ctx.instring.end(), PositionT(iter_ctx.filename), + iter_ctx.language); + iter_ctx.last = iterator_type(); + } + + private: + std::string instring; + }; + }; + +/////////////////////////////////////////////////////////////////////////////// +// +// load_file +// +// The load_file policy opens a given file and returns the wrapped +// istreambuf_iterators. +// +/////////////////////////////////////////////////////////////////////////////// + struct load_file { + + template + class inner { + + public: + ~inner() { if (instream.is_open()) instream.close(); } + + template + static + void init_iterators(IterContextT &iter_ctx, + PositionT const &act_pos) + { + typedef typename IterContextT::iterator_type iterator_type; + + iter_ctx.instream.open(iter_ctx.filename.c_str()); + if (!iter_ctx.instream.is_open()) { + BOOST_WAVE_THROW(preprocess_exception, bad_include_file, + iter_ctx.filename, act_pos); + } + iter_ctx.instream.unsetf(std::ios::skipws); + + using boost::spirit::make_multi_pass; + iter_ctx.first = iterator_type( + make_multi_pass(std::istreambuf_iterator( + iter_ctx.instream.rdbuf())), + make_multi_pass(std::istreambuf_iterator()), + PositionT(iter_ctx.filename), iter_ctx.language); + iter_ctx.last = iterator_type(); + } + + private: + std::ifstream instream; + }; + }; + +} // namespace iterattion_context_policies + +/////////////////////////////////////////////////////////////////////////////// +// +template +struct base_iteration_context { + +public: + base_iteration_context(BOOST_WAVE_STRINGTYPE const &fname) + : real_filename(fname), filename(fname), line(1), emitted_lines(1) + {} + base_iteration_context(IteratorT const &first_, IteratorT const &last_, + BOOST_WAVE_STRINGTYPE const &fname) + : first(first_), last(last_), real_filename(fname), filename(fname), + line(1), emitted_lines(1) + {} + +// the actual input stream + IteratorT first; // actual input stream position + IteratorT last; // end of input stream + BOOST_WAVE_STRINGTYPE real_filename; // real name of the current file + BOOST_WAVE_STRINGTYPE filename; // actual processed file + int line; // line counter of underlying stream + int emitted_lines; // count of emitted newlines +}; + +/////////////////////////////////////////////////////////////////////////////// +// +template < + typename IteratorT, + typename InputPolicyT = + iteration_context_policies::load_file_to_string +> +struct iteration_context +: public base_iteration_context, + public InputPolicyT::template + inner > +{ + typedef IteratorT iterator_type; + typedef typename IteratorT::token_type::position_type position_type; + + typedef iteration_context self_type; + + iteration_context(BOOST_WAVE_STRINGTYPE const &fname, + position_type const &act_pos, + boost::wave::language_support language_) + : base_iteration_context(fname), + language(language_) + { + InputPolicyT::template inner::init_iterators(*this, act_pos); + } + + boost::wave::language_support language; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED) diff --git a/include/boost/wave/cpplexer/cpp_lex_interface.hpp b/include/boost/wave/cpplexer/cpp_lex_interface.hpp new file mode 100644 index 000000000..3e110f01f --- /dev/null +++ b/include/boost/wave/cpplexer/cpp_lex_interface.hpp @@ -0,0 +1,81 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the abstract lexer interface + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED) +#define CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +/////////////////////////////////////////////////////////////////////////////// +// +// new_lexer_gen: generates a new instance of the required C++ lexer +// +/////////////////////////////////////////////////////////////////////////////// +template struct lex_input_interface; + +template < + typename IteratorT, + typename PositionT = boost::wave::util::file_position_type +> +struct new_lexer_gen +{ +// The NewLexer function allows the opaque generation of a new lexer object. +// It is coupled to the token type to allow to decouple the lexer/token +// configurations at compile time. + static lex_input_interface > * + new_lexer(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// The lex_input_interface decouples the lex_iterator_shim from the actual +// lexer. This is done to allow compile time reduction. +// Thanks to JCAB for having this idea. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct lex_input_interface +{ + typedef typename TokenT::position_type position_type; + + virtual TokenT get() = 0; + virtual void set_position(position_type const &pos) = 0; + + virtual ~lex_input_interface() {} + +// The new_lexer function allows the opaque generation of a new lexer object. +// It is coupled to the token type to allow to distinguish different +// lexer/token configurations at compile time. + template + static lex_input_interface * + new_lexer(IteratorT const &first, IteratorT const &last, + position_type const &pos, boost::wave::language_support language) + { + return new_lexer_gen::new_lexer (first, last, + pos, language); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED) diff --git a/include/boost/wave/cpplexer/cpp_lex_iterator.hpp b/include/boost/wave/cpplexer/cpp_lex_iterator.hpp new file mode 100644 index 000000000..45d3f7b4d --- /dev/null +++ b/include/boost/wave/cpplexer/cpp_lex_iterator.hpp @@ -0,0 +1,139 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the lexer iterator + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED) +#define CPP_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_iterator_functor_shim +// +/////////////////////////////////////////////////////////////////////////////// + +template +class lex_iterator_functor_shim +{ +public: + template + lex_iterator_functor_shim(IteratorT const &first, IteratorT const &last, + typename TokenT::position_type const &pos, + boost::wave::language_support language) + : functor_ptr(lex_input_interface + ::new_lexer(first, last, pos, language)) + {} + +// interface to the boost::spirit::multi_pass_policies::functor_input policy + typedef TokenT result_type; + + static result_type const eof; + + result_type operator()() + { + BOOST_ASSERT(0 != functor_ptr.get()); + return functor_ptr->get(); + } + void set_position(typename TokenT::position_type const &pos) + { + BOOST_ASSERT(0 != functor_ptr.get()); + functor_ptr->set_position(pos); + } + +private: + boost::shared_ptr > functor_ptr; +}; + +/////////////////////////////////////////////////////////////////////////////// +// eof token +template +typename lex_iterator_functor_shim::result_type const + lex_iterator_functor_shim::eof; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_iterator +// +// A generic C++ lexer interface class, which allows to plug in different +// lexer implementations. The interface between the lexer type used and +// the preprocessor component depends on the token type only (template +// parameter TokenT). +// Additionally, the following requirements apply: +// +// - the lexer type should have a function implemented, which returnes +// the next lexed token from the input stream: +// typename TokenT get(); +// - at the end of the input stream this function should return the +// eof token equivalent +// - the lexer should implement a constructor taking two iterators +// pointing to the beginning and the end of the input stream, +// a third parameter containing the name of the parsed input file +// and a 4th parameter of the type boost::wave::language_support +// which specifies, which language subset should be supported (C++, +// C99, C++0x etc.). +// +/////////////////////////////////////////////////////////////////////////////// + +template +class lex_iterator +: public boost::spirit::multi_pass< + impl::lex_iterator_functor_shim, + boost::wave::util::functor_input + > +{ + typedef impl::lex_iterator_functor_shim input_policy_type; + typedef + boost::spirit::multi_pass + base_t; + typedef lex_iterator self_type; + +public: + typedef TokenT token_type; + + lex_iterator() + {} + + template + lex_iterator(IteratorT const &first, IteratorT const &last, + typename TokenT::position_type const &pos, + boost::wave::language_support language) + : base_t(input_policy_type(first, last, pos, language)) + {} +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED) diff --git a/include/boost/wave/cpplexer/cpp_lex_token.hpp b/include/boost/wave/cpplexer/cpp_lex_token.hpp new file mode 100644 index 000000000..604f6ed84 --- /dev/null +++ b/include/boost/wave/cpplexer/cpp_lex_token.hpp @@ -0,0 +1,108 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + A generic C++ lexer token definition + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED) +#define CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +/////////////////////////////////////////////////////////////////////////////// +// forward declaration of the token type +template +class lex_token; + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_token +// +/////////////////////////////////////////////////////////////////////////////// + +template +class lex_token +{ +public: + typedef BOOST_WAVE_STRINGTYPE string_type; + typedef PositionT position_type; + + lex_token() + : id(T_EOI) + {} + + lex_token(token_id id_, string_type const &value_, PositionT const &pos_) + : id(id_), value(value_), pos(pos_) + {} + +// accessors + operator token_id() const { return id; } + string_type const &get_value() const { return value; } + position_type const &get_position() const { return pos; } + void set_token_id (token_id id_) { id = id_; } + void set_value (string_type const &newval) { value = newval; } + void set_position (position_type const &pos_) { pos = pos_; } + +// debug support +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 +// access functions for the tree_to_xml functionality + static int get_token_id(lex_token const &t) + { return ID_FROM_TOKEN(token_id(t)); } + static string_type get_token_value(lex_token const &t) + { return t.get_value(); } +#endif + +#if defined(BOOST_SPIRIT_DEBUG) +// debug support + void print (std::ostream &stream) const + { + stream << get_token_name(id) << "("; + for (std::size_t i = 0; i < value.size(); ++i) { + switch (value[i]) { + case '\r': stream << "\\r"; break; + case '\n': stream << "\\n"; break; + default: + stream << value[i]; + break; + } + } + stream << ")"; + } +#endif // defined(BOOST_SPIRIT_DEBUG) + +private: + token_id id; // the token id + string_type value; // the text, which was parsed into this token + PositionT pos; // the original file position +}; + +#if defined(BOOST_SPIRIT_DEBUG) +template +inline std::ostream & +operator<< (std::ostream &stream, lex_token const &object) +{ + object.print(stream); + return stream; +} +#endif // defined(BOOST_SPIRIT_DEBUG) + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED) diff --git a/include/boost/wave/cpplexer/cpplexer_exceptions.hpp b/include/boost/wave/cpplexer/cpplexer_exceptions.hpp new file mode 100644 index 000000000..3a5969d82 --- /dev/null +++ b/include/boost/wave/cpplexer/cpplexer_exceptions.hpp @@ -0,0 +1,194 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED) +#define CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED + +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// helper macro for throwing exceptions +#if !defined(BOOST_WAVE_LEXER_THROW) +#ifdef BOOST_NO_STRINGSTREAM +#include +#define BOOST_WAVE_LEXER_THROW(cls, code, msg, line, column, name) \ + { \ + using namespace boost::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, line, column, name); \ + } \ + /**/ +#else +#include +#define BOOST_WAVE_LEXER_THROW(cls, code, msg, line, column, name) \ + { \ + using namespace boost::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, line, column, name); \ + } \ + /**/ +#endif // BOOST_NO_STRINGSTREAM +#endif // BOOST_WAVE_LEXER_THROW + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +/////////////////////////////////////////////////////////////////////////////// +// exception severity +namespace util { + + enum severity { + severity_remark = 0, + severity_warning, + severity_error, + severity_fatal + }; + + 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 + }; + BOOST_ASSERT(severity_remark <= level && level <= severity_fatal); + return severity_text[level]; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// cpplexer_exception, the base class for all specific C++ lexer exceptions +class cpplexer_exception +: public std::exception +{ +public: + cpplexer_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; + } + ~cpplexer_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; +}; + +/////////////////////////////////////////////////////////////////////////////// +// lexing_exception error +class lexing_exception : + public cpplexer_exception +{ +public: + enum error_code { + unexpected_error = 0, + universal_char_invalid = 1, + universal_char_base_charset = 2, + universal_char_not_allowed = 3, + generic_lexing_error = 4 + }; + + lexing_exception(char const *what_, error_code code, int line_, + int column_, char const *filename_) throw() + : cpplexer_exception(line_, column_, filename_), + level(severity_level(code)) + { + unsigned int off = 0; + while (off < sizeof(buffer) && *what_) + buffer[off++] = *what_++; + buffer[off] = 0; + } + ~lexing_exception() throw() {} + + virtual char const *what() const throw() + { + return "boost::wave::lexing_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 + "universal character name specifies an invalid character", // universal_char_invalid + "a universal character name cannot designate a character in the " + "basic character set", // universal_char_base_charset + "this universal character is not allowed in an identifier", // universal_char_not_allowed + "generic lexing error" // generic_lexing_error + }; + 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_error, // universal_char_invalid + util::severity_error, // universal_char_base_charset + util::severity_error, // universal_char_not_allowed + util::severity_error // generic_lexing_error + }; + 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 cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED) diff --git a/include/boost/wave/cpplexer/re2clex/aq.hpp b/include/boost/wave/cpplexer/re2clex/aq.hpp new file mode 100644 index 000000000..2d73e0dd0 --- /dev/null +++ b/include/boost/wave/cpplexer/re2clex/aq.hpp @@ -0,0 +1,52 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001 Daniel C. Nuffer. + Copyright (c) 2001-2005 Hartmut Kaiser. + 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) +=============================================================================*/ + +#if !defined(AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED) +#define AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +typedef std::size_t aq_stdelement; + +typedef struct tag_aq_queuetype +{ + std::size_t head; + std::size_t tail; + std::size_t size; + std::size_t max_size; + aq_stdelement* queue; +} aq_queuetype; + +typedef aq_queuetype* aq_queue; + +int aq_enqueue(aq_queue q, aq_stdelement e); +int aq_enqueue_front(aq_queue q, aq_stdelement e); +int aq_serve(aq_queue q, aq_stdelement *e); +int aq_pop(aq_queue q); +#define AQ_EMPTY(q) (q->size == 0) +#define AQ_FULL(q) (q->size == q->max_size) +aq_queue aq_create(void); +void aq_terminate(aq_queue q); +int aq_grow(aq_queue q); + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED) diff --git a/include/boost/wave/cpplexer/re2clex/cpp.re.hpp b/include/boost/wave/cpplexer/re2clex/cpp.re.hpp new file mode 100644 index 000000000..426d42354 --- /dev/null +++ b/include/boost/wave/cpplexer/re2clex/cpp.re.hpp @@ -0,0 +1,34 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Re2C based C++ lexer + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED) +#define CPP_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +/////////////////////////////////////////////////////////////////////////////// +// The scanner function to call whenever a new token is requested +boost::wave::token_id scan(Scanner *s); + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED) diff --git a/include/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp b/include/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp new file mode 100644 index 000000000..7e0ffc36b --- /dev/null +++ b/include/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp @@ -0,0 +1,307 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Re2C based C++ lexer + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED) +#define CPP_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED + +#include +#include +#include +#if defined(BOOST_SPIRIT_DEBUG) +#include +#endif // defined(BOOST_SPIRIT_DEBUG) + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +/////////////////////////////////////////////////////////////////////////////// +// +// encapsulation of the re2c based cpp lexer +// +/////////////////////////////////////////////////////////////////////////////// + +template +class lexer +{ +public: + + typedef char char_t; + typedef Scanner base_t; + typedef lex_token token_type; + typedef typename token_type::string_type string_type; + + lexer(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language); + ~lexer(); + + lex_token get(); + void set_position(PositionT const &pos) + { + filename = pos.get_file(); + scanner.line = pos.get_line(); + scanner.file_name = filename.c_str(); + } + +// error reporting from the re2c generated lexer + static int report_error(Scanner *s, char *, ...); + +private: + static char const *tok_names[]; + + Scanner scanner; + string_type filename; + string_type value; + bool at_eof; + + static token_cache const cache; +}; + +/////////////////////////////////////////////////////////////////////////////// +// initialize cpp lexer +template +inline +lexer::lexer(IteratorT const &first, + IteratorT const &last, PositionT const &pos, + boost::wave::language_support language) +: filename(pos.get_file()), at_eof(false) +{ + memset(&scanner, '\0', sizeof(Scanner)); + scanner.fd = -1; + scanner.eol_offsets = aq_create(); + scanner.first = scanner.act = (uchar *)&(*first); + scanner.last = scanner.first + std::distance(first, last); + scanner.line = 1; // start with line_no 1 + scanner.error_proc = report_error; + scanner.file_name = filename.c_str(); + +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + scanner.enable_ms_extensions = 1; +#else + scanner.enable_ms_extensions = 0; +#endif + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + scanner.act_in_c99_mode = boost::wave::need_c99(language); +#endif + + boost::ignore_unused_variable_warning(language); +} + +template +inline +lexer::~lexer() +{ + aq_terminate(scanner.eol_offsets); + free(scanner.bot); +} + +/////////////////////////////////////////////////////////////////////////////// +// get the next token from the input stream +template +inline lex_token +lexer::get() +{ + if (at_eof) + return lex_token(); // return T_EOI + + token_id id = token_id(scan(&scanner)); + + switch (id) { + case T_IDENTIFIER: + // test identifier characters for validity (throws if invalid chars found) + value = string_type((char const *)scanner.tok, scanner.cur-scanner.tok); + impl::validate_identifier_name(value, scanner.line, -1, filename); + break; + + case T_STRINGLIT: + case T_CHARLIT: + // test literal characters for validity (throws if invalid chars found) + value = string_type((char const *)scanner.tok, scanner.cur-scanner.tok); + impl::validate_literal(value, scanner.line, -1, filename); + break; + +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + case T_PP_HHEADER: + case T_PP_QHEADER: + case T_PP_INCLUDE: + // convert to the corresponding ..._next token, if appropriate + value = string_type((char const *)scanner.tok, scanner.cur-scanner.tok); + if (string_type::npos != value.find("include_")) + id = token_id(id | AltTokenType); + break; +#endif + + case T_OCTALINT: + case T_DECIMALINT: + case T_HEXAINT: + case T_INTLIT: + case T_FLOATLIT: + case T_FIXEDPOINTLIT: + case T_CCOMMENT: + case T_CPPCOMMENT: + case T_SPACE: + case T_SPACE2: + case T_ANY: + value = string_type((char const *)scanner.tok, scanner.cur-scanner.tok); + break; + + case T_EOF: + // T_EOF is returned as a valid token, the next call will return T_EOI, + // i.e. the actual end of input + at_eof = true; + break; + + default: + if (CATEGORY_FROM_TOKEN(id) != EXTCATEGORY_FROM_TOKEN(id) || + IS_CATEGORY(id, UnknownTokenType)) + { + value = string_type((char const *)scanner.tok, scanner.cur-scanner.tok); + } + else { + value = cache.get_token_value(id); + } + break; + } + + return lex_token(id, value, + PositionT(filename, scanner.line, -1)); +} + +template +inline int +lexer::report_error(Scanner *s, char *msg, ...) +{ + BOOST_ASSERT(0 != s); + BOOST_ASSERT(0 != msg); + + using namespace std; // some system have vsprintf in namespace std + + char buffer[200]; // should be large enough + va_list params; + va_start(params, msg); + vsprintf(buffer, msg, params); + va_end(params); + + BOOST_WAVE_LEXER_THROW(lexing_exception, generic_lexing_error, buffer, s->line, -1, + s->file_name); + return 0; // unreachable code; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_functor +// +/////////////////////////////////////////////////////////////////////////////// + +template +class lex_functor +: public lex_input_interface::token_type> +{ +public: + + typedef typename lexer::token_type token_type; + + lex_functor(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language) + : lexer(first, last, pos, language) + {} + virtual ~lex_functor() {} + +// get the next token from the input stream + token_type get() { return lexer.get(); } + void set_position(PositionT const &pos) + { lexer.set_position(pos); } + +private: + lexer lexer; +}; + +/////////////////////////////////////////////////////////////////////////////// +template +token_cache::string_type> const + lexer::cache = + token_cache::string_type>(); + +} // namespace re2clex + +/////////////////////////////////////////////////////////////////////////////// +// +// The new_lexer_gen<>::new_lexer function (declared in cpp_lex_interface.hpp) +// should be defined inline, if the lex_functor shouldn't be instantiated +// separately from the lex_iterator. +// +// Separate (explicit) instantiation helps to reduce compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 +#define BOOST_WAVE_RE2C_NEW_LEXER_INLINE +#else +#define BOOST_WAVE_RE2C_NEW_LEXER_INLINE inline +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// The 'new_lexer' function allows the opaque generation of a new lexer object. +// It is coupled to the iterator type to allow to decouple the lexer/iterator +// configurations at compile time. +// +// This function is declared inside the cpp_slex_token.hpp file, which is +// referenced by the source file calling the lexer and the source file, which +// instantiates the lex_functor. But is is defined here, so it will be +// instantiated only while compiling the source file, which instantiates the +// lex_functor. While the cpp_re2c_token.hpp file may be included everywhere, +// this file (cpp_re2c_lexer.hpp) should be included only once. This allows +// to decouple the lexer interface from the lexer implementation and reduces +// compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +template +BOOST_WAVE_RE2C_NEW_LEXER_INLINE +lex_input_interface > * +new_lexer_gen::new_lexer(IteratorT const &first, + IteratorT const &last, PositionT const &pos, + boost::wave::language_support language) +{ + return new re2clex::lex_functor(first, last, pos, + language); +} + +#undef BOOST_WAVE_RE2C_NEW_LEXER_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED) diff --git a/include/boost/wave/cpplexer/re2clex/scanner.hpp b/include/boost/wave/cpplexer/re2clex/scanner.hpp new file mode 100644 index 000000000..46b4bf5ef --- /dev/null +++ b/include/boost/wave/cpplexer/re2clex/scanner.hpp @@ -0,0 +1,58 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001 Daniel C. Nuffer. + Copyright (c) 2001-2005 Hartmut Kaiser. + 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) +=============================================================================*/ + +#if !defined(SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED) +#define SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +struct Scanner; +typedef unsigned char uchar; +typedef int (* ReportErrorProc)(struct Scanner *, char *, ...); + +typedef struct Scanner { + int fd; /* file descriptor */ + uchar* first; /* start of input buffer (if fd == -1) */ + uchar* act; /* act position of input buffer (if fd == -1) */ + uchar* last; /* end (one past last char) of input buffer (if fd == -1) */ + uchar* bot; /* beginning of the current buffer */ + uchar* top; /* top of the current buffer */ + uchar* eof; /* when we read in the last buffer, will point 1 past the + end of the file, otherwise 0 */ + uchar* tok; /* points to the beginning of the current token */ + uchar* ptr; /* used for YYMARKER - saves backtracking info */ + uchar* cur; /* saves the cursor (maybe is redundant with tok?) */ + uchar* lim; /* used for YYLIMIT - points to the end of the buffer */ + /* (lim == top) except for the last buffer, it points to + the end of the input (lim == eof - 1) */ + unsigned int line; /* current line being lexed */ + ReportErrorProc error_proc; /* if != 0 this function is called to + report an error */ + char const *file_name; /* name of the lexed file */ + aq_queue eol_offsets; + int enable_ms_extensions; /* enable MS extensions */ + int act_in_c99_mode; /* lexer works in C99 mode */ + int act_in_cpp0x_mode; /* lexer works in C++0x mode */ +} Scanner; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED) diff --git a/include/boost/wave/cpplexer/token_cache.hpp b/include/boost/wave/cpplexer/token_cache.hpp new file mode 100644 index 000000000..d5f1ab720 --- /dev/null +++ b/include/boost/wave/cpplexer/token_cache.hpp @@ -0,0 +1,60 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED) +#define TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +/////////////////////////////////////////////////////////////////////////////// +// +// The token_cache template is used to cache the tokens corresponding to the +// keywords, operators and other constant language elements. +// +// This avoids repeated construction of these tokens, which is especially +// effective when used in conjunction with a copy on write string +// implementation (COW string). +// +/////////////////////////////////////////////////////////////////////////////// +template +class token_cache +{ +public: + token_cache() + : cache(T_LAST_TOKEN - T_FIRST_TOKEN) + { + typename std::vector::iterator it = cache.begin(); + typename std::vector::iterator end = cache.end(); + for (unsigned int i = T_FIRST_TOKEN; i < T_LAST_TOKEN; ++i, ++it) + { + *it = StringT(boost::wave::get_token_value(token_id(i))); + } + } + + StringT const &get_token_value(token_id id) const + { + return cache[BASEID_FROM_TOKEN(id) - T_FIRST_TOKEN]; + } + +private: + std::vector cache; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED) diff --git a/include/boost/wave/cpplexer/validate_universal_char.hpp b/include/boost/wave/cpplexer/validate_universal_char.hpp new file mode 100644 index 000000000..597abb959 --- /dev/null +++ b/include/boost/wave/cpplexer/validate_universal_char.hpp @@ -0,0 +1,314 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Grammar for universal character validation (see C++ standard: Annex E) + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ +#if !defined(VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED) +#define VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED + +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace impl { + +enum universal_char_type { + universal_char_type_valid = 0, + universal_char_type_invalid = 1, + universal_char_type_base_charset = 2, + universal_char_type_not_allowed_for_identifiers = 3, +}; + +namespace { + + /////////////////////////////////////////////////////////////////////////// + // + // is_range is a helper function for the classification by brute force + // below + // + /////////////////////////////////////////////////////////////////////////// + inline bool + in_range(unsigned long ch, unsigned long l, unsigned long u) + { + return (l <= ch && ch <= u); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// classify_universal_char +// +// This function classifies an universal character value into 4 subranges: +// universal_char_type_valid +// the universal character value is valid for identifiers +// universal_char_type_invalid +// the universal character value is not valid for its usage inside +// identifiers (see C++ Standard: 2.2.2 [lex.charset]) +// universal_char_type_base_charset +// the universal character value designates a character from the base +// character set +// universal_char_type_not_allowed_for_identifiers +// the universal character value is not allowed in an identifier +// +// Implementation note: +// This classification isn't implemented very effectively here. This +// function should be rewritten with some range run matching algorithm. +// +/////////////////////////////////////////////////////////////////////////////// +inline universal_char_type +classify_universal_char (unsigned long ch) +{ +// test for invalid characters + if (ch <= 0x0020 || in_range(ch, 0x007f, 0x009f)) + return universal_char_type_invalid; + +// test for characters in the range of the base character set + if (in_range(ch, 0x0021, 0x005f) || in_range(ch, 0x0061, 0x007e)) + return universal_char_type_base_charset; + +// test for additional valid character values (see C++ Standard: Annex E) + if (in_range(ch, 0x00c0, 0x00d6) || in_range(ch, 0x00d8, 0x00f6) || + in_range(ch, 0x00f8, 0x01f5) || in_range(ch, 0x01fa, 0x0217) || + in_range(ch, 0x0250, 0x02a8) || in_range(ch, 0x1e00, 0x1e9a) || + in_range(ch, 0x1ea0, 0x1ef9)) + { + return universal_char_type_valid; // Latin + } + + if (0x0384 == ch || in_range(ch, 0x0388, 0x038a) || + 0x038c == ch || in_range(ch, 0x038e, 0x03a1) || + in_range(ch, 0x03a3, 0x03ce) || in_range(ch, 0x03d0, 0x03d6) || + 0x03da == ch || 0x03dc == ch || 0x03de == ch || 0x03e0 == ch || + in_range(ch, 0x03e2, 0x03f3) || in_range(ch, 0x1f00, 0x1f15) || + in_range(ch, 0x1f18, 0x1f1d) || in_range(ch, 0x1f20, 0x1f45) || + in_range(ch, 0x1f48, 0x1f4d) || in_range(ch, 0x1f50, 0x1f57) || + 0x1f59 == ch || 0x1f5b == ch || 0x1f5d == ch || + in_range(ch, 0x1f5f, 0x1f7d) || in_range(ch, 0x1f80, 0x1fb4) || + in_range(ch, 0x1fb6, 0x1fbc) || in_range(ch, 0x1fc2, 0x1fc4) || + in_range(ch, 0x1fc6, 0x1fcc) || in_range(ch, 0x1fd0, 0x1fd3) || + in_range(ch, 0x1fd6, 0x1fdb) || in_range(ch, 0x1fe0, 0x1fec) || + in_range(ch, 0x1ff2, 0x1ff4) || in_range(ch, 0x1ff6, 0x1ffc)) + { + return universal_char_type_valid; // Greek + } + + if (in_range(ch, 0x0401, 0x040d) || in_range(ch, 0x040f, 0x044f) || + in_range(ch, 0x0451, 0x045c) || in_range(ch, 0x045e, 0x0481) || + in_range(ch, 0x0490, 0x04c4) || in_range(ch, 0x04c7, 0x04c8) || + in_range(ch, 0x04cb, 0x04cc) || in_range(ch, 0x04d0, 0x04eb) || + in_range(ch, 0x04ee, 0x04f5) || in_range(ch, 0x04f8, 0x04f9)) + { + return universal_char_type_valid; // Cyrillic + } + + if (in_range(ch, 0x0531, 0x0556) || in_range(ch, 0x0561, 0x0587)) + return universal_char_type_valid; // Armenian + + if (in_range(ch, 0x05d0, 0x05ea) || in_range(ch, 0x05f0, 0x05f4)) + return universal_char_type_valid; // Hebrew + + if (in_range(ch, 0x0621, 0x063a) || in_range(ch, 0x0640, 0x0652) || + in_range(ch, 0x0670, 0x06b7) || in_range(ch, 0x06ba, 0x06be) || + in_range(ch, 0x06c0, 0x06ce) || in_range(ch, 0x06e5, 0x06e7)) + { + return universal_char_type_valid; // Arabic + } + + if (in_range(ch, 0x0905, 0x0939) || in_range(ch, 0x0958, 0x0962)) + return universal_char_type_valid; // Devanagari + + if (in_range(ch, 0x0985, 0x098c) || in_range(ch, 0x098f, 0x0990) || + in_range(ch, 0x0993, 0x09a8) || in_range(ch, 0x09aa, 0x09b0) || + 0x09b2 == ch || in_range(ch, 0x09b6, 0x09b9) || + in_range(ch, 0x09dc, 0x09dd) || in_range(ch, 0x09df, 0x09e1) || + in_range(ch, 0x09f0, 0x09f1)) + { + return universal_char_type_valid; // Bengali + } + + if (in_range(ch, 0x0a05, 0x0a0a) || in_range(ch, 0x0a0f, 0x0a10) || + in_range(ch, 0x0a13, 0x0a28) || in_range(ch, 0x0a2a, 0x0a30) || + in_range(ch, 0x0a32, 0x0a33) || in_range(ch, 0x0a35, 0x0a36) || + in_range(ch, 0x0a38, 0x0a39) || in_range(ch, 0x0a59, 0x0a5c) || + 0x0a5e == ch) + { + return universal_char_type_valid; // Gurmukhi + } + + if (in_range(ch, 0x0a85, 0x0a8b) || 0x0a8d == ch || + in_range(ch, 0x0a8f, 0x0a91) || in_range(ch, 0x0a93, 0x0aa8) || + in_range(ch, 0x0aaa, 0x0ab0) || in_range(ch, 0x0ab2, 0x0ab3) || + in_range(ch, 0x0ab5, 0x0ab9) || 0x0ae0 == ch) + { + return universal_char_type_valid; // Gujarati + } + + if (in_range(ch, 0x0b05, 0x0b0c) || in_range(ch, 0x0b0f, 0x0b10) || + in_range(ch, 0x0b13, 0x0b28) || in_range(ch, 0x0b2a, 0x0b30) || + in_range(ch, 0x0b32, 0x0b33) || in_range(ch, 0x0b36, 0x0b39) || + in_range(ch, 0x0b5c, 0x0b5d) || in_range(ch, 0x0b5f, 0x0b61)) + { + return universal_char_type_valid; // Oriya + } + + if (in_range(ch, 0x0b85, 0x0b8a) || in_range(ch, 0x0b8e, 0x0b90) || + in_range(ch, 0x0b92, 0x0b95) || in_range(ch, 0x0b99, 0x0b9a) || + 0x0b9c == ch || in_range(ch, 0x0b9e, 0x0b9f) || + in_range(ch, 0x0ba3, 0x0ba4) || in_range(ch, 0x0ba8, 0x0baa) || + in_range(ch, 0x0bae, 0x0bb5) || in_range(ch, 0x0bb7, 0x0bb9)) + { + return universal_char_type_valid; // Tamil + } + + if (in_range(ch, 0x0c05, 0x0c0c) || in_range(ch, 0x0c0e, 0x0c10) || + in_range(ch, 0x0c12, 0x0c28) || in_range(ch, 0x0c2a, 0x0c33) || + in_range(ch, 0x0c35, 0x0c39) || in_range(ch, 0x0c60, 0x0c61)) + { + return universal_char_type_valid; // Telugu + } + + if (in_range(ch, 0x0c85, 0x0c8c) || in_range(ch, 0x0c8e, 0x0c90) || + in_range(ch, 0x0c92, 0x0ca8) || in_range(ch, 0x0caa, 0x0cb3) || + in_range(ch, 0x0cb5, 0x0cb9) || in_range(ch, 0x0ce0, 0x0ce1)) + { + return universal_char_type_valid; // Kannada + } + + if (in_range(ch, 0x0d05, 0x0d0c) || in_range(ch, 0x0d0e, 0x0d10) || + in_range(ch, 0x0d12, 0x0d28) || in_range(ch, 0x0d2a, 0x0d39) || + in_range(ch, 0x0d60, 0x0d61)) + { + return universal_char_type_valid; // Malayalam + } + + if (in_range(ch, 0x0e01, 0x0e30) || in_range(ch, 0x0e32, 0x0e33) || + in_range(ch, 0x0e40, 0x0e46) || in_range(ch, 0x0e4f, 0x0e5b)) + { + return universal_char_type_valid; // Thai + } + + return universal_char_type_not_allowed_for_identifiers; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// validate_identifier_name +// +// The validate_identifier_name function tests a given identifier name for +// its validity with regard to eventually contained universal characters. +// These should be in valid ranges (see the function +// classify_universal_char above). +// +// If the identifier name contains invalid or not allowed universal +// characters a corresponding lexing_exception is thrown. +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +validate_identifier_name (StringT const &name, int line, int column, + StringT const &file_name) +{ + using namespace std; // some systems have strtoul in namespace std:: + +typename StringT::size_type pos = name.find_first_of('\\'); + + while (StringT::npos != pos) { + // the identifier name contains a backslash (must be universal char) + BOOST_SPIRIT_ASSERT('u' == name[pos+1] || 'U' == name[pos+1]); + + StringT uchar_val(name.substr(pos+2, ('u' == name[pos+1]) ? 4 : 8)); + universal_char_type type = + classify_universal_char(strtoul(uchar_val.c_str(), 0, 16)); + + if (universal_char_type_valid != type) { + // an invalid char was found, so throw an exception + StringT error_uchar(name.substr(pos, ('u' == name[pos+1]) ? 6 : 10)); + + if (universal_char_type_invalid == type) { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_invalid, + error_uchar, line, column, file_name.c_str()); + } + else if (universal_char_type_base_charset == type) { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_base_charset, + error_uchar, line, column, file_name.c_str()); + } + else { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_not_allowed, + error_uchar, line, column, file_name.c_str()); + } + } + + // find next universal char (if appropriate) + pos = name.find_first_of('\\', pos+2); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// validate_literal +// +// The validate_literal function tests a given string or character literal +// for its validity with regard to eventually contained universal +// characters. These should be in valid ranges (see the function +// classify_universal_char above). +// +// If the string or character literal contains invalid or not allowed +// universal characters a corresponding lexing_exception is thrown. +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +validate_literal (StringT const &name, int line, int column, + StringT const &file_name) +{ + using namespace std; // some systems have strtoul in namespace std:: + +typename StringT::size_type pos = name.find_first_of('\\'); + + while (StringT::npos != pos) { + // the literal contains a backslash (may be universal char) + if ('u' == name[pos+1] || 'U' == name[pos+1]) { + StringT uchar_val(name.substr(pos+2, ('u' == name[pos+1]) ? 4 : 8)); + universal_char_type type = + classify_universal_char(strtoul(uchar_val.c_str(), 0, 16)); + + if (universal_char_type_valid != type && + universal_char_type_not_allowed_for_identifiers != type) + { + // an invalid char was found, so throw an exception + StringT error_uchar(name.substr(pos, ('u' == name[pos+1]) ? 6 : 10)); + + if (universal_char_type_invalid == type) { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_invalid, + error_uchar, line, column, file_name.c_str()); + } + else { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_base_charset, + error_uchar, line, column, file_name.c_str()); + } + } + } + + // find next universal char (if appropriate) + pos = name.find_first_of('\\', pos+2); + } +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_chlit_grammar.hpp b/include/boost/wave/grammars/cpp_chlit_grammar.hpp new file mode 100644 index 000000000..fd304ae43 --- /dev/null +++ b/include/boost/wave/grammars/cpp_chlit_grammar.hpp @@ -0,0 +1,229 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED) +#define CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Reusable grammar to parse a C++ style character literal +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +namespace closures { + + struct chlit_closure + : boost::spirit::closure + { + member1 value; + }; +} + +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// compose a multibyte character literal +// +/////////////////////////////////////////////////////////////////////////////// + struct compose_character_literal { + + template + struct result { + + typedef unsigned int type; + }; + + unsigned int + operator()(unsigned int res, unsigned int character) const + { + unsigned int retval = (res << 8) | (character & 0xff); + return retval; + } + }; + phoenix::function const compose; + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CHLIT_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR) \ + /**/ + +struct chlit_grammar : + public boost::spirit::grammar +{ + chlit_grammar() + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "chlit_grammar", + TRACE_CHLIT_GRAMMAR); + } + + template + struct definition + { + typedef + boost::spirit::rule + rule_t; + + rule_t ch_lit; + + definition(chlit_grammar const &self) + { + using namespace boost::spirit; + using namespace phoenix; + + ch_lit + = !ch_p('L') + >> ch_p('\'')[self.value = val(0)] + >> +( ( + ch_p('\\') + >> ( ch_p('a') // BEL + [ + self.value = impl::compose(self.value, val(0x07)) + ] + | ch_p('b') // BS + [ + self.value = impl::compose(self.value, val(0x08)) + ] + | ch_p('t') // HT + [ + self.value = impl::compose(self.value, val(0x09)) + ] + | ch_p('n') // NL + [ + self.value = impl::compose(self.value, val(0x0a)) + ] + | ch_p('v') // VT + [ + self.value = impl::compose(self.value, val(0x0b)) + ] + | ch_p('f') // FF + [ + self.value = impl::compose(self.value, val(0x0c)) + ] + | ch_p('r') // CR + [ + self.value = impl::compose(self.value, val(0x0d)) + ] + | ch_p('?') + [ + self.value = impl::compose(self.value, val('?')) + ] + | ch_p('\'') + [ + self.value = impl::compose(self.value, val('\'')) + ] + | ch_p('\"') + [ + self.value = impl::compose(self.value, val('\"')) + ] + | ch_p('\\') + [ + self.value = impl::compose(self.value, val('\\')) + ] + | ch_p('x') + >> uint_parser() + [ + self.value = impl::compose(self.value, arg1) + ] + | ch_p('u') + >> uint_parser() + [ + self.value = impl::compose(self.value, arg1) + ] + | ch_p('U') + >> uint_parser() + [ + self.value = impl::compose(self.value, arg1) + ] + | uint_parser() + [ + self.value = impl::compose(self.value, arg1) + ] + ) + ) + | ~eps_p(ch_p('\'')) >> anychar_p + [ + self.value = impl::compose(self.value, arg1) + ] + ) + >> ch_p('\'') + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(ch_lit, TRACE_CHLIT_GRAMMAR); + } + + // start rule of this grammar + rule_t const& start() const + { return ch_lit; } + }; +}; + +#undef TRACE_CHLIT_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following function is defined here, to allow the separation of +// the compilation of the intlit_grammap from the function using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE inline +#endif + +template +BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE +unsigned int +chlit_grammar_gen::evaluate(TokenT const &token) +{ + using namespace boost::spirit; + +static chlit_grammar g; +unsigned int result = 0; +typename TokenT::string_type const &token_val = token.get_value(); +parse_info hit = + parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]); + + if (!hit.hit) { + BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, + token_val, token.get_position()); + } + return result; +} + +#undef BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_defined_grammar.hpp b/include/boost/wave/grammars/cpp_defined_grammar.hpp new file mode 100644 index 000000000..9c407f88a --- /dev/null +++ b/include/boost/wave/grammars/cpp_defined_grammar.hpp @@ -0,0 +1,172 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED) +#define CPP_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED + +#include +#include +#include +#if SPIRIT_VERSION >= 0x1700 +#include +#include +#endif // SPIRIT_VERSION >= 0x1700 + +#include +#include +#include +#include + +#if !defined(spirit_append_actor) +#if SPIRIT_VERSION >= 0x1700 +#define spirit_append_actor(actor) boost::spirit::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::assign_a(actor) +#else +#define spirit_append_actor(actor) boost::spirit::append(actor) +#define spirit_assign_actor(actor) boost::spirit::assign(actor) +#endif // SPIRIT_VERSION >= 0x1700 +#endif // !defined(spirit_append_actor) + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CPP_DEFINED_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR) \ + /**/ + +template +struct defined_grammar : + public boost::spirit::grammar > +{ + defined_grammar(ContainerT &result_seq_) + : result_seq(result_seq_) + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "defined_grammar", + TRACE_CPP_DEFINED_GRAMMAR); + } + + template + struct definition + { + typedef boost::spirit::rule rule_t; + + rule_t defined_op; + rule_t identifier; + + definition(defined_grammar const &self) + { + using namespace boost::spirit; + using namespace boost::wave; + using namespace boost::wave::util; + + defined_op // parens not required, see C++ standard 16.1.1 + = ch_p(T_IDENTIFIER) // token contains 'defined' + >> ( + ( ch_p(T_LEFTPAREN) + >> identifier + >> ch_p(T_RIGHTPAREN) + ) + | identifier + ) + ; + + identifier + = ch_p(T_IDENTIFIER) + [ + spirit_append_actor(self.result_seq) + ] + | pattern_p(KeywordTokenType, TokenTypeMask) + [ + spirit_append_actor(self.result_seq) + ] + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(defined_op, TRACE_CPP_DEFINED_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(identifier, TRACE_CPP_DEFINED_GRAMMAR); + } + + // start rule of this grammar + rule_t const& start() const + { return defined_op; } + }; + + ContainerT &result_seq; +}; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_CPP_DEFINED_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following parse function is defined here, to allow the separation of +// the compilation of the defined_grammar from the function +// using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE inline +#endif + +// The parse_operator_define function is instantiated manually twice to +// simplify the explicit specialization of this template. This way the user +// has only to specify one template parameter (the lexer type) to correctly +// formulate the required explicit specialization. +// This results in no code overhead, because otherwise the function would be +// generated by the compiler twice anyway. + +template +BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE +boost::spirit::parse_info< + typename defined_grammar_gen::iterator1_t +> +defined_grammar_gen::parse_operator_defined ( + iterator1_t const &first, iterator1_t const &last, + token_sequence_type &found_qualified_name) +{ + using namespace boost::spirit; + using namespace boost::wave; + + defined_grammar g(found_qualified_name); + return boost::spirit::parse ( + first, last, g, ch_p(T_SPACE) | ch_p(T_CCOMMENT)); +} + +template +BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE +boost::spirit::parse_info< + typename defined_grammar_gen::iterator2_t +> +defined_grammar_gen::parse_operator_defined ( + iterator2_t const &first, iterator2_t const &last, + token_sequence_type &found_qualified_name) +{ + using namespace boost::spirit; + using namespace boost::wave; + + defined_grammar g(found_qualified_name); + return boost::spirit::parse ( + first, last, g, ch_p(T_SPACE) | ch_p(T_CCOMMENT)); +} + +#undef BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_defined_grammar_gen.hpp b/include/boost/wave/grammars/cpp_defined_grammar_gen.hpp new file mode 100644 index 000000000..8af34745d --- /dev/null +++ b/include/boost/wave/grammars/cpp_defined_grammar_gen.hpp @@ -0,0 +1,63 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED) +#define CPP_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED + +#include + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +template +struct defined_grammar_gen +{ + typedef typename LexIteratorT::token_type token_type; + typedef std::list > + token_sequence_type; + +// The parse_operator_define function is instantiated manually twice to +// simplify the explicit specialization of this template. This way the user +// has only to specify one template parameter (the lexer iterator type) to +// correctly formulate the required explicit specialization. +// This results in no code overhead, because otherwise the function would be +// generated by the compiler twice anyway. + + typedef boost::wave::util::unput_queue_iterator< + typename token_sequence_type::iterator, token_type, token_sequence_type> + iterator1_t; + + typedef boost::wave::util::unput_queue_iterator< + LexIteratorT, token_type, token_sequence_type> + iterator2_t; + +// parse the operator defined and return the found qualified name + static boost::spirit::parse_info + parse_operator_defined (iterator1_t const &first, iterator1_t const &last, + token_sequence_type &found_qualified_name); + + static boost::spirit::parse_info + parse_operator_defined (iterator2_t const &first, iterator2_t const &last, + token_sequence_type &found_qualified_name); +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_expression_grammar.hpp b/include/boost/wave/grammars/cpp_expression_grammar.hpp new file mode 100644 index 000000000..0fb2d6190 --- /dev/null +++ b/include/boost/wave/grammars/cpp_expression_grammar.hpp @@ -0,0 +1,710 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED) +#define CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED + +#include +#include +#include +#include +#if SPIRIT_VERSION >= 0x1700 +#include +#include +#endif // SPIRIT_VERSION >= 0x1700 + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#if !defined(spirit_append_actor) +#if SPIRIT_VERSION >= 0x1700 +#define spirit_append_actor(actor) boost::spirit::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::assign_a(actor) +#else +#define spirit_append_actor(actor) boost::spirit::append(actor) +#define spirit_assign_actor(actor) boost::spirit::assign(actor) +#endif // SPIRIT_VERSION >= 0x1700 +#endif // !defined(spirit_append_actor) + +/////////////////////////////////////////////////////////////////////////////// +// +// Encapsulation of the grammar for evaluation of constant preprocessor +// expressions +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { +namespace closures { + +/////////////////////////////////////////////////////////////////////////////// +// +// define the closure type used throughout the C++ expression grammar +// +// Throughout this grammar all literal tokens are stored into a +// closure_value variables, which converts the types appropriately, where +// required. +// +/////////////////////////////////////////////////////////////////////////////// + struct cpp_expr_closure + : boost::spirit::closure + { + member1 val; + }; + +} // namespace closures + +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// convert the given tokenvalue (integer literal) to a unsigned long +// +/////////////////////////////////////////////////////////////////////////////// + struct convert_intlit { + + template + struct result { + + typedef boost::wave::grammars::closures::closure_value type; + }; + + template + boost::wave::grammars::closures::closure_value + operator()(TokenT const &token) const + { + typedef boost::wave::grammars::closures::closure_value return_t; + bool is_unsigned = false; + unsigned long ul = intlit_grammar_gen::evaluate(token, + is_unsigned); + + return is_unsigned ? return_t(ul) : return_t(static_cast(ul)); + } + }; + phoenix::function const as_intlit; + +/////////////////////////////////////////////////////////////////////////////// +// +// convert the given tokenvalue (character literal) to a unsigned int +// +/////////////////////////////////////////////////////////////////////////////// + struct convert_chlit { + + template + struct result { + + typedef boost::wave::grammars::closures::closure_value type; + }; + + template + boost::wave::grammars::closures::closure_value + operator()(TokenT const &token) const + { + typedef boost::wave::grammars::closures::closure_value return_t; + return return_t(chlit_grammar_gen::evaluate(token)); + } + }; + phoenix::function const as_chlit; + +//////////////////////////////////////////////////////////////////////////////// +// +// Handle the ?: operator with correct type propagation +// +//////////////////////////////////////////////////////////////////////////////// + struct operator_questionmark { + + template + struct result { + + typedef boost::wave::grammars::closures::closure_value type; + }; + + template + boost::wave::grammars::closures::closure_value + operator()(CondT const &cond, Arg1T &val1, Arg2T const &val2) const + { + typedef boost::wave::grammars::closures::closure_value return_t; + return return_t(val1.handle_questionmark(cond, val2)); + } + }; + phoenix::function const questionmark; + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CPP_EXPR_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR) \ + /**/ + +struct expression_grammar : + public boost::spirit::grammar< + expression_grammar, + closures::cpp_expr_closure::context_t + > +{ + expression_grammar() + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "expression_grammar", + TRACE_CPP_EXPR_GRAMMAR); + } + + template + struct definition + { + typedef closures::cpp_expr_closure closure_type; + typedef boost::spirit::rule rule_t; + typedef boost::spirit::rule simple_rule_t; + + simple_rule_t pp_expression; + + rule_t const_exp; + rule_t logical_or_exp, logical_and_exp; + rule_t inclusive_or_exp, exclusive_or_exp, and_exp; + rule_t cmp_equality, cmp_relational; + rule_t shift_exp; + rule_t add_exp, multiply_exp; + rule_t unary_exp, primary_exp, constant; + + rule_t const_exp_nocalc; + rule_t logical_or_exp_nocalc, logical_and_exp_nocalc; + rule_t inclusive_or_exp_nocalc, exclusive_or_exp_nocalc, and_exp_nocalc; + rule_t cmp_equality_nocalc, cmp_relational_nocalc; + rule_t shift_exp_nocalc; + rule_t add_exp_nocalc, multiply_exp_nocalc; + rule_t unary_exp_nocalc, primary_exp_nocalc, constant_nocalc; + + boost::spirit::subrule<0, closure_type::context_t> const_exp_subrule; + + definition(expression_grammar const &self) + { + using namespace boost::spirit; + using namespace phoenix; + using namespace boost::wave; + using boost::wave::util::pattern_p; + + pp_expression + = const_exp[self.val = arg1] + ; + + const_exp + = logical_or_exp[const_exp.val = arg1] + >> !(const_exp_subrule = + ch_p(T_QUESTION_MARK) + >> const_exp + [ + const_exp_subrule.val = arg1 + ] + >> ch_p(T_COLON) + >> const_exp + [ + const_exp_subrule.val = + impl::questionmark(const_exp.val, + const_exp_subrule.val, arg1) + ] + )[const_exp.val = arg1] + ; + + logical_or_exp + = logical_and_exp[logical_or_exp.val = arg1] + >> *( if_p(static_cast_(logical_or_exp.val)) + [ + // if one of the || operators is true, no more + // evaluation is required + pattern_p(T_OROR, MainTokenMask) + >> logical_and_exp_nocalc + [ + logical_or_exp.val = + static_cast_(logical_or_exp.val) + ] + ] + .else_p + [ + pattern_p(T_OROR, MainTokenMask) + >> logical_and_exp + [ + logical_or_exp.val = + logical_or_exp.val || arg1 + ] + ] + ) + ; + + logical_and_exp + = inclusive_or_exp[logical_and_exp.val = arg1] + >> *( if_p(static_cast_(logical_and_exp.val)) + [ + pattern_p(T_ANDAND, MainTokenMask) + >> inclusive_or_exp + [ + logical_and_exp.val = + logical_and_exp.val && arg1 + ] + ] + .else_p + [ + // if one of the && operators is false, no more + // evaluation is required + pattern_p(T_ANDAND, MainTokenMask) + >> inclusive_or_exp_nocalc + [ + logical_and_exp.val = + static_cast_(logical_and_exp.val) + ] + ] + ) + ; + + inclusive_or_exp + = exclusive_or_exp[inclusive_or_exp.val = arg1] + >> *( pattern_p(T_OR, MainTokenMask) + >> exclusive_or_exp + [ + inclusive_or_exp.val = + static_cast_(inclusive_or_exp.val) + | static_cast_(arg1) + ] + ) + ; + + exclusive_or_exp + = and_exp[exclusive_or_exp.val = arg1] + >> *( pattern_p(T_XOR, MainTokenMask) + >> and_exp + [ + exclusive_or_exp.val = + static_cast_(exclusive_or_exp.val) + ^ static_cast_(arg1) + ] + ) + ; + + and_exp + = cmp_equality[and_exp.val = arg1] + >> *( pattern_p(T_AND, MainTokenMask) + >> cmp_equality + [ + and_exp.val = + static_cast_(and_exp.val) + & static_cast_(arg1) + ] + ) + ; + + cmp_equality + = cmp_relational[cmp_equality.val = arg1] + >> *( ch_p(T_EQUAL) + >> cmp_relational + [ + cmp_equality.val = + cmp_equality.val == arg1 + ] + | pattern_p(T_NOTEQUAL, MainTokenMask) + >> cmp_relational + [ + cmp_equality.val = + cmp_equality.val != arg1 + ] + ) + ; + + cmp_relational + = shift_exp[cmp_relational.val = arg1] + >> *( ch_p(T_LESSEQUAL) + >> shift_exp + [ + cmp_relational.val = + cmp_relational.val <= arg1 + ] + | ch_p(T_GREATEREQUAL) + >> shift_exp + [ + cmp_relational.val = + cmp_relational.val >= arg1 + ] + | ch_p(T_LESS) + >> shift_exp + [ + cmp_relational.val = + cmp_relational.val < arg1 + ] + | ch_p(T_GREATER) + >> shift_exp + [ + cmp_relational.val = + cmp_relational.val > arg1 + ] + ) + ; + + shift_exp + = add_exp[shift_exp.val = arg1] + >> *( ch_p(T_SHIFTLEFT) + >> add_exp + [ + shift_exp.val <<= arg1 + ] + | ch_p(T_SHIFTRIGHT) + >> add_exp + [ + shift_exp.val >>= arg1 + ] + ) + ; + + add_exp + = multiply_exp[add_exp.val = arg1] + >> *( ch_p(T_PLUS) + >> multiply_exp + [ + add_exp.val += arg1 + ] + | ch_p(T_MINUS) + >> multiply_exp + [ + add_exp.val -= arg1 + ] + ) + ; + + multiply_exp + = unary_exp[multiply_exp.val = arg1] + >> *( ch_p(T_STAR) + >> unary_exp + [ + multiply_exp.val *= arg1 + ] + | ch_p(T_DIVIDE) + >> unary_exp + [ + multiply_exp.val /= arg1 + ] + | ch_p(T_PERCENT) + >> unary_exp + [ + multiply_exp.val = + static_cast_(multiply_exp.val) + % static_cast_(arg1) + ] + ) + ; + + unary_exp + = primary_exp[unary_exp.val = arg1] + | ch_p(T_PLUS) >> unary_exp + [ + unary_exp.val = static_cast_(arg1) + ] + | ch_p(T_MINUS) >> unary_exp + [ + unary_exp.val = -static_cast_(arg1) + ] + | pattern_p(T_COMPL, MainTokenMask) >> unary_exp + [ + unary_exp.val = ~static_cast_(arg1) + ] + | pattern_p(T_NOT, MainTokenMask) >> unary_exp + [ + unary_exp.val = !static_cast_(arg1) + ] + ; + + primary_exp + = constant[primary_exp.val = arg1] + | ch_p(T_LEFTPAREN) + >> const_exp[primary_exp.val = arg1] + >> ch_p(T_RIGHTPAREN) + ; + + constant + = ch_p(T_INTLIT) + [ + constant.val = impl::as_intlit(arg1) + ] + | ch_p(T_CHARLIT) + [ + constant.val = impl::as_chlit(arg1) + ] + ; + + // here follows the same grammar, but without any embedded + // calculations + const_exp_nocalc + = logical_or_exp_nocalc + >> !( ch_p(T_QUESTION_MARK) + >> const_exp_nocalc + >> ch_p(T_COLON) + >> const_exp_nocalc + ) + ; + + logical_or_exp_nocalc + = logical_and_exp_nocalc + >> *( pattern_p(T_OROR, MainTokenMask) + >> logical_and_exp_nocalc + ) + ; + + logical_and_exp_nocalc + = inclusive_or_exp_nocalc + >> *( pattern_p(T_ANDAND, MainTokenMask) + >> inclusive_or_exp_nocalc + ) + ; + + inclusive_or_exp_nocalc + = exclusive_or_exp_nocalc + >> *( pattern_p(T_OR, MainTokenMask) + >> exclusive_or_exp_nocalc + ) + ; + + exclusive_or_exp_nocalc + = and_exp_nocalc + >> *( pattern_p(T_XOR, MainTokenMask) + >> and_exp_nocalc + ) + ; + + and_exp_nocalc + = cmp_equality_nocalc + >> *( pattern_p(T_AND, MainTokenMask) + >> cmp_equality_nocalc + ) + ; + + cmp_equality_nocalc + = cmp_relational_nocalc + >> *( ch_p(T_EQUAL) + >> cmp_relational_nocalc + | pattern_p(T_NOTEQUAL, MainTokenMask) + >> cmp_relational_nocalc + ) + ; + + cmp_relational_nocalc + = shift_exp_nocalc + >> *( ch_p(T_LESSEQUAL) + >> shift_exp_nocalc + | ch_p(T_GREATEREQUAL) + >> shift_exp_nocalc + | ch_p(T_LESS) + >> shift_exp_nocalc + | ch_p(T_GREATER) + >> shift_exp_nocalc + ) + ; + + shift_exp_nocalc + = add_exp_nocalc + >> *( ch_p(T_SHIFTLEFT) + >> add_exp_nocalc + | ch_p(T_SHIFTRIGHT) + >> add_exp_nocalc + ) + ; + + add_exp_nocalc + = multiply_exp_nocalc + >> *( ch_p(T_PLUS) + >> multiply_exp_nocalc + | ch_p(T_MINUS) + >> multiply_exp_nocalc + ) + ; + + multiply_exp_nocalc + = unary_exp_nocalc + >> *( ch_p(T_STAR) + >> unary_exp_nocalc + | ch_p(T_DIVIDE) + >> unary_exp_nocalc + | ch_p(T_PERCENT) + >> unary_exp_nocalc + ) + ; + + unary_exp_nocalc + = primary_exp_nocalc + | ch_p(T_PLUS) >> unary_exp_nocalc + | ch_p(T_MINUS) >> unary_exp_nocalc + | pattern_p(T_COMPL, MainTokenMask) >> unary_exp_nocalc + | pattern_p(T_NOT, MainTokenMask) >> unary_exp_nocalc + ; + + primary_exp_nocalc + = constant_nocalc + | ch_p(T_LEFTPAREN) + >> const_exp_nocalc + >> ch_p(T_RIGHTPAREN) + ; + + constant_nocalc + = ch_p(T_INTLIT) + | ch_p(T_CHARLIT) + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_expression, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_or_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_and_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(inclusive_or_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(exclusive_or_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(and_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_equality, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_relational, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(shift_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(add_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(multiply_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(unary_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(primary_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(constant, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp_subrule, TRACE_CPP_EXPR_GRAMMAR); + + BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_and_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(inclusive_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(exclusive_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(and_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_equality_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_relational_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(shift_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(add_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(multiply_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(unary_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(primary_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(constant_nocalc, TRACE_CPP_EXPR_GRAMMAR); + } + + // start rule of this grammar + simple_rule_t const& start() const + { return pp_expression; } + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_CPP_EXPR_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following function is defined here, to allow the separation of +// the compilation of the expression_grammar from the function using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE inline +#endif + +template +BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE +bool +expression_grammar_gen::evaluate( + typename token_sequence_type::const_iterator const &first, + typename token_sequence_type::const_iterator const &last, + typename token_type::position_type const &act_pos, + bool if_block_status) +{ + using namespace boost::spirit; + using namespace boost::wave; + + typedef typename token_sequence_type::const_iterator iterator_type; + +static expression_grammar g; // expression grammar +boost::wave::grammars::closures::closure_value result; // expression result +parse_info hit = parse (first, last, g[spirit_assign_actor(result)], + ch_p(T_SPACE) | ch_p(T_CCOMMENT) | ch_p(T_CPPCOMMENT)); + + if (!hit.hit) { + // expression is illformed + if (if_block_status) { + typedef typename token_sequence_type::value_type::string_type string_type; + BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, + boost::wave::util::impl::as_string(first, last), act_pos); + } + else { + // as the if_block_status is false any errors will not be reported + return false; + } + } + + if (!hit.full) { + // The token list starts with a valid expression, but there remains + // something. If the remainder consists out of whitespace only, the + // expression is still valid. + iterator_type next = hit.stop; + + while (next != last) { + switch (token_id(*next)) { + case T_SPACE: + case T_SPACE2: + case T_CCOMMENT: + break; // ok continue + + case T_NEWLINE: + case T_EOF: + case T_CPPCOMMENT: // contains newline + return bool(result); // expression is valid + + default: + // expression is illformed + if (if_block_status) { + typedef typename token_sequence_type::value_type::string_type + string_type; + BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, + boost::wave::util::impl::as_string(first, last), + act_pos); + } + else { + // as the if_block_status is false any errors will not be + // reported + return false; + } + } + ++next; + } + } + + if (!result.is_valid()) { + // division by zero occured + typedef typename token_sequence_type::value_type::string_type string_type; + BOOST_WAVE_THROW(preprocess_exception, division_by_zero, + boost::wave::util::impl::as_string(first, last), + act_pos); + } + +// token sequence is a valid expression + return bool(result); +} + +#undef BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_expression_grammar_gen.hpp b/include/boost/wave/grammars/cpp_expression_grammar_gen.hpp new file mode 100644 index 000000000..866a6f51d --- /dev/null +++ b/include/boost/wave/grammars/cpp_expression_grammar_gen.hpp @@ -0,0 +1,53 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED) +#define CPP_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// expression_grammar_gen template class +// +// This template helps separating the compilation of the +// expression_grammar class from the compilation of the main +// pp_iterator. This is done to safe compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct expression_grammar_gen { + + typedef TokenT token_type; + typedef std::list > + token_sequence_type; + + static bool evaluate( + typename token_sequence_type::const_iterator const &first, + typename token_sequence_type::const_iterator const &last, + typename token_type::position_type const &tok, + bool if_block_status); +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_expression_value.hpp b/include/boost/wave/grammars/cpp_expression_value.hpp new file mode 100644 index 000000000..4aea6481a --- /dev/null +++ b/include/boost/wave/grammars/cpp_expression_value.hpp @@ -0,0 +1,585 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED) +#define CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED + +#if defined (BOOST_SPIRIT_DEBUG) +#include +#endif // defined(BOOST_SPIRIT_DEBUG) + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { +namespace closures { + +/////////////////////////////////////////////////////////////////////////////// +// +// The closure_value class represents the closure type, which is used for the +// expression grammar. +// +// This class was introduced to allow the expression grammar to respect +// the numeric type of a numeric literal or expression result. +// +/////////////////////////////////////////////////////////////////////////////// +class closure_value { +public: + + enum value_type { + is_int = 1, + is_uint = 2, + is_bool = 3 + }; + + closure_value(bool valid_ = true) + : type(is_int), valid(valid_) + { value.i = 0; } + explicit closure_value(int i, bool valid_ = true) + : type(is_int), valid(valid_) + { value.i = i; } + explicit closure_value(unsigned int ui, bool valid_ = true) + : type(is_uint), valid(valid_) + { value.ui = ui; } + explicit closure_value(long i, bool valid_ = true) + : type(is_int), valid(valid_) + { value.i = i; } + explicit closure_value(unsigned long ui, bool valid_ = true) + : type(is_uint), valid(valid_) + { value.ui = ui; } + explicit closure_value(bool b, bool valid_ = true) + : type(is_bool), valid(valid_) + { value.b = b; } + + value_type get_type() const { return type; } + bool is_valid() const { return valid; } + +// implicit conversion + operator int() const + { + switch (type) { + case is_uint: return value.ui; + case is_bool: return value.b ? 1 : 0; + case is_int: break; + } + return value.i; + } + operator unsigned int() const + { + switch (type) { + case is_uint: return value.ui; + case is_bool: return value.b ? 1 : 0; + case is_int: break; + } + return value.i; + } + operator long() const + { + switch (type) { + case is_uint: return value.ui; + case is_bool: return value.b ? 1 : 0; + case is_int: break; + } + return value.i; + } + operator unsigned long() const + { + switch (type) { + case is_uint: return value.ui; + case is_bool: return value.b ? 1 : 0; + case is_int: break; + } + return value.i; + } + operator bool() const + { + switch (type) { + case is_uint: return value.ui != 0; + case is_bool: return value.b; + case is_int: break; + } + return value.i != 0.0; + } + +// assignment + closure_value &operator= (closure_value const &rhs) + { + switch (rhs.get_type()) { + case is_int: + value.i = long(rhs); + type = is_int; + break; + + case is_uint: + value.ui = (unsigned long)(rhs); + type = is_uint; + break; + + case is_bool: + value.b = bool(rhs); + type = is_bool; + break; + } + valid = rhs.valid; + return *this; + } + closure_value &operator= (int rhs) + { + type = is_int; + value.i = rhs; + valid = true; + return *this; + } + closure_value &operator= (unsigned int rhs) + { + type = is_uint; + value.ui = rhs; + valid = true; + return *this; + } + closure_value &operator= (long rhs) + { + type = is_int; + value.i = rhs; + valid = true; + return *this; + } + closure_value &operator= (unsigned long rhs) + { + type = is_uint; + value.ui = rhs; + valid = true; + return *this; + } + closure_value &operator= (bool rhs) + { + type = is_bool; + value.b = rhs; + valid = true; + return *this; + } + +// arithmetics + closure_value &operator+= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: value.i += long(rhs); break; + case is_int: value.i += rhs.value.i; break; + case is_uint: value.ui += rhs.value.ui; type = is_uint; break; + } + break; + + case is_uint: value.ui += (unsigned long)(rhs); break; + case is_bool: + value.i = value.b + bool(rhs); + type = is_int; + } + valid = valid && rhs.valid; + return *this; + } + closure_value &operator-= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: value.i -= long(rhs); break; + case is_int: value.i -= rhs.value.i; break; + case is_uint: value.ui -= rhs.value.ui; type = is_uint; break; + } + break; + + case is_uint: value.ui -= (unsigned long)(rhs); break; + case is_bool: + value.i = value.b - bool(rhs); + type = is_int; + } + valid = valid && rhs.valid; + return *this; + } + closure_value &operator*= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: value.i *= long(rhs); break; + case is_int: value.i *= rhs.value.i; break; + case is_uint: value.ui *= rhs.value.ui; type = is_uint; break; + } + break; + + case is_uint: value.ui *= (unsigned long)(rhs); break; + case is_bool: + switch (rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) * rhs.value.i; + type = is_int; + break; + + case is_uint: + value.ui = (value.b ? 1 : 0) * rhs.value.ui; + type = is_uint; + break; + + case is_bool: + value.b = 0 != ((value.b ? 1 : 0) * (rhs.value.b ? 1 : 0)); + break; + } + } + valid = valid && rhs.valid; + return *this; + } + closure_value &operator/= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + case is_int: + if (valid && long(rhs) != 0) + value.i /= long(rhs); + else + valid = false; // division by zero + break; + + case is_uint: + if (valid && rhs.value.ui != 0) { + value.ui /= rhs.value.ui; + type = is_uint; + } + else { + valid = false; // division by zero + } + break; + } + break; + + case is_uint: + if (valid && (unsigned long)(rhs) != 0) + value.ui /= (unsigned long)(rhs); + else + valid = false; // division by zero + break; + + case is_bool: + if (valid && bool(rhs)) { + switch(rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) / rhs.value.i; + type = is_int; + break; + + case is_uint: + value.i = (value.b ? 1 : 0) / rhs.value.ui; + type = is_int; + break; + + case is_bool: + break; + } + } + else { + valid = false; // division by zero + } + } + return *this; + } + + friend closure_value + operator- (closure_value const &rhs) + { + switch (rhs.type) { + case is_int: return closure_value(-long(rhs), rhs.valid); + case is_bool: return closure_value(!bool(rhs), rhs.valid); + case is_uint: break; + } + return closure_value(-(int)(unsigned long)(rhs), rhs.valid); + } + friend closure_value + operator! (closure_value const &rhs) + { + switch (rhs.type) { + case is_int: return closure_value(!long(rhs), rhs.valid); + case is_bool: return closure_value(!bool(rhs), rhs.valid); + case is_uint: break; + } + return closure_value(!(unsigned long)(rhs), rhs.valid); + } + +// comparison + friend closure_value + operator== (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = bool(lhs) == rhs.value.b; break; + case is_int: cmp = lhs.value.i == rhs.value.i; break; + case is_uint: cmp = lhs.value.ui == rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui == (unsigned long)(rhs); break; + case is_bool: cmp = lhs.value.b == bool(rhs); break; + } + return closure_value(cmp, lhs.valid && rhs.valid); + } + friend closure_value + operator!= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!bool(lhs == rhs), lhs.valid && rhs.valid); + } + friend closure_value + operator> (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = lhs.value.i > long(rhs); break; + case is_int: cmp = lhs.value.i > rhs.value.i; break; + case is_uint: cmp = lhs.value.ui > rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui > (unsigned long)(rhs); break; + case is_bool: cmp = lhs.value.b > bool(rhs); break; + } + return closure_value(cmp, lhs.valid && rhs.valid); + } + friend closure_value + operator< (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: cmp = long(lhs) < long(rhs); break; + switch(rhs.type) { + case is_bool: cmp = lhs.value.i < long(rhs); break; + case is_int: cmp = lhs.value.i < rhs.value.i; break; + case is_uint: cmp = lhs.value.ui < rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui < (unsigned long)(rhs); break; + case is_bool: cmp = bool(lhs) < bool(rhs); break; + } + return closure_value(cmp, lhs.valid && rhs.valid); + } + friend closure_value + operator<= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!bool(lhs > rhs), lhs.valid && rhs.valid); + } + friend closure_value + operator>= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!bool(lhs < rhs), lhs.valid && rhs.valid); + } + + closure_value & + operator<<= (closure_value const &rhs) + { + switch (type) { + case is_bool: + case is_int: + switch (rhs.type) { + case is_bool: + case is_int: + { + long shift_by = long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.i <<= shift_by; + } + break; + + case is_uint: + { + unsigned long shift_by = (unsigned long)(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui <<= shift_by; + + // Note: The usual arithmetic conversions are not performed on + // bit shift operations. + } + break; + } + break; + + case is_uint: + switch (rhs.type) { + case is_bool: + case is_int: + { + long shift_by = long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.ui <<= shift_by; + } + break; + + case is_uint: + { + unsigned long shift_by = (unsigned long)(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui <<= shift_by; + } + break; + } + } + valid = valid && rhs.valid; + return *this; + } + + closure_value & + operator>>= (closure_value const &rhs) + { + switch (type) { + case is_bool: + case is_int: + switch (rhs.type) { + case is_bool: + case is_int: + { + long shift_by = long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.i >>= shift_by; + } + break; + + case is_uint: + { + unsigned long shift_by = (unsigned long)(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui >>= shift_by; + + // Note: The usual arithmetic conversions are not performed on + // bit shift operations. + } + break; + } + break; + + case is_uint: + switch (rhs.type) { + case is_bool: + case is_int: + { + long shift_by = long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.ui >>= shift_by; + } + break; + + case is_uint: + { + unsigned long shift_by = (unsigned long)(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui >>= shift_by; + } + break; + } + break; + } + valid = valid && rhs.valid; + return *this; + } + + friend closure_value + operator|| (closure_value const &lhs, closure_value const &rhs) + { + bool result = bool(lhs) || bool(rhs); + return closure_value(result, lhs.valid && rhs.valid); + } + + friend closure_value + operator&& (closure_value const &lhs, closure_value const &rhs) + { + bool result = bool(lhs) && bool(rhs); + return closure_value(result, lhs.valid && rhs.valid); + } + + // handle the ?: operator + closure_value & + handle_questionmark(closure_value const &cond, closure_value const &val2) + { + switch (type) { + case is_int: + switch (val2.type) { + case is_bool: value.b = bool(cond) ? value.b : bool(val2); break; + case is_int: value.i = bool(cond) ? value.i : long(val2); break; + case is_uint: + value.ui = bool(cond) ? value.ui : (unsigned long)(val2); + type = is_uint; // changing type! + break; + } + break; + + case is_uint: value.ui = bool(cond) ? value.ui : (unsigned long)(val2); break; + case is_bool: value.b = bool(cond) ? value.b : bool(val2); break; + } + valid = bool(cond) ? valid : val2.valid; + return *this; + } + +#if defined (BOOST_SPIRIT_DEBUG) + friend std::ostream& + operator<< (std::ostream &o, closure_value const &val) + { + switch (val.type) { + case is_int: o << "int(" << long(val) << ")"; break; + case is_uint: o << "unsigned int(" << (unsigned long)(val) << ")"; break; + case is_bool: o << "bool(" << bool(val) << ")"; break; + } + return o; + } +#endif // defined(BOOST_SPIRIT_DEBUG) + +private: + value_type type; + union { + long i; + unsigned long ui; + bool b; + } value; + bool valid; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace closures +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_expression_variant.hpp b/include/boost/wave/grammars/cpp_expression_variant.hpp new file mode 100644 index 000000000..d4ab78c45 --- /dev/null +++ b/include/boost/wave/grammars/cpp_expression_variant.hpp @@ -0,0 +1,556 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED) +#define CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED + +#if defined (BOOST_SPIRIT_DEBUG) +#include +#endif // defined(BOOST_SPIRIT_DEBUG) + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { +namespace closures { + +/////////////////////////////////////////////////////////////////////////////// +// +// Definition of the variant visitors needed for type correct value access +// +/////////////////////////////////////////////////////////////////////////////// +struct long_visitor : public boost::static_visitor +{ + template + long operator() (T val) + { + return T(val); + } +}; + +struct ulong_visitor : public boost::static_visitor +{ + template + unsigned long operator() (T val) + { + return T(val); + } +}; + +struct bool_visitor : public boost::static_visitor +{ + template + bool operator() (T val) + { + return T(val); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Definition of the variant visitors needed for unary and binary operations +// on the expression values. +// +/////////////////////////////////////////////////////////////////////////////// +struct plus_visitor : public boost::static_visitor<> +{ + template + void operator()(unsigned long &lhs, T2 rhs) const + { + return lhs + rhs; + } +}; + +struct minus_visitor : public boost::static_visitor +{ + template + long operator()(T1 lhs, T2 rhs) const + { + return lhs - rhs; + } +}; + +struct multiply_visitor : public boost::static_visitor +{ + template + long operator()(T1 &lhs, T2 rhs) const + { + lhs *= rhs; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// The closure_value class represents the closure type, which is used for the +// expression grammar. +// +// This class was introduced to allow the expression grammar to respect +// the numeric type of a numeric literal or expression result. +// +/////////////////////////////////////////////////////////////////////////////// +class closure_value +{ +public: + + closure_value() + : value(0L), valid(true) + {} + explicit closure_value(long i, bool valid_ = true) + : value(i), valid(valid_) + {} + explicit closure_value(unsigned long ui, bool valid_ = true) + : value(ui), valid(valid_) + {} + explicit closure_value(bool b, bool valid_ = true) + : value(b), valid(valid_) + {} + + bool is_valid() const { return valid; } + +// implicit conversion + operator long() const + { + return as_long(); + } + operator unsigned long() const + { + return as_ulong(); + } + operator bool() const + { + return as_bool(); + } + +// assignment + closure_value &operator= (long rhs) + { + value = rhs; + valid = true; + return *this; + } + closure_value &operator= (unsigned long rhs) + { + value = rhs; + valid = true; + return *this; + } + closure_value &operator= (bool rhs) + { + value = rhs; + valid = true; + return *this; + } + +// arithmetics + closure_value &operator+= (closure_value const &rhs) + { + if (valid = valid && rhs.valid) + value = boost::apply_visitor(plus_visitor(), value, rhs.value); + return *this; + } + closure_value &operator-= (closure_value const &rhs) + { + if (valid = valid && rhs.valid) + value = boost::apply_visitor(minus_visitor(), value, rhs.value); + return *this; + } + closure_value &operator*= (closure_value const &rhs) + { + if (valid = valid && rhs.valid) + value = boost::apply_visitor(multiply_visitor(), value, rhs.value); + return *this; + } + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: value.i *= long(rhs); break; + case is_int: value.i *= rhs.value.i; break; + case is_uint: value.ui *= rhs.value.ui; type = is_uint; break; + } + break; + + case is_uint: value.ui *= unsigned long(rhs); break; + case is_bool: + switch (rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) * rhs.value.i; + type = is_int; + break; + + case is_uint: + value.ui = (value.b ? 1 : 0) * rhs.value.ui; + type = is_uint; + break; + + case is_bool: + value.b = 0 != ((value.b ? 1 : 0) * (rhs.value.b ? 1 : 0)); + break; + } + } + valid = valid && rhs.valid; + return *this; + } + closure_value &operator/= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + case is_int: + if (valid && long(rhs) != 0) + value.i /= long(rhs); + else + valid = false; // division by zero + break; + + case is_uint: + if (valid && rhs.value.ui != 0) { + value.ui /= rhs.value.ui; + type = is_uint; + } + else { + valid = false; // division by zero + } + break; + } + break; + + case is_uint: + if (valid && unsigned long(rhs) != 0) + value.ui /= unsigned long(rhs); + else + valid = false; // division by zero + break; + + case is_bool: + if (valid && bool(rhs)) { + switch(rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) / rhs.value.i; + type = is_int; + break; + + case is_uint: + value.i = (value.b ? 1 : 0) / rhs.value.ui; + type = is_int; + break; + + case is_bool: + break; + } + } + else { + valid = false; // division by zero + } + } + return *this; + } + + friend closure_value + operator- (closure_value const &rhs) + { + switch (rhs.type) { + case is_int: return closure_value(-long(rhs), rhs.valid); + case is_bool: return closure_value(!bool(rhs), rhs.valid); + case is_uint: break; + } + return closure_value(-(int)unsigned long(rhs), rhs.valid); + } + friend closure_value + operator! (closure_value const &rhs) + { + switch (rhs.type) { + case is_int: return closure_value(!long(rhs), rhs.valid); + case is_bool: return closure_value(!bool(rhs), rhs.valid); + case is_uint: break; + } + return closure_value(!unsigned long(rhs), rhs.valid); + } + +// comparison + friend closure_value + operator== (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = bool(lhs) == rhs.value.b; break; + case is_int: cmp = lhs.value.i == rhs.value.i; break; + case is_uint: cmp = lhs.value.ui == rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui == unsigned long(rhs); break; + case is_bool: cmp = lhs.value.b == bool(rhs); break; + } + return closure_value(cmp, lhs.valid && rhs.valid); + } + friend closure_value + operator!= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!bool(lhs == rhs), lhs.valid && rhs.valid); + } + friend closure_value + operator> (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = lhs.value.i > long(rhs); break; + case is_int: cmp = lhs.value.i > rhs.value.i; break; + case is_uint: cmp = lhs.value.ui > rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui > unsigned long(rhs); break; + case is_bool: cmp = lhs.value.b > bool(rhs); break; + } + return closure_value(cmp, lhs.valid && rhs.valid); + } + friend closure_value + operator< (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: cmp = long(lhs) < long(rhs); break; + switch(rhs.type) { + case is_bool: cmp = lhs.value.i < long(rhs); break; + case is_int: cmp = lhs.value.i < rhs.value.i; break; + case is_uint: cmp = lhs.value.ui < rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui < unsigned long(rhs); break; + case is_bool: cmp = bool(lhs) < bool(rhs); break; + } + return closure_value(cmp, lhs.valid && rhs.valid); + } + friend closure_value + operator<= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!bool(lhs > rhs), lhs.valid && rhs.valid); + } + friend closure_value + operator>= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!bool(lhs < rhs), lhs.valid && rhs.valid); + } + + closure_value & + operator<<= (closure_value const &rhs) + { + switch (type) { + case is_bool: + case is_int: + switch (rhs.type) { + case is_bool: + case is_int: + { + long shift_by = long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.i <<= shift_by; + } + break; + + case is_uint: + { + unsigned long shift_by = unsigned long(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui <<= shift_by; + + // Note: The usual arithmetic conversions are not performed on + // bit shift operations. + } + break; + } + break; + + case is_uint: + switch (rhs.type) { + case is_bool: + case is_int: + { + long shift_by = long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.ui <<= shift_by; + } + break; + + case is_uint: + { + unsigned long shift_by = unsigned long(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui <<= shift_by; + } + break; + } + } + valid = valid && rhs.valid; + return *this; + } + + closure_value & + operator>>= (closure_value const &rhs) + { + switch (type) { + case is_bool: + case is_int: + switch (rhs.type) { + case is_bool: + case is_int: + { + long shift_by = long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.i >>= shift_by; + } + break; + + case is_uint: + { + unsigned long shift_by = unsigned long(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui >>= shift_by; + + // Note: The usual arithmetic conversions are not performed on + // bit shift operations. + } + break; + } + break; + + case is_uint: + switch (rhs.type) { + case is_bool: + case is_int: + { + long shift_by = long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.ui >>= shift_by; + } + break; + + case is_uint: + { + unsigned long shift_by = unsigned long(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui >>= shift_by; + } + break; + } + break; + } + valid = valid && rhs.valid; + return *this; + } + + friend closure_value + operator|| (closure_value const &lhs, closure_value const &rhs) + { + bool result = bool(lhs) || bool(rhs); + return closure_value(result, lhs.valid && rhs.valid); + } + + friend closure_value + operator&& (closure_value const &lhs, closure_value const &rhs) + { + bool result = bool(lhs) && bool(rhs); + return closure_value(result, lhs.valid && rhs.valid); + } + + // handle the ?: operator + closure_value & + handle_questionmark(closure_value const &cond, closure_value const &val2) + { + switch (type) { + case is_int: + switch (val2.type) { + case is_bool: value.b = bool(cond) ? value.b : bool(val2); break; + case is_int: value.i = bool(cond) ? value.i : long(val2); break; + case is_uint: + value.ui = bool(cond) ? value.ui : unsigned long(val2); + type = is_uint; // changing type! + break; + } + break; + + case is_uint: value.ui = bool(cond) ? value.ui : unsigned long(val2); break; + case is_bool: value.b = bool(cond) ? value.b : bool(val2); break; + } + valid = bool(cond) ? valid : val2.valid; + return *this; + } + +#if defined (BOOST_SPIRIT_DEBUG) + friend std::ostream& + operator<< (std::ostream &o, closure_value const &val) + { + switch (val.type) { + case is_int: o << "int(" << long(val) << ")"; break; + case is_uint: o << "unsigned int(" << unsigned long(val) << ")"; break; + case is_bool: o << "bool(" << bool(val) << ")"; break; + } + return o; + } +#endif // defined(BOOST_SPIRIT_DEBUG) + +protected: + long as_long() const + { + return boost::apply_visitor(long_visitor(), value); + } + unsigned long as_ulong() const + { + return boost::apply_visitor(ulong_visitor(), value); + } + bool as_bool() const + { + return boost::apply_visitor(bool_visitor(), value); + } + +private: + boost::variant value; + bool valid; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace closures +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_grammar.hpp b/include/boost/wave/grammars/cpp_grammar.hpp new file mode 100644 index 000000000..9d8711ad8 --- /dev/null +++ b/include/boost/wave/grammars/cpp_grammar.hpp @@ -0,0 +1,738 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED) +#define CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED + +#include +#include +#include +#include +#include + +#include + +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 +#include +#include +#endif + +#include +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// store_position +// +// The store_position functor extracts the actual file position from the +// supplied token. +// +/////////////////////////////////////////////////////////////////////////////// + + template + struct store_position { + + store_position(PositionT &pos_) : pos(pos_) {} + + template + void operator()(TokenT const &token) const + { + pos = token.get_position(); + } + + PositionT &pos; + }; + +/////////////////////////////////////////////////////////////////////////////// +// +// store_found_eof +// +// The store_found_eof functor sets a given flag if the T_EOF token was +// found during the parsing process +// +/////////////////////////////////////////////////////////////////////////////// + + struct store_found_eof { + + store_found_eof(bool &found_eof_) : found_eof(found_eof_) {} + + template + void operator()(TokenT const &token) const + { + found_eof = true; + } + + bool &found_eof; + }; + +/////////////////////////////////////////////////////////////////////////////// +// +// store_found_directive +// +// The store_found_directive functor stores the token_id of the recognized +// pp directive +// +/////////////////////////////////////////////////////////////////////////////// + + struct store_found_directive { + + store_found_directive(boost::wave::token_id &found_directive_) + : found_directive(found_directive_) {} + + template + void operator()(TokenT const &token) const + { + found_directive = boost::wave::token_id(token); + } + + boost::wave::token_id &found_directive; + }; + +/////////////////////////////////////////////////////////////////////////////// +// +// flush_underlying_parser +// +// The flush_underlying_parser flushes the underlying +// multi_pass_iterator during the normal parsing process. This is +// used at certain points during the parsing process, when it is +// clear, that no backtracking is needed anymore and the input +// gathered so far may be discarded. +// +/////////////////////////////////////////////////////////////////////////////// + struct flush_underlying_parser + : public boost::spirit::parser + { + typedef flush_underlying_parser this_t; + + template + typename boost::spirit::parser_result::type + parse(ScannerT const& scan) const + { + scan.first.clear_queue(); + return scan.empty_match(); + } + }; + + flush_underlying_parser const + flush_underlying_parser_p = flush_underlying_parser(); + +} // anonymous namespace + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CPP_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// Encapsulation of the C++ preprocessor grammar. +template +struct cpp_grammar : + public boost::spirit::grammar > +{ + typedef cpp_grammar grammar_t; + typedef impl::store_position store_pos_t; + typedef impl::store_found_eof store_found_eof_t; + typedef impl::store_found_directive store_found_directive_t; + + template + struct definition + { + // non-parse_tree generating rule type + typedef typename ScannerT::iteration_policy_t iteration_policy_t; + typedef boost::spirit::match_policy match_policy_t; + typedef typename ScannerT::action_policy_t action_policy_t; + typedef + boost::spirit::scanner_policies< + iteration_policy_t, match_policy_t, action_policy_t> + policies_t; + typedef + boost::spirit::scanner + non_tree_scanner_t; + typedef boost::spirit::rule no_tree_rule_t; + + // 'normal' (parse_tree generating) rule type + typedef boost::spirit::rule rule_t; + + rule_t pp_statement; + rule_t include_file, system_include_file, macro_include_file; + rule_t plain_define, macro_definition, macro_parameters; + rule_t undefine; + rule_t ppifdef, ppifndef, ppif, ppelse, ppelif, ppendif; + rule_t ppline; + rule_t pperror; + rule_t ppwarning; + rule_t pppragma; + rule_t illformed; + rule_t ppqualifiedname; + rule_t eol_tokens; + no_tree_rule_t ppsp; +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + rule_t ppregion; + rule_t ppendregion; +#endif + + definition(cpp_grammar const &self) + { + // import the spirit and cpplexer namespaces here + using namespace boost::spirit; + using namespace boost::wave; + using namespace boost::wave::util; + + // save the rule id's for later use + self.rule_ids.pp_statement_id = pp_statement.id().to_long(); + self.rule_ids.include_file_id = include_file.id().to_long(); + self.rule_ids.sysinclude_file_id = system_include_file.id().to_long(); + self.rule_ids.macroinclude_file_id = macro_include_file.id().to_long(); + self.rule_ids.plain_define_id = plain_define.id().to_long(); + self.rule_ids.macro_parameters_id = macro_parameters.id().to_long(); + self.rule_ids.macro_definition_id = macro_definition.id().to_long(); + self.rule_ids.undefine_id = undefine.id().to_long(); + self.rule_ids.ifdef_id = ppifdef.id().to_long(); + self.rule_ids.ifndef_id = ppifndef.id().to_long(); + self.rule_ids.if_id = ppif.id().to_long(); + self.rule_ids.elif_id = ppelif.id().to_long(); + self.rule_ids.else_id = ppelse.id().to_long(); + self.rule_ids.endif_id = ppendif.id().to_long(); + self.rule_ids.line_id = ppline.id().to_long(); + self.rule_ids.error_id = pperror.id().to_long(); + self.rule_ids.warning_id = ppwarning.id().to_long(); + self.rule_ids.pragma_id = pppragma.id().to_long(); + self.rule_ids.illformed_id = illformed.id().to_long(); + self.rule_ids.ppspace_id = ppsp.id().to_long(); + self.rule_ids.ppqualifiedname_id = ppqualifiedname.id().to_long(); +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + self.rule_ids.region_id = ppregion.id().to_long(); + self.rule_ids.endregion_id = ppendregion.id().to_long(); +#endif + +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 + self.map_rule_id_to_name.init_rule_id_to_name_map(self); +#endif + + // recognizes preprocessor directives only + + // C++ standard 16.1: A preprocessing directive consists of a sequence + // of preprocessing tokens. The first token in the sequence is # + // preprocessing token that is either the first character in the source + // file (optionally after white space containing no new-line + // characters) or that follows white space containing at least one + // new-line character. The last token in the sequence is the first + // new-line character that follows the first token in the sequence. + + pp_statement + = ( include_file + | system_include_file + | macro_include_file + | plain_define + | undefine + | ppifdef + | ppifndef + | ppif + | ppelse + | ppelif + | ppendif + | ppline + | pperror + | ppwarning + | pppragma + | illformed +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + | ppregion + | ppendregion +#endif + ) + >> eol_tokens +// In parser debug mode it is useful not to flush the underlying stream +// to allow its investigation in the debugger and to see the correct +// output in the printed debug log.. +// Note: this may break the parser, though. +#if !(defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \ + ) + >> impl::flush_underlying_parser_p +#endif // !(defined(BOOST_SPIRIT_DEBUG) && + ; + + // #include ... + include_file // include "..." + = ch_p(T_PP_QHEADER) + [ store_found_directive_t(self.found_directive) ] +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + | ch_p(T_PP_QHEADER_NEXT) + [ store_found_directive_t(self.found_directive) ] +#endif + ; + + system_include_file // include <...> + = ch_p(T_PP_HHEADER) + [ store_found_directive_t(self.found_directive) ] +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + | ch_p(T_PP_HHEADER_NEXT) + [ store_found_directive_t(self.found_directive) ] +#endif + ; + + macro_include_file // include ...anything else... + = no_node_d + [ + ch_p(T_PP_INCLUDE) + [ store_found_directive_t(self.found_directive) ] +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + | ch_p(T_PP_INCLUDE_NEXT) + [ store_found_directive_t(self.found_directive) ] +#endif + ] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + // #define FOO foo (with optional parameters) + plain_define + = no_node_d + [ + ch_p(T_PP_DEFINE) + [ store_found_directive_t(self.found_directive) ] + >> +ppsp + ] + >> ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, TokenTypeMask) + | pattern_p(OperatorTokenType|AltExtTokenType, + ExtTokenTypeMask) // and, bit_and etc. + ) + >> ( ( no_node_d[eps_p(ch_p(T_LEFTPAREN))] + >> macro_parameters + >> !macro_definition + ) + | !( no_node_d[+ppsp] + >> macro_definition + ) + ) + ; + + // parameter list + // normal C++ mode + macro_parameters + = confix_p( + no_node_d[ch_p(T_LEFTPAREN) >> *ppsp], + !list_p( + ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, TokenTypeMask) +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + | ch_p(T_ELLIPSIS) +#endif + ), + no_node_d[*ppsp >> ch_p(T_COMMA) >> *ppsp] + ), + no_node_d[*ppsp >> ch_p(T_RIGHTPAREN)] + ) + ; + + // macro body (anything left until eol) + macro_definition + = no_node_d[*ppsp] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + // #undef FOO + undefine + = no_node_d + [ + ch_p(T_PP_UNDEF) + [ store_found_directive_t(self.found_directive) ] + >> +ppsp + ] + >> ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, TokenTypeMask) + ) + ; + + // #ifdef et.al. + ppifdef + = no_node_d + [ + ch_p(T_PP_IFDEF) + [ store_found_directive_t(self.found_directive) ] + >> +ppsp + ] + >> ppqualifiedname + ; + + ppifndef + = no_node_d + [ + ch_p(T_PP_IFNDEF) + [ store_found_directive_t(self.found_directive) ] + >> +ppsp + ] + >> ppqualifiedname + ; + + ppif + = no_node_d + [ + ch_p(T_PP_IF) + [ store_found_directive_t(self.found_directive) ] + >> *ppsp + ] + >> +( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + ppelse + = no_node_d + [ + ch_p(T_PP_ELSE) + [ store_found_directive_t(self.found_directive) ] + ] + ; + + ppelif + = no_node_d + [ + ch_p(T_PP_ELIF) + [ store_found_directive_t(self.found_directive) ] + >> *ppsp + ] + >> +( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + ppendif + = no_node_d + [ + ch_p(T_PP_ENDIF) + [ store_found_directive_t(self.found_directive) ] + ] + ; + + // #line ... + ppline + = no_node_d + [ + ch_p(T_PP_LINE) + [ store_found_directive_t(self.found_directive) ] + >> *ppsp + ] + >> +( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + // #region ... + ppregion + = no_node_d + [ + ch_p(T_MSEXT_PP_REGION) + [ store_found_directive_t(self.found_directive) ] + >> +ppsp + ] + >> ppqualifiedname + ; + + // #endregion + ppendregion + = no_node_d + [ + ch_p(T_MSEXT_PP_ENDREGION) + [ store_found_directive_t(self.found_directive) ] + ] + ; +#endif + + // # something else (ill formed preprocessor directive) + illformed // for error reporting + = no_node_d + [ + pattern_p(T_POUND, MainTokenMask) + >> *ppsp + ] + >> ( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + >> no_node_d + [ + *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ] + ; + + // #error + pperror + = no_node_d + [ + ch_p(T_PP_ERROR) + [ store_found_directive_t(self.found_directive) ] + >> *ppsp + ] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + // #warning + ppwarning + = no_node_d + [ + ch_p(T_PP_WARNING) + [ store_found_directive_t(self.found_directive) ] + >> *ppsp + ] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + // #pragma ... + pppragma + = no_node_d + [ + ch_p(T_PP_PRAGMA) + [ store_found_directive_t(self.found_directive) ] + ] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + ppqualifiedname + = no_node_d[*ppsp] + >> ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, TokenTypeMask) + ) + ; + + // auxiliary helper rules + ppsp // valid space in a line with a preprocessor directive + = ch_p(T_SPACE) | ch_p(T_CCOMMENT) + ; + + // end of line tokens + eol_tokens + = no_node_d + [ + *ppsp + >> ( ch_p(T_NEWLINE) + [ store_pos_t(self.pos_of_newline) ] + | ch_p(T_CPPCOMMENT) + [ store_pos_t(self.pos_of_newline) ] + | ch_p(T_EOF) + [ store_pos_t(self.pos_of_newline) ] + [ store_found_eof_t(self.found_eof) ] + ) + ] + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_statement, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(include_file, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(system_include_file, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_include_file, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(undefine, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifdef, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifndef, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppif, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelse, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelif, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendif, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppline, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(pperror, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppwarning, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(illformed, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppsp, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppqualifiedname, TRACE_CPP_GRAMMAR); +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppregion, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendregion, TRACE_CPP_GRAMMAR); +#endif + } + + // start rule of this grammar + rule_t const& start() const + { return pp_statement; } + }; + + cpp_grammar_rule_ids &rule_ids; + PositionT &pos_of_newline; + bool &found_eof; + boost::wave::token_id &found_directive; + + cpp_grammar(cpp_grammar_rule_ids &rule_ids_, PositionT &pos_of_newline_, + bool &found_eof_, boost::wave::token_id &found_directive_) + : rule_ids(rule_ids_), pos_of_newline(pos_of_newline_), + found_eof(found_eof_), found_directive(found_directive_) + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "cpp_grammar", + TRACE_CPP_GRAMMAR); + } + +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 +// helper function and data to get readable names of the rules known to us + struct map_ruleid_to_name : + public std::map + { + typedef std::map base_t; + + void init_rule_id_to_name_map(cpp_grammar const &self) + { + struct { + int parser_id; + char const *rule_name; + } + init_ruleid_name_map[] = { + { self.rule_ids.pp_statement_id, "pp_statement" }, + { self.rule_ids.include_file_id, "include_file" }, + { self.rule_ids.sysinclude_file_id, "system_include_file" }, + { self.rule_ids.macroinclude_file_id, "macro_include_file" }, + { self.rule_ids.plain_define_id, "plain_define" }, + { self.rule_ids.macro_parameters_id, "macro_parameters" }, + { self.rule_ids.macro_definition_id, "macro_definition" }, + { self.rule_ids.undefine_id, "undefine" }, + { self.rule_ids.ifdef_id, "ppifdef" }, + { self.rule_ids.ifndef_id, "ppifndef" }, + { self.rule_ids.if_id, "ppif" }, + { self.rule_ids.elif_id, "ppelif" }, + { self.rule_ids.else_id, "ppelse" }, + { self.rule_ids.endif_id, "ppendif" }, + { self.rule_ids.line_id, "ppline" }, + { self.rule_ids.error_id, "pperror" }, + { self.rule_ids.warning_id, "ppwarning" }, + { self.rule_ids.pragma_id, "pppragma" }, + { self.rule_ids.illformed_id, "illformed" }, + { self.rule_ids.ppsp_id, "ppsp" }, + { self.rule_ids.ppqualifiedname_id, "ppqualifiedname" }, +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + { self.rule_ids.region_id, "ppregion" }, + { self.rule_ids.endregion_id, "ppendregion" }, +#endif + { 0 } + }; + + // initialize parser_id to rule_name map + for (int i = 0; 0 != init_ruleid_name_map[i].parser_id; ++i) + base_t::insert(base_t::value_type( + boost::spirit::parser_id(init_ruleid_name_map[i].parser_id), + std::string(init_ruleid_name_map[i].rule_name)) + ); + } + }; + mutable map_ruleid_to_name map_rule_id_to_name; +#endif // WAVE_DUMP_PARSE_TREE != 0 +}; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_CPP_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following parse function is defined here, to allow the separation of +// the compilation of the cpp_grammar from the function using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_GRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_GRAMMAR_GEN_INLINE inline +#endif + +namespace { + + char const *get_directivename(boost::wave::token_id id) + { + using namespace boost::wave; + switch (id) { + case T_PP_QHEADER: + case T_PP_HHEADER: + case T_PP_INCLUDE: return "#include"; + case T_PP_DEFINE: return "#define"; + case T_PP_UNDEF: return "#undef"; + case T_PP_IFDEF: return "#ifdef"; + case T_PP_IFNDEF: return "#ifndef"; + case T_PP_IF: return "#if"; + case T_PP_ELSE: return "#else"; + case T_PP_ELIF: return "#elif"; + case T_PP_ENDIF: return "#endif"; + case T_PP_LINE: return "#line"; + case T_PP_ERROR: return "#error"; + case T_PP_WARNING: return "#warning"; + case T_PP_PRAGMA: return "#pragma"; + default: + return "#unknown directive"; + } + } +} + +template +BOOST_WAVE_GRAMMAR_GEN_INLINE +boost::spirit::tree_parse_info +cpp_grammar_gen::parse_cpp_grammar ( + LexIteratorT const &first, LexIteratorT const &last, + bool &found_eof_, position_type const &act_pos) +{ + using namespace boost::spirit; + using namespace boost::wave; + + pos_of_newline = position_type(); // reset position + found_eof = false; // reset flag + found_directive = T_EOF; // reset found directive + + static cpp_grammar g( + rule_ids, pos_of_newline, found_eof, found_directive); + + tree_parse_info hit = pt_parse (first, last, g); + +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 + if (hit.match) { + tree_to_xml (BOOST_WAVE_DUMP_PARSE_TREE_OUT, hit.trees, "", + g.map_rule_id_to_name, &TokenT::get_token_id, + &TokenT::get_token_value); + } +#endif + + if (!hit.match && found_directive != T_EOF) { + // recognized invalid directive + std::string directive = get_directivename(found_directive); + + BOOST_WAVE_THROW(preprocess_exception, ill_formed_directive, + directive, act_pos); + } + + found_eof_ = found_eof; + return hit; +} + +#undef BOOST_WAVE_GRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_grammar_gen.hpp b/include/boost/wave/grammars/cpp_grammar_gen.hpp new file mode 100644 index 000000000..a410aa660 --- /dev/null +++ b/include/boost/wave/grammars/cpp_grammar_gen.hpp @@ -0,0 +1,117 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED) +#define CPP_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED + +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// store parser_id's of all rules of the cpp_grammar here for later access +// +/////////////////////////////////////////////////////////////////////////////// +struct cpp_grammar_rule_ids { + std::size_t pp_statement_id; + std::size_t include_file_id; // #include "..." + std::size_t sysinclude_file_id; // #include <...> + std::size_t macroinclude_file_id; // #include ... + std::size_t plain_define_id; // #define + std::size_t macro_parameters_id; + std::size_t macro_definition_id; + std::size_t undefine_id; // #undef + std::size_t ifdef_id; // #ifdef + std::size_t ifndef_id; // #ifndef + std::size_t if_id; // #if + std::size_t elif_id; // #elif + std::size_t else_id; // #else + std::size_t endif_id; // #endif + std::size_t line_id; // #line + std::size_t error_id; // #error + std::size_t warning_id; // #warning + std::size_t pragma_id; // #pragma + std::size_t illformed_id; + std::size_t ppspace_id; + std::size_t ppqualifiedname_id; +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + std::size_t region_id; // #region + std::size_t endregion_id; // #endregion +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// cpp_grammar_gen template class +// +// This template helps separating the compilation of the cpp_grammar +// class from the compilation of the main pp_iterator. This is done to +// safe compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct cpp_grammar_gen +{ + typedef LexIteratorT iterator_type; + typedef typename LexIteratorT::token_type token_type; + typedef typename token_type::position_type position_type; + +// the parser_id's of all rules of the cpp_grammar are stored here +// note: these are valid only after the first call to parse_cpp_grammar + static cpp_grammar_rule_ids rule_ids; + +// the actual position of the last matched T_NEWLINE is stored here into the +// member 'pos_of_newline' + static position_type pos_of_newline; + +// the found_eof flag is set to true during the parsing, if the directive +// under inspection terminates with a T__EOF token + static bool found_eof; + +// the found_directive contains the token_id of the recognized pp directive + static boost::wave::token_id found_directive; + +// parse the cpp_grammar and return the resulting parse tree + static boost::spirit::tree_parse_info + parse_cpp_grammar (iterator_type const &first, iterator_type const &last, + bool &found_eof_, position_type const &act_pos); +}; + +/////////////////////////////////////////////////////////////////////////////// +// definitions of the static members +template +cpp_grammar_rule_ids + cpp_grammar_gen::rule_ids; + +template +typename LexIteratorT::token_type::position_type + cpp_grammar_gen::pos_of_newline; + +template +bool cpp_grammar_gen::found_eof = false; + +template +boost::wave::token_id cpp_grammar_gen::found_directive = + boost::wave::T_EOF; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_intlit_grammar.hpp b/include/boost/wave/grammars/cpp_intlit_grammar.hpp new file mode 100644 index 000000000..3ea29e459 --- /dev/null +++ b/include/boost/wave/grammars/cpp_intlit_grammar.hpp @@ -0,0 +1,183 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED) +#define CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED + +#include +#include +#if SPIRIT_VERSION >= 0x1700 +#include +#include +#endif // SPIRIT_VERSION >= 0x1700 + +#include +#include +#include + +#include +#include +#include + +#if !defined(spirit_append_actor) +#if SPIRIT_VERSION >= 0x1700 +#define spirit_append_actor(actor) boost::spirit::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::assign_a(actor) +#else +#define spirit_append_actor(actor) boost::spirit::append(actor) +#define spirit_assign_actor(actor) boost::spirit::assign(actor) +#endif // SPIRIT_VERSION >= 0x1700 +#endif // !defined(spirit_append_actor) + +/////////////////////////////////////////////////////////////////////////////// +// +// Reusable grammar for parsing of C++ style integer literals +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +namespace closures { + + struct intlit_closure + : boost::spirit::closure + { + member1 val; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_INTLIT_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR) \ + /**/ + +struct intlit_grammar : + boost::spirit::grammar +{ + intlit_grammar(bool &is_unsigned_) : is_unsigned(is_unsigned_) + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "intlit_grammar", + TRACE_INTLIT_GRAMMAR); + } + + template + struct definition + { + typedef boost::spirit::rule rule_t; + + rule_t int_lit; + boost::spirit::subrule<0> sub_int_lit; + boost::spirit::subrule<1> oct_lit; + boost::spirit::subrule<2> hex_lit; + boost::spirit::subrule<3> dec_lit; + + definition(intlit_grammar const &self) + { + using namespace boost::spirit; + using namespace phoenix; + + int_lit = ( + sub_int_lit = + ( ch_p('0')[self.val = 0] >> (hex_lit | oct_lit) + | dec_lit + ) + >> !as_lower_d[ + (ch_p('u')[var(self.is_unsigned) = true] || ch_p('l')) + | (ch_p('l') || ch_p('u')[var(self.is_unsigned) = true]) + ] + , + + hex_lit = + (ch_p('X') | ch_p('x')) + >> uint_parser() + [ + self.val = arg1, + var(self.is_unsigned) = true + ] + , + + oct_lit = + !uint_parser() + [ + self.val = arg1, + var(self.is_unsigned) = true + ] + , + + dec_lit = + int_parser() + [ + self.val = arg1 + ] + + ) + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(int_lit, TRACE_INTLIT_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(sub_int_lit, TRACE_INTLIT_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(hex_lit, TRACE_INTLIT_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(oct_lit, TRACE_INTLIT_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(dec_lit, TRACE_INTLIT_GRAMMAR); + } + + // start rule of this grammar + rule_t const& start() const + { return int_lit; } + }; + + bool &is_unsigned; +}; + +#undef TRACE_INTLIT_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following function is defined here, to allow the separation of +// the compilation of the intlit_grammap from the function using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE inline +#endif + +template +BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE +unsigned long +intlit_grammar_gen::evaluate(TokenT const &token, + bool &is_unsigned) +{ + using namespace boost::spirit; + +intlit_grammar g(is_unsigned); +unsigned long result = 0; +typename TokenT::string_type const &token_val = token.get_value(); +parse_info hit = + parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]); + + if (!hit.hit) { + BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, + token_val, token.get_position()); + } + return result; +} + +#undef BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_literal_grammar_gen.hpp b/include/boost/wave/grammars/cpp_literal_grammar_gen.hpp new file mode 100644 index 000000000..a0c78d9d8 --- /dev/null +++ b/include/boost/wave/grammars/cpp_literal_grammar_gen.hpp @@ -0,0 +1,54 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED) +#define CPP_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// cpp_intlit_grammar_gen template class +// +// This template helps separating the compilation of the intlit_grammar +// class from the compilation of the expression_grammar. This is done +// to safe compilation time. +// +/////////////////////////////////////////////////////////////////////////////// +template +struct intlit_grammar_gen { + + static unsigned long evaluate(TokenT const &tok, bool &is_unsigned); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// cpp_chlit_grammar_gen template class +// +// This template helps separating the compilation of the chlit_grammar +// class from the compilation of the expression_grammar. This is done +// to safe compilation time. +// +/////////////////////////////////////////////////////////////////////////////// +template +struct chlit_grammar_gen { + + static unsigned int evaluate(TokenT const &tok); +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_predef_macros_gen.hpp b/include/boost/wave/grammars/cpp_predef_macros_gen.hpp new file mode 100644 index 000000000..ed14f8869 --- /dev/null +++ b/include/boost/wave/grammars/cpp_predef_macros_gen.hpp @@ -0,0 +1,73 @@ +/*============================================================================= + A Standard compliant C++ preprocessor + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED) +#define CPP_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED + +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// store parser_id's of all rules of the predefined_macros_grammar here +// for later access +// +/////////////////////////////////////////////////////////////////////////////// +struct predefined_macros_grammar_rule_ids { + std::size_t plain_define_id; // #define + std::size_t macro_parameters_id; + std::size_t macro_definition_id; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// predefined_macros_grammar_gen template class +// +// This template helps separating the compilation of the +// predefined_macros_grammar class from the compilation of the +// main pp_iterator. This is done to safe compilation time. +// +// This class helps parsing command line given macro definitions in a +// similar way, as macros are parsed by the cpp_grammar class. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct predefined_macros_grammar_gen +{ + typedef LexIteratorT iterator_type; + +// the parser_id's of all rules of the cpp_grammar are stored here +// note: these are valid only after the first call to parse_cpp_grammar + static predefined_macros_grammar_rule_ids rule_ids; + +// parse the cpp_grammar and return the resulting parse tree + static boost::spirit::tree_parse_info + parse_predefined_macro (iterator_type const &first, iterator_type const &last); +}; + +/////////////////////////////////////////////////////////////////////////////// +// definitions of the static members +template +predefined_macros_grammar_rule_ids + predefined_macros_grammar_gen::rule_ids; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED) diff --git a/include/boost/wave/grammars/cpp_predef_macros_grammar.hpp b/include/boost/wave/grammars/cpp_predef_macros_grammar.hpp new file mode 100644 index 000000000..2d837c249 --- /dev/null +++ b/include/boost/wave/grammars/cpp_predef_macros_grammar.hpp @@ -0,0 +1,156 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED) +#define CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED + +#include +#include +#include +#include + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_PREDEF_MACROS_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// Encapsulation of the grammar for command line driven predefined macros. +struct predefined_macros_grammar : + public boost::spirit::grammar +{ + template + struct definition + { + // 'normal' (parse_tree generating) rule type + typedef boost::spirit::rule rule_t; + + rule_t plain_define, macro_definition, macro_parameters; + + definition(predefined_macros_grammar const &self) + { + // import the spirit and cpplexer namespaces here + using namespace boost::spirit; + using namespace boost::wave; + using namespace boost::wave::util; + + // save the rule id's for later use + self.rule_ids.plain_define_id = plain_define.id().to_long(); + self.rule_ids.macro_parameters_id = macro_parameters.id().to_long(); + self.rule_ids.macro_definition_id = macro_definition.id().to_long(); + + // recognizes command line defined macro syntax, i.e. + // -DMACRO + // -DMACRO= + // -DMACRO=value + // -DMACRO(x) + // -DMACRO(x)= + // -DMACRO(x)=value + + // This grammar resembles the overall structure of the cpp_grammar to + // make it possible to reuse the parse tree traversal code + plain_define + = ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, TokenTypeMask) + ) + >> !macro_parameters + >> !macro_definition + ; + + // parameter list + macro_parameters + = confix_p( + no_node_d[ch_p(T_LEFTPAREN) >> *ch_p(T_SPACE)], + !list_p( + ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, TokenTypeMask) + ), + no_node_d + [ + *ch_p(T_SPACE) >> ch_p(T_COMMA) >> *ch_p(T_SPACE) + ] + ), + no_node_d[*ch_p(T_SPACE) >> ch_p(T_RIGHTPAREN)] + ) + ; + + // macro body (anything left until eol) + macro_definition + = no_node_d[ch_p(T_ASSIGN)] + >> *anychar_p + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_PREDEF_MACROS_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_PREDEF_MACROS_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_PREDEF_MACROS_GRAMMAR); + } + + // start rule of this grammar + rule_t const& start() const + { return plain_define; } + }; + + predefined_macros_grammar_rule_ids &rule_ids; + + predefined_macros_grammar(predefined_macros_grammar_rule_ids &rule_ids_) + : rule_ids(rule_ids_) + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, + "predefined_macros_grammar", TRACE_PREDEF_MACROS_GRAMMAR); + } + +}; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_PREDEF_MACROS_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following parse function is defined here, to allow the separation of +// the compilation of the cpp_predefined_macros_grammar from the function +// using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE inline +#endif + +template +BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE +boost::spirit::tree_parse_info +predefined_macros_grammar_gen::parse_predefined_macro ( + LexIteratorT const &first, LexIteratorT const &last) +{ + static predefined_macros_grammar g(rule_ids); + return boost::spirit::pt_parse (first, last, g); +} + +#undef BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED) diff --git a/include/boost/wave/language_support.hpp b/include/boost/wave/language_support.hpp new file mode 100644 index 000000000..cb3e35ef6 --- /dev/null +++ b/include/boost/wave/language_support.hpp @@ -0,0 +1,137 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + Definition of the various language support constants + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ +#if !defined(LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED) +#define LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +enum language_support { +// support flags for C++98 + support_normal = 0x01, + support_cpp = support_normal, + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +// support flags for C99 + support_variadics = 0x02, + support_c99 = support_variadics, +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// need_cpp +// +// Extract, if the language to support is C++98 +// +/////////////////////////////////////////////////////////////////////////////// +inline bool +need_cpp(language_support language) +{ + return language == support_cpp; +} + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + +/////////////////////////////////////////////////////////////////////////////// +// +// need_variadics +// +// Extract, if the language to support needs variadics support +// +/////////////////////////////////////////////////////////////////////////////// +inline bool +need_variadics(language_support language) +{ + return (language & support_variadics) ? true : false; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// enable_variadics +// +// Set variadics support in the language to support +// +/////////////////////////////////////////////////////////////////////////////// +inline language_support +enable_variadics(language_support language, bool enable = true) +{ + if (enable) + return static_cast(language | support_variadics); + return static_cast(language & ~support_variadics); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// need_c99 +// +// Extract, if the language to support is C99 +// +/////////////////////////////////////////////////////////////////////////////// +inline bool +need_c99(language_support language) +{ + return language == support_c99; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// enable_c99 +// +// Set, whether to support C99 (alternatively C++98 is supported) +// +/////////////////////////////////////////////////////////////////////////////// +inline language_support +enable_c99(bool enable = true) +{ + return enable ? support_c99 : support_cpp; +} + +#else // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + +/////////////////////////////////////////////////////////////////////////////// +inline bool +need_variadics(language_support language) +{ + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +inline language_support +enable_variadics(language_support language, bool enable = true) +{ + return language; +} + +////////////////////////////////////////////////////////////////////////////// +inline bool +need_c99(language_support language) +{ + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +inline language_support +enable_c99(bool enable = true) +{ + return support_cpp; +} + +#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +#endif // !defined(LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED) diff --git a/include/boost/wave/preprocessing_hooks.hpp b/include/boost/wave/preprocessing_hooks.hpp new file mode 100644 index 000000000..7e6965715 --- /dev/null +++ b/include/boost/wave/preprocessing_hooks.hpp @@ -0,0 +1,210 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(PREPROCESSING_HOOKS_HPP_338DE478_A13C_4B63_9BA9_041C917793B8_INCLUDED) +#define PREPROCESSING_HOOKS_HPP_338DE478_A13C_4B63_9BA9_041C917793B8_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace context_policies { + +/////////////////////////////////////////////////////////////////////////////// +// +// The default_preprocessing_hooks class is a placeholder for all +// preprocessing hooks called from inside the preprocessing engine +// +/////////////////////////////////////////////////////////////////////////////// +struct default_preprocessing_hooks { + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanding_function_like_macro' is called, whenever a + // function-like macro is to be expanded. + // + // The macroname parameter marks the position, where the macro to expand + // is defined. + // The formal_args parameter holds the formal arguments used during the + // definition of the macro. + // The definition parameter holds the macro definition for the macro to + // trace. + // + // The macro call parameter marks the position, where this macro invoked. + // The arguments parameter holds the macro arguments used during the + // invocation of the macro + // + /////////////////////////////////////////////////////////////////////////// + template + void expanding_function_like_macro( + TokenT const ¯odef, std::vector const &formal_args, + ContainerT const &definition, + TokenT const ¯ocall, std::vector const &arguments) + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanding_object_like_macro' is called, whenever a + // object-like macro is to be expanded . + // + // The macroname parameter marks the position, where the macro to expand + // is defined. + // The definition parameter holds the macro definition for the macro to + // trace. + // + // The macro call parameter marks the position, where this macro invoked. + // + /////////////////////////////////////////////////////////////////////////// + template + void expanding_object_like_macro(TokenT const ¯o, + ContainerT const &definition, TokenT const ¯ocall) + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanded_macro' is called, whenever the expansion of a + // macro is finished but before the rescanning process starts. + // + // The parameter 'result' contains the token sequence generated as the + // result of the macro expansion. + // + /////////////////////////////////////////////////////////////////////////// + template + void expanded_macro(ContainerT const &result) + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'rescanned_macro' is called, whenever the rescanning of a + // macro is finished. + // + // The parameter 'result' contains the token sequence generated as the + // result of the rescanning. + // + /////////////////////////////////////////////////////////////////////////// + template + void rescanned_macro(ContainerT const &result) + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'opened_include_file' is called, whenever a file referred + // by an #include directive was successfully located and opened. + // + // The parameter 'filename' contains the full file system path of the + // opened file. + // + // The include_depth parameter contains the current include file depth. + // + // The is_system_include parameter denotes, if the given file was found + // as a result of a #include <...> directive. + // + /////////////////////////////////////////////////////////////////////////// + void + opened_include_file(std::string const &filename, std::size_t include_depth, + bool is_system_include) + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'returning_from_include_file' is called, whenever an + // included file is about to be closed after it's processing is complete. + // + /////////////////////////////////////////////////////////////////////////// + void + returning_from_include_file() + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'interpret_pragma' is called, whenever a #pragma wave + // directive is found, which isn't known to the core Wave library. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'pending' may be used to push tokens back into the input + // stream, which are to be used as the replacement text for the whole + // #pragma wave() directive. + // + // The parameter 'option' contains the name of the interpreted pragma. + // + // The parameter 'values' holds the values of the parameter provided to + // the pragma operator. + // + // The parameter 'act_token' contains the actual #pragma token, which may + // be used for error output. + // + // If the return value is 'false', the whole #pragma directive is + // interpreted as unknown and a corresponding error message is issued. A + // return value of 'true' signs a successful interpretation of the given + // #pragma. + // + /////////////////////////////////////////////////////////////////////////// + template + bool + interpret_pragma(ContextT const &ctx, ContainerT &pending, + typename ContextT::token_type const &option, ContainerT const &values, + typename ContextT::token_type const &act_token) + { + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'defined_macro' is called, whenever a macro was defined + // successfully. + // + // The parameter 'name' is a reference to the token holding the macro name. + // + // The parameter 'is_functionlike' is set to true, whenever the newly + // defined macro is defined as a function like macro. + // + // The parameter 'parameters' holds the parameter tokens for the macro + // definition. If the macro has no parameters or if it is a object like + // macro, then this container is empty. + // + // The parameter 'definition' contains the token sequence given as the + // replacement sequence (definition part) of the newly defined macro. + // + // The parameter 'is_predefined' is set to true for all macros predefined + // during the initialisation pahase of the library. + // + /////////////////////////////////////////////////////////////////////////// + template + void + defined_macro(TokenT const ¯o_name, bool is_functionlike, + ParametersT const ¶meters, DefinitionT const &definition, + bool is_predefined) + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'undefined_macro' is called, whenever a macro definition + // was removed successfully. + // + // The parameter 'name' holds the name of the macro, which definition was + // removed. + // + /////////////////////////////////////////////////////////////////////////// + template + void + undefined_macro(StringT const ¯o_name) + {} + +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace context_policies +} // namespace wave +} // namespace boost + +#endif // !defined(PREPROCESSING_HOOKS_HPP_338DE478_A13C_4B63_9BA9_041C917793B8_INCLUDED) diff --git a/include/boost/wave/token_ids.hpp b/include/boost/wave/token_ids.hpp new file mode 100644 index 000000000..379627fa1 --- /dev/null +++ b/include/boost/wave/token_ids.hpp @@ -0,0 +1,673 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + The definition of a default set of token identifiers and related + functions. + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED) +#define TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +// Allow external redefinition of the token identifiers to use +#if !defined(BOOST_WAVE_TOKEN_IDS_DEFINED) +#define BOOST_WAVE_TOKEN_IDS_DEFINED + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +/////////////////////////////////////////////////////////////////////////////// +// assemble tokenid's +#define TOKEN_FROM_ID(id, cat) ((id) | (cat)) +#define ID_FROM_TOKEN(tok) ((tok) & ~TokenTypeMask) +#define BASEID_FROM_TOKEN(tok) ((tok) & ~ExtTokenTypeMask) +#define CATEGORY_FROM_TOKEN(tok) ((tok) & TokenTypeMask) +#define EXTCATEGORY_FROM_TOKEN(tok) ((tok) & ExtTokenTypeMask) +#define IS_CATEGORY(tok, cat) \ + ((CATEGORY_FROM_TOKEN(tok) == (cat)) ? true : false) \ + /**/ +#define IS_EXTCATEGORY(tok, cat) \ + ((EXTCATEGORY_FROM_TOKEN(tok) == (cat)) ? true : false) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// the token_category helps to classify the different token types +enum token_category { + IdentifierTokenType = 0x10000000, + ParameterTokenType = 0x11000000, + ExtParameterTokenType = 0x11100000, + KeywordTokenType = 0x20000000, + OperatorTokenType = 0x30000000, + LiteralTokenType = 0x40000000, + IntegerLiteralTokenType = 0x41000000, + FloatingLiteralTokenType = 0x42000000, + StringLiteralTokenType = 0x43000000, + CharacterLiteralTokenType = 0x44000000, + BoolLiteralTokenType = 0x45000000, + PPTokenType = 0x50000000, + PPConditionalTokenType = 0x50100000, + + UnknownTokenType = 0xA0000000, + EOLTokenType = 0xB0000000, + EOFTokenType = 0xC0000000, + WhiteSpaceTokenType = 0xD0000000, + InternalTokenType = 0xE0000000, + + TokenTypeMask = 0xFF000000, + AltTokenType = 0x00100000, + TriGraphTokenType = 0x00200000, + AltExtTokenType = 0x00500000, // and, bit_and etc. + ExtTokenTypeMask = 0xFFF00000, + TokenValueMask = 0x000FFFFF, + MainTokenMask = TokenTypeMask|TokenValueMask, +}; + +/////////////////////////////////////////////////////////////////////////////// +// the token_id assigns unique numbers to the different C++ lexemes +enum token_id { + T_FIRST_TOKEN = 256, + T_AND = TOKEN_FROM_ID(T_FIRST_TOKEN, OperatorTokenType), + T_AND_ALT = TOKEN_FROM_ID(T_FIRST_TOKEN, OperatorTokenType|AltExtTokenType), + T_ANDAND = TOKEN_FROM_ID(257, OperatorTokenType), + T_ANDAND_ALT = TOKEN_FROM_ID(257, OperatorTokenType|AltExtTokenType), + T_ASSIGN = TOKEN_FROM_ID(258, OperatorTokenType), + T_ANDASSIGN = TOKEN_FROM_ID(259, OperatorTokenType), + T_ANDASSIGN_ALT = TOKEN_FROM_ID(259, OperatorTokenType|AltExtTokenType), + T_OR = TOKEN_FROM_ID(260, OperatorTokenType), + T_OR_ALT = TOKEN_FROM_ID(260, OperatorTokenType|AltExtTokenType), + T_OR_TRIGRAPH = TOKEN_FROM_ID(260, OperatorTokenType|TriGraphTokenType), + T_ORASSIGN = TOKEN_FROM_ID(261, OperatorTokenType), + T_ORASSIGN_ALT = TOKEN_FROM_ID(261, OperatorTokenType|AltExtTokenType), + T_XOR = TOKEN_FROM_ID(262, OperatorTokenType), + T_XOR_ALT = TOKEN_FROM_ID(262, OperatorTokenType|AltExtTokenType), + T_XOR_TRIGRAPH = TOKEN_FROM_ID(262, OperatorTokenType|TriGraphTokenType), + T_XORASSIGN = TOKEN_FROM_ID(263, OperatorTokenType), + T_XORASSIGN_ALT = TOKEN_FROM_ID(263, OperatorTokenType|AltExtTokenType), + T_COMMA = TOKEN_FROM_ID(264, OperatorTokenType), + T_COLON = TOKEN_FROM_ID(265, OperatorTokenType), + T_DIVIDE = TOKEN_FROM_ID(266, OperatorTokenType), + T_DIVIDEASSIGN = TOKEN_FROM_ID(267, OperatorTokenType), + T_DOT = TOKEN_FROM_ID(268, OperatorTokenType), + T_DOTSTAR = TOKEN_FROM_ID(269, OperatorTokenType), + T_ELLIPSIS = TOKEN_FROM_ID(270, OperatorTokenType), + T_EQUAL = TOKEN_FROM_ID(271, OperatorTokenType), + T_GREATER = TOKEN_FROM_ID(272, OperatorTokenType), + T_GREATEREQUAL = TOKEN_FROM_ID(273, OperatorTokenType), + T_LEFTBRACE = TOKEN_FROM_ID(274, OperatorTokenType), + T_LEFTBRACE_ALT = TOKEN_FROM_ID(274, OperatorTokenType|AltTokenType), + T_LEFTBRACE_TRIGRAPH = TOKEN_FROM_ID(274, OperatorTokenType|TriGraphTokenType), + T_LESS = TOKEN_FROM_ID(275, OperatorTokenType), + T_LESSEQUAL = TOKEN_FROM_ID(276, OperatorTokenType), + T_LEFTPAREN = TOKEN_FROM_ID(277, OperatorTokenType), + T_LEFTBRACKET = TOKEN_FROM_ID(278, OperatorTokenType), + T_LEFTBRACKET_ALT = TOKEN_FROM_ID(278, OperatorTokenType|AltTokenType), + T_LEFTBRACKET_TRIGRAPH = TOKEN_FROM_ID(278, OperatorTokenType|TriGraphTokenType), + T_MINUS = TOKEN_FROM_ID(279, OperatorTokenType), + T_MINUSASSIGN = TOKEN_FROM_ID(280, OperatorTokenType), + T_MINUSMINUS = TOKEN_FROM_ID(281, OperatorTokenType), + T_PERCENT = TOKEN_FROM_ID(282, OperatorTokenType), + T_PERCENTASSIGN = TOKEN_FROM_ID(283, OperatorTokenType), + T_NOT = TOKEN_FROM_ID(284, OperatorTokenType), + T_NOT_ALT = TOKEN_FROM_ID(284, OperatorTokenType|AltExtTokenType), + T_NOTEQUAL = TOKEN_FROM_ID(285, OperatorTokenType), + T_NOTEQUAL_ALT = TOKEN_FROM_ID(285, OperatorTokenType|AltExtTokenType), + T_OROR = TOKEN_FROM_ID(286, OperatorTokenType), + T_OROR_ALT = TOKEN_FROM_ID(286, OperatorTokenType|AltExtTokenType), + T_PLUS = TOKEN_FROM_ID(287, OperatorTokenType), + T_PLUSASSIGN = TOKEN_FROM_ID(288, OperatorTokenType), + T_PLUSPLUS = TOKEN_FROM_ID(289, OperatorTokenType), + T_ARROW = TOKEN_FROM_ID(290, OperatorTokenType), + T_ARROWSTAR = TOKEN_FROM_ID(291, OperatorTokenType), + T_QUESTION_MARK = TOKEN_FROM_ID(292, OperatorTokenType), + T_RIGHTBRACE = TOKEN_FROM_ID(293, OperatorTokenType), + T_RIGHTBRACE_ALT = TOKEN_FROM_ID(293, OperatorTokenType|AltTokenType), + T_RIGHTBRACE_TRIGRAPH = TOKEN_FROM_ID(293, OperatorTokenType|TriGraphTokenType), + T_RIGHTPAREN = TOKEN_FROM_ID(294, OperatorTokenType), + T_RIGHTBRACKET = TOKEN_FROM_ID(295, OperatorTokenType), + T_RIGHTBRACKET_ALT = TOKEN_FROM_ID(295, OperatorTokenType|AltTokenType), + T_RIGHTBRACKET_TRIGRAPH = TOKEN_FROM_ID(295, OperatorTokenType|TriGraphTokenType), + T_COLON_COLON = TOKEN_FROM_ID(296, OperatorTokenType), + T_SEMICOLON = TOKEN_FROM_ID(297, OperatorTokenType), + T_SHIFTLEFT = TOKEN_FROM_ID(298, OperatorTokenType), + T_SHIFTLEFTASSIGN = TOKEN_FROM_ID(299, OperatorTokenType), + T_SHIFTRIGHT = TOKEN_FROM_ID(300, OperatorTokenType), + T_SHIFTRIGHTASSIGN = TOKEN_FROM_ID(301, OperatorTokenType), + T_STAR = TOKEN_FROM_ID(302, OperatorTokenType), + T_COMPL = TOKEN_FROM_ID(303, OperatorTokenType), + T_COMPL_ALT = TOKEN_FROM_ID(303, OperatorTokenType|AltExtTokenType), + T_COMPL_TRIGRAPH = TOKEN_FROM_ID(303, OperatorTokenType|TriGraphTokenType), + T_STARASSIGN = TOKEN_FROM_ID(304, OperatorTokenType), + T_ASM = TOKEN_FROM_ID(305, KeywordTokenType), + T_AUTO = TOKEN_FROM_ID(306, KeywordTokenType), + T_BOOL = TOKEN_FROM_ID(307, KeywordTokenType), + T_FALSE = TOKEN_FROM_ID(308, BoolLiteralTokenType), + T_TRUE = TOKEN_FROM_ID(309, BoolLiteralTokenType), + T_BREAK = TOKEN_FROM_ID(310, KeywordTokenType), + T_CASE = TOKEN_FROM_ID(311, KeywordTokenType), + T_CATCH = TOKEN_FROM_ID(312, KeywordTokenType), + T_CHAR = TOKEN_FROM_ID(313, KeywordTokenType), + T_CLASS = TOKEN_FROM_ID(314, KeywordTokenType), + T_CONST = TOKEN_FROM_ID(315, KeywordTokenType), + T_CONSTCAST = TOKEN_FROM_ID(316, KeywordTokenType), + T_CONTINUE = TOKEN_FROM_ID(317, KeywordTokenType), + T_DEFAULT = TOKEN_FROM_ID(318, KeywordTokenType), + T_DEFINED = TOKEN_FROM_ID(319, KeywordTokenType), + T_DELETE = TOKEN_FROM_ID(320, KeywordTokenType), + T_DO = TOKEN_FROM_ID(321, KeywordTokenType), + T_DOUBLE = TOKEN_FROM_ID(322, KeywordTokenType), + T_DYNAMICCAST = TOKEN_FROM_ID(323, KeywordTokenType), + T_ELSE = TOKEN_FROM_ID(324, KeywordTokenType), + T_ENUM = TOKEN_FROM_ID(325, KeywordTokenType), + T_EXPLICIT = TOKEN_FROM_ID(326, KeywordTokenType), + T_EXPORT = TOKEN_FROM_ID(327, KeywordTokenType), + T_EXTERN = TOKEN_FROM_ID(328, KeywordTokenType), + T_FLOAT = TOKEN_FROM_ID(329, KeywordTokenType), + T_FOR = TOKEN_FROM_ID(330, KeywordTokenType), + T_FRIEND = TOKEN_FROM_ID(331, KeywordTokenType), + T_GOTO = TOKEN_FROM_ID(332, KeywordTokenType), + T_IF = TOKEN_FROM_ID(333, KeywordTokenType), + T_INLINE = TOKEN_FROM_ID(334, KeywordTokenType), + T_INT = TOKEN_FROM_ID(335, KeywordTokenType), + T_LONG = TOKEN_FROM_ID(336, KeywordTokenType), + T_MUTABLE = TOKEN_FROM_ID(337, KeywordTokenType), + T_NAMESPACE = TOKEN_FROM_ID(338, KeywordTokenType), + T_NEW = TOKEN_FROM_ID(339, KeywordTokenType), + T_OPERATOR = TOKEN_FROM_ID(340, KeywordTokenType), + T_PRIVATE = TOKEN_FROM_ID(341, KeywordTokenType), + T_PROTECTED = TOKEN_FROM_ID(342, KeywordTokenType), + T_PUBLIC = TOKEN_FROM_ID(343, KeywordTokenType), + T_REGISTER = TOKEN_FROM_ID(344, KeywordTokenType), + T_REINTERPRETCAST = TOKEN_FROM_ID(345, KeywordTokenType), + T_RETURN = TOKEN_FROM_ID(346, KeywordTokenType), + T_SHORT = TOKEN_FROM_ID(347, KeywordTokenType), + T_SIGNED = TOKEN_FROM_ID(348, KeywordTokenType), + T_SIZEOF = TOKEN_FROM_ID(349, KeywordTokenType), + T_STATIC = TOKEN_FROM_ID(350, KeywordTokenType), + T_STATICCAST = TOKEN_FROM_ID(351, KeywordTokenType), + T_STRUCT = TOKEN_FROM_ID(352, KeywordTokenType), + T_SWITCH = TOKEN_FROM_ID(353, KeywordTokenType), + T_TEMPLATE = TOKEN_FROM_ID(354, KeywordTokenType), + T_THIS = TOKEN_FROM_ID(355, KeywordTokenType), + T_THROW = TOKEN_FROM_ID(356, KeywordTokenType), + T_TRY = TOKEN_FROM_ID(357, KeywordTokenType), + T_TYPEDEF = TOKEN_FROM_ID(358, KeywordTokenType), + T_TYPEID = TOKEN_FROM_ID(359, KeywordTokenType), + T_TYPENAME = TOKEN_FROM_ID(360, KeywordTokenType), + T_UNION = TOKEN_FROM_ID(361, KeywordTokenType), + T_UNSIGNED = TOKEN_FROM_ID(362, KeywordTokenType), + T_USING = TOKEN_FROM_ID(363, KeywordTokenType), + T_VIRTUAL = TOKEN_FROM_ID(364, KeywordTokenType), + T_VOID = TOKEN_FROM_ID(365, KeywordTokenType), + T_VOLATILE = TOKEN_FROM_ID(366, KeywordTokenType), + T_WCHART = TOKEN_FROM_ID(367, KeywordTokenType), + T_WHILE = TOKEN_FROM_ID(368, KeywordTokenType), + T_PP_DEFINE = TOKEN_FROM_ID(369, PPTokenType), + T_PP_IF = TOKEN_FROM_ID(370, PPConditionalTokenType), + T_PP_IFDEF = TOKEN_FROM_ID(371, PPConditionalTokenType), + T_PP_IFNDEF = TOKEN_FROM_ID(372, PPConditionalTokenType), + T_PP_ELSE = TOKEN_FROM_ID(373, PPConditionalTokenType), + T_PP_ELIF = TOKEN_FROM_ID(374, PPConditionalTokenType), + T_PP_ENDIF = TOKEN_FROM_ID(375, PPConditionalTokenType), + T_PP_ERROR = TOKEN_FROM_ID(376, PPTokenType), + T_PP_LINE = TOKEN_FROM_ID(377, PPTokenType), + T_PP_PRAGMA = TOKEN_FROM_ID(378, PPTokenType), + T_PP_UNDEF = TOKEN_FROM_ID(379, PPTokenType), + T_PP_WARNING = TOKEN_FROM_ID(380, PPTokenType), + T_IDENTIFIER = TOKEN_FROM_ID(381, IdentifierTokenType), + T_OCTALINT = TOKEN_FROM_ID(382, IntegerLiteralTokenType), + T_DECIMALINT = TOKEN_FROM_ID(383, IntegerLiteralTokenType), + T_HEXAINT = TOKEN_FROM_ID(384, IntegerLiteralTokenType), + T_INTLIT = TOKEN_FROM_ID(385, IntegerLiteralTokenType), + T_FLOATLIT = TOKEN_FROM_ID(386, FloatingLiteralTokenType), + T_FIXEDPOINTLIT = TOKEN_FROM_ID(386, FloatingLiteralTokenType|AltTokenType), // IDL specific + T_CCOMMENT = TOKEN_FROM_ID(387, WhiteSpaceTokenType), + T_CPPCOMMENT = TOKEN_FROM_ID(388, WhiteSpaceTokenType), + T_CHARLIT = TOKEN_FROM_ID(389, CharacterLiteralTokenType), + T_STRINGLIT = TOKEN_FROM_ID(390, StringLiteralTokenType), + T_CONTLINE = TOKEN_FROM_ID(391, EOLTokenType), + T_SPACE = TOKEN_FROM_ID(392, WhiteSpaceTokenType), + T_SPACE2 = TOKEN_FROM_ID(393, WhiteSpaceTokenType), + T_NEWLINE = TOKEN_FROM_ID(394, EOLTokenType), + T_POUND_POUND = TOKEN_FROM_ID(395, OperatorTokenType), + T_POUND_POUND_ALT = TOKEN_FROM_ID(395, OperatorTokenType|AltTokenType), + T_POUND_POUND_TRIGRAPH = TOKEN_FROM_ID(395, OperatorTokenType|TriGraphTokenType), + T_POUND = TOKEN_FROM_ID(396, OperatorTokenType), + T_POUND_ALT = TOKEN_FROM_ID(396, OperatorTokenType|AltTokenType), + T_POUND_TRIGRAPH = TOKEN_FROM_ID(396, OperatorTokenType|TriGraphTokenType), + T_ANY = TOKEN_FROM_ID(397, UnknownTokenType), + T_PP_INCLUDE = TOKEN_FROM_ID(398, PPTokenType), + T_PP_QHEADER = TOKEN_FROM_ID(399, PPTokenType), + T_PP_HHEADER = TOKEN_FROM_ID(400, PPTokenType), + T_PP_INCLUDE_NEXT = TOKEN_FROM_ID(398, PPTokenType|AltTokenType), + T_PP_QHEADER_NEXT = TOKEN_FROM_ID(399, PPTokenType|AltTokenType), + T_PP_HHEADER_NEXT = TOKEN_FROM_ID(400, PPTokenType|AltTokenType), + T_EOF = TOKEN_FROM_ID(401, EOFTokenType), // end of file reached + T_EOI = TOKEN_FROM_ID(402, EOFTokenType), // end of input reached + +// MS extensions + T_MSEXT_INT8 = TOKEN_FROM_ID(403, KeywordTokenType), + T_MSEXT_INT16 = TOKEN_FROM_ID(404, KeywordTokenType), + T_MSEXT_INT32 = TOKEN_FROM_ID(405, KeywordTokenType), + T_MSEXT_INT64 = TOKEN_FROM_ID(406, KeywordTokenType), + T_MSEXT_BASED = TOKEN_FROM_ID(407, KeywordTokenType), + T_MSEXT_DECLSPEC = TOKEN_FROM_ID(408, KeywordTokenType), + T_MSEXT_CDECL = TOKEN_FROM_ID(409, KeywordTokenType), + T_MSEXT_FASTCALL = TOKEN_FROM_ID(410, KeywordTokenType), + T_MSEXT_STDCALL = TOKEN_FROM_ID(411, KeywordTokenType), + T_MSEXT_TRY = TOKEN_FROM_ID(412, KeywordTokenType), + T_MSEXT_EXCEPT = TOKEN_FROM_ID(413, KeywordTokenType), + T_MSEXT_FINALLY = TOKEN_FROM_ID(414, KeywordTokenType), + T_MSEXT_LEAVE = TOKEN_FROM_ID(415, KeywordTokenType), + T_MSEXT_INLINE = TOKEN_FROM_ID(416, KeywordTokenType), + T_MSEXT_ASM = TOKEN_FROM_ID(417, KeywordTokenType), + + T_MSEXT_PP_REGION = TOKEN_FROM_ID(418, PPTokenType), + T_MSEXT_PP_ENDREGION = TOKEN_FROM_ID(419, PPTokenType), + + T_LAST_TOKEN_ID, + T_LAST_TOKEN = ID_FROM_TOKEN(T_LAST_TOKEN_ID), + +// pseudo tokens to help streamlining macro replacement, these should not +// returned from the lexer nor should these be returned from the pp-iterator + T_NONREPLACABLE_IDENTIFIER = TOKEN_FROM_ID(T_LAST_TOKEN+1, IdentifierTokenType), + T_PLACEHOLDER = TOKEN_FROM_ID(T_LAST_TOKEN+2, WhiteSpaceTokenType), + T_PLACEMARKER = TOKEN_FROM_ID(T_LAST_TOKEN+3, InternalTokenType), + T_PARAMETERBASE = TOKEN_FROM_ID(T_LAST_TOKEN+4, ParameterTokenType), + T_EXTPARAMETERBASE = TOKEN_FROM_ID(T_LAST_TOKEN+5, ExtParameterTokenType), +}; + +/////////////////////////////////////////////////////////////////////////////// +// redefine the TOKEN_FROM_ID macro to be more type safe +#undef TOKEN_FROM_ID +#define TOKEN_FROM_ID(id, cat) boost::wave::token_id((id) | (cat)) +#define BASE_TOKEN(tok) \ + boost::wave::token_id((tok) & MainTokenMask) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// return a token name +inline BOOST_WAVE_STRINGTYPE +get_token_name(token_id tokid) +{ +// Table of token names +// +// Please note that the sequence of token names must match the sequence of +// token id's defined in then enum token_id above. +static char const *tok_names[] = { + /* 256 */ "AND", + /* 257 */ "ANDAND", + /* 258 */ "ASSIGN", + /* 259 */ "ANDASSIGN", + /* 260 */ "OR", + /* 261 */ "ORASSIGN", + /* 262 */ "XOR", + /* 263 */ "XORASSIGN", + /* 264 */ "COMMA", + /* 265 */ "COLON", + /* 266 */ "DIVIDE", + /* 267 */ "DIVIDEASSIGN", + /* 268 */ "DOT", + /* 269 */ "DOTSTAR", + /* 270 */ "ELLIPSIS", + /* 271 */ "EQUAL", + /* 272 */ "GREATER", + /* 273 */ "GREATEREQUAL", + /* 274 */ "LEFTBRACE", + /* 275 */ "LESS", + /* 276 */ "LESSEQUAL", + /* 277 */ "LEFTPAREN", + /* 278 */ "LEFTBRACKET", + /* 279 */ "MINUS", + /* 280 */ "MINUSASSIGN", + /* 281 */ "MINUSMINUS", + /* 282 */ "PERCENT", + /* 283 */ "PERCENTASSIGN", + /* 284 */ "NOT", + /* 285 */ "NOTEQUAL", + /* 286 */ "OROR", + /* 287 */ "PLUS", + /* 288 */ "PLUSASSIGN", + /* 289 */ "PLUSPLUS", + /* 290 */ "ARROW", + /* 291 */ "ARROWSTAR", + /* 292 */ "QUESTION_MARK", + /* 293 */ "RIGHTBRACE", + /* 294 */ "RIGHTPAREN", + /* 295 */ "RIGHTBRACKET", + /* 296 */ "COLON_COLON", + /* 297 */ "SEMICOLON", + /* 298 */ "SHIFTLEFT", + /* 299 */ "SHIFTLEFTASSIGN", + /* 300 */ "SHIFTRIGHT", + /* 301 */ "SHIFTRIGHTASSIGN", + /* 302 */ "STAR", + /* 303 */ "COMPL", + /* 304 */ "STARASSIGN", + /* 305 */ "ASM", + /* 306 */ "AUTO", + /* 307 */ "BOOL", + /* 308 */ "FALSE", + /* 309 */ "TRUE", + /* 310 */ "BREAK", + /* 311 */ "CASE", + /* 312 */ "CATCH", + /* 313 */ "CHAR", + /* 314 */ "CLASS", + /* 315 */ "CONST", + /* 316 */ "CONSTCAST", + /* 317 */ "CONTINUE", + /* 318 */ "DEFAULT", + /* 319 */ "DEFINED", + /* 320 */ "DELETE", + /* 321 */ "DO", + /* 322 */ "DOUBLE", + /* 323 */ "DYNAMICCAST", + /* 324 */ "ELSE", + /* 325 */ "ENUM", + /* 326 */ "EXPLICIT", + /* 327 */ "EXPORT", + /* 328 */ "EXTERN", + /* 329 */ "FLOAT", + /* 330 */ "FOR", + /* 331 */ "FRIEND", + /* 332 */ "GOTO", + /* 333 */ "IF", + /* 334 */ "INLINE", + /* 335 */ "INT", + /* 336 */ "LONG", + /* 337 */ "MUTABLE", + /* 338 */ "NAMESPACE", + /* 339 */ "NEW", + /* 340 */ "OPERATOR", + /* 341 */ "PRIVATE", + /* 342 */ "PROTECTED", + /* 343 */ "PUBLIC", + /* 344 */ "REGISTER", + /* 345 */ "REINTERPRETCAST", + /* 346 */ "RETURN", + /* 347 */ "SHORT", + /* 348 */ "SIGNED", + /* 349 */ "SIZEOF", + /* 350 */ "STATIC", + /* 351 */ "STATICCAST", + /* 352 */ "STRUCT", + /* 353 */ "SWITCH", + /* 354 */ "TEMPLATE", + /* 355 */ "THIS", + /* 356 */ "THROW", + /* 357 */ "TRY", + /* 358 */ "TYPEDEF", + /* 359 */ "TYPEID", + /* 360 */ "TYPENAME", + /* 361 */ "UNION", + /* 362 */ "UNSIGNED", + /* 363 */ "USING", + /* 364 */ "VIRTUAL", + /* 365 */ "VOID", + /* 366 */ "VOLATILE", + /* 367 */ "WCHART", + /* 368 */ "WHILE", + /* 369 */ "PP_DEFINE", + /* 370 */ "PP_IF", + /* 371 */ "PP_IFDEF", + /* 372 */ "PP_IFNDEF", + /* 373 */ "PP_ELSE", + /* 374 */ "PP_ELIF", + /* 375 */ "PP_ENDIF", + /* 376 */ "PP_ERROR", + /* 377 */ "PP_LINE", + /* 378 */ "PP_PRAGMA", + /* 379 */ "PP_UNDEF", + /* 380 */ "PP_WARNING", + /* 381 */ "IDENTIFIER", + /* 382 */ "OCTALINT", + /* 383 */ "DECIMALINT", + /* 384 */ "HEXAINT", + /* 385 */ "INTLIT", + /* 386 */ "FLOATLIT", + /* 387 */ "CCOMMENT", + /* 388 */ "CPPCOMMENT", + /* 389 */ "CHARLIT", + /* 390 */ "STRINGLIT", + /* 391 */ "CONTLINE", + /* 392 */ "SPACE", + /* 393 */ "SPACE2", + /* 394 */ "NEWLINE", + /* 395 */ "POUND_POUND", + /* 396 */ "POUND", + /* 397 */ "ANY", + /* 398 */ "PP_INCLUDE", + /* 399 */ "PP_QHEADER", + /* 400 */ "PP_HHEADER", + /* 401 */ "EOF", + /* 402 */ "EOI", + + // MS extensions + /* 403 */ "MSEXT_INT8", + /* 404 */ "MSEXT_INT16", + /* 405 */ "MSEXT_INT32", + /* 406 */ "MSEXT_INT64", + /* 407 */ "MSEXT_BASED", + /* 408 */ "MSEXT_DECLSPEC", + /* 409 */ "MSEXT_CDECL", + /* 410 */ "MSEXT_FASTCALL", + /* 411 */ "MSEXT_STDCALL", + /* 412 */ "MSEXT_TRY", + /* 413 */ "MSEXT_EXCEPT", + /* 414 */ "MSEXT_FINALLY", + /* 415 */ "MSEXT_LEAVE", + /* 416 */ "MSEXT_INLINE", + /* 417 */ "MSEXT_ASM", + /* 418 */ "MSEXT_REGION", + /* 419 */ "MSEXT_ENDREGION", + }; + + unsigned int id = BASEID_FROM_TOKEN(tokid)-T_FIRST_TOKEN; + + BOOST_ASSERT(id < T_LAST_TOKEN-T_FIRST_TOKEN); + return tok_names[id]; +} + +/////////////////////////////////////////////////////////////////////////////// +// return a token name +inline char const * +get_token_value(token_id tokid) +{ +// Table of token values +// +// Please note that the sequence of token names must match the sequence of +// token id's defined in then enum token_id above. +static char const *tok_names[] = { + /* 256 */ "&", + /* 257 */ "&&", + /* 258 */ "=", + /* 259 */ "&=", + /* 260 */ "|", + /* 261 */ "|=", + /* 262 */ "^", + /* 263 */ "^=", + /* 264 */ ",", + /* 265 */ ":", + /* 266 */ "/", + /* 267 */ "/=", + /* 268 */ ".", + /* 269 */ ".*", + /* 270 */ "...", + /* 271 */ "==", + /* 272 */ ">", + /* 273 */ ">=", + /* 274 */ "{", + /* 275 */ "<", + /* 276 */ "<=", + /* 277 */ "(", + /* 278 */ "[", + /* 279 */ "-", + /* 280 */ "-=", + /* 281 */ "--", + /* 282 */ "%", + /* 283 */ "%=", + /* 284 */ "!", + /* 285 */ "!=", + /* 286 */ "||", + /* 287 */ "+", + /* 288 */ "+=", + /* 289 */ "++", + /* 290 */ "->", + /* 291 */ "->*", + /* 292 */ "?", + /* 293 */ "}", + /* 294 */ ")", + /* 295 */ "]", + /* 296 */ "::", + /* 297 */ ";", + /* 298 */ "<<", + /* 299 */ "<<=", + /* 300 */ ">>", + /* 301 */ ">>=", + /* 302 */ "*", + /* 303 */ "~", + /* 304 */ "*=", + /* 305 */ "asm", + /* 306 */ "auto", + /* 307 */ "bool", + /* 308 */ "false", + /* 309 */ "true", + /* 310 */ "break", + /* 311 */ "case", + /* 312 */ "catch", + /* 313 */ "char", + /* 314 */ "class", + /* 315 */ "const", + /* 316 */ "const_cast", + /* 317 */ "continue", + /* 318 */ "default", + /* 319 */ "defined", + /* 320 */ "delete", + /* 321 */ "do", + /* 322 */ "double", + /* 323 */ "dynamic_cast", + /* 324 */ "else", + /* 325 */ "enum", + /* 326 */ "explicit", + /* 327 */ "export", + /* 328 */ "extern", + /* 329 */ "float", + /* 330 */ "for", + /* 331 */ "friend", + /* 332 */ "goto", + /* 333 */ "if", + /* 334 */ "inline", + /* 335 */ "int", + /* 336 */ "long", + /* 337 */ "mutable", + /* 338 */ "namespace", + /* 339 */ "new", + /* 340 */ "operator", + /* 341 */ "private", + /* 342 */ "protected", + /* 343 */ "public", + /* 344 */ "register", + /* 345 */ "reinterpret_cast", + /* 346 */ "return", + /* 347 */ "short", + /* 348 */ "signed", + /* 349 */ "sizeof", + /* 350 */ "static", + /* 351 */ "static_cast", + /* 352 */ "struct", + /* 353 */ "switch", + /* 354 */ "template", + /* 355 */ "this", + /* 356 */ "throw", + /* 357 */ "try", + /* 358 */ "typedef", + /* 359 */ "typeid", + /* 360 */ "typename", + /* 361 */ "union", + /* 362 */ "unsigned", + /* 363 */ "using", + /* 364 */ "virtual", + /* 365 */ "void", + /* 366 */ "volatile", + /* 367 */ "wchar_t", + /* 368 */ "while", + /* 369 */ "#define", + /* 370 */ "#if", + /* 371 */ "#ifdef", + /* 372 */ "#ifndef", + /* 373 */ "#else", + /* 374 */ "#elif", + /* 375 */ "#endif", + /* 376 */ "#error", + /* 377 */ "#line", + /* 378 */ "#pragma ", + /* 379 */ "#undef ", + /* 380 */ "#warning", + /* 381 */ "", // identifier + /* 382 */ "", // octalint + /* 383 */ "", // decimalint + /* 384 */ "", // hexlit + /* 385 */ "", // intlit + /* 386 */ "", // floatlit + /* 387 */ "", // ccomment + /* 388 */ "", // cppcomment + /* 389 */ "", // charlit + /* 390 */ "", // stringlit + /* 391 */ "", // contline + /* 392 */ "", // space + /* 393 */ "", // space2 + /* 394 */ "\n", + /* 395 */ "##", + /* 396 */ "#", + /* 397 */ "", // any + /* 398 */ "#include", + /* 399 */ "#include", + /* 400 */ "#include", + /* 401 */ "", // eof + /* 402 */ "", // eoi + + // MS extensions + /* 403 */ "__int8", + /* 404 */ "__int16", + /* 405 */ "__int32", + /* 406 */ "__int64", + /* 407 */ "__based", + /* 408 */ "__declspec", + /* 409 */ "__cdecl", + /* 410 */ "__fastcall", + /* 411 */ "__stdcall", + /* 412 */ "__try", + /* 413 */ "__except", + /* 414 */ "__finally", + /* 415 */ "__leave", + /* 416 */ "__inline", + /* 417 */ "__asm", + /* 418 */ "#region", + /* 419 */ "#endregion", + }; + + unsigned int id = BASEID_FROM_TOKEN(tokid)-T_FIRST_TOKEN; + + BOOST_ASSERT(id < T_LAST_TOKEN-T_FIRST_TOKEN); + return tok_names[id]; +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +#endif // #if !defined(BOOST_WAVE_TOKEN_IDS_DEFINED) + +#endif // !defined(TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED) + diff --git a/include/boost/wave/util/cpp_ifblock.hpp b/include/boost/wave/util/cpp_ifblock.hpp new file mode 100644 index 000000000..3c4ccb3e0 --- /dev/null +++ b/include/boost/wave/util/cpp_ifblock.hpp @@ -0,0 +1,147 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED) +#define CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// the class if_blocks handles recursive conditional compilation contexts +class if_block +{ +public: + if_block() : + status(true), some_part_status(true), + enclosing_status(true), is_in_else(false) + { + } + if_block(bool status_, bool enclosing_status_) : + status(status_), + some_part_status(status_), + enclosing_status(enclosing_status_), + is_in_else(false) + { + } + + void set_status(bool status_) + { + status = status_; + if (status_) + some_part_status = true; + } + bool get_status() const { return status; } + bool get_some_part_status() const { return some_part_status; } + bool get_enclosing_status() const { return enclosing_status; } + bool get_in_else() const { return is_in_else; } + void set_in_else() { is_in_else = true; } + +private: + bool status; // Current block is true + bool some_part_status; // One of the preceeding or current #if/#elif was true + bool enclosing_status; // Enclosing #if block is true + bool is_in_else; // Inside the #else part +}; + +/////////////////////////////////////////////////////////////////////////////// +// stack of conditional compilation contexts +class if_block_stack +: private std::stack +{ +public: + typedef std::stack::size_type size_type; + + void enter_if_block(bool new_status) + { + // If enclosing block is false, then this block is also false + bool enclosing_status = get_status(); + this->push (value_type (new_status && enclosing_status, enclosing_status)); + } + bool enter_elif_block(bool new_status) + { + if (!is_inside_ifpart()) + return false; // #elif without matching #if + + if (get_enclosing_status()) { + if (get_status()) { + // entered a (false) #elif block from a true block + this->top().set_status(false); + } + else if (new_status && !this->top().get_some_part_status()) { + // Entered true #elif block and no previous block was true + this->top().set_status(new_status); + } + } + return true; + } + bool enter_else_block() + { + if (!is_inside_ifpart()) + return false; // #else without matching #if + + if (get_enclosing_status()) { + if (!this->top().get_some_part_status()) { + // Entered (true) #else block and no previous block was true + this->top().set_status(true); + } + else if (get_status()) { + // Entered (false) #else block from true block + this->top().set_status(false); + } + + // Set else flag + this->top().set_in_else(); + } + return true; + } + bool exit_if_block() + { + if (0 == this->size()) + return false; // #endif without matching #if + + this->pop(); + return true; + } + +// return, wether the top (innermost) condition is true or false + bool get_status() const + { + return 0 == this->size() || this->top().get_status(); + } + + size_type get_if_block_depth() const { return this->size(); } + +protected: + bool get_enclosing_status() const + { + return 0 == this->size() || this->top().get_enclosing_status(); + } + + bool is_inside_ifpart() const + { + return 0 != this->size() && !this->top().get_in_else(); + } + bool is_inside_elsepart() const + { + return 0 != this->size() && this->top().get_in_else(); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED) diff --git a/include/boost/wave/util/cpp_include_pathes.hpp b/include/boost/wave/util/cpp_include_pathes.hpp new file mode 100644 index 000000000..1e8e2b011 --- /dev/null +++ b/include/boost/wave/util/cpp_include_pathes.hpp @@ -0,0 +1,218 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_INCLUDE_PATHES_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED) +#define CPP_INCLUDE_PATHES_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED + +#include +#include +#include + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// +// include_pathes - controlling the include path search order +// +// General notes: +// +// Any directories specified with the 'add_include_path()' function before +// the function 'set_sys_include_delimiter()' is called are searched only +// for the case of '#include "file"' directives, they are not searched for +// '#include ' directives. If additional directories are specified +// with the 'add_include_path()' function after a call to the function +// 'set_sys_include_delimiter()', these directories are searched for all +// '#include' directives. +// +// In addition, a call to the function 'set_sys_include_delimiter()' +// inhibits the use of the current directory as the first search directory +// for '#include "file"' directives. Therefore, the current directory is +// searched only if it is requested explicitly with a call to the function +// 'add_include_path(".")'. +// +// Calling both functions, the 'set_sys_include_delimiter()' and +// 'add_include_path(".")' allows you to control precisely which +// directories are searched before the current one and which are searched +// after. +// +/////////////////////////////////////////////////////////////////////////////// +class include_pathes +{ + typedef std::list include_list_t; + typedef std::set pragma_once_set_t; + +public: + include_pathes() + : was_sys_include_path(false), + current_dir(boost::filesystem::initial_path()) + {} + + bool add_include_path(char const *path_, bool is_system = false) + { + return add_include_path(path_, (is_system || was_sys_include_path) ? + system_include_pathes : user_include_pathes); + } + void set_sys_include_delimiter() { was_sys_include_path = true; } + bool find_include_file (std::string &s, bool is_system, + char const *current_file) const; + void set_current_directory(char const *path_); + + void init_initial_path() { boost::filesystem::initial_path(); } + +protected: + bool find_include_file (std::string &s, include_list_t const &pathes, + char const *) const; + bool add_include_path(char const *path_, include_list_t &pathes_); + +private: + include_list_t user_include_pathes; + include_list_t system_include_pathes; + bool was_sys_include_path; // saw a set_sys_include_delimiter() + boost::filesystem::path current_dir; + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +public: + bool has_pragma_once(std::string const &filename) + { + return pragma_once_files.find(filename) != pragma_once_files.end(); + } + bool add_pragma_once_header(std::string const &filename) + { + return pragma_once_files.insert(filename).second; + } + +private: + pragma_once_set_t pragma_once_files; +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +// Add an include path to one of the search lists (user include path or system +// include path). +inline +bool include_pathes::add_include_path ( + char const *path_, include_list_t &pathes_) +{ + namespace fs = boost::filesystem; + if (path_) { + fs::path newpath = fs::complete(fs::path(path_, fs::native), current_dir); + + if (!fs::exists(newpath) || !fs::is_directory(newpath)) { + // the given path does not form a name of a valid file system directory + // item + return false; + } + + pathes_.push_back (newpath); + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// Find an include file by traversing the list of include directories +inline +bool include_pathes::find_include_file (std::string &s, + include_list_t const &pathes, char const *current_file) const +{ + namespace fs = boost::filesystem; + typedef include_list_t::const_iterator const_include_list_iter_t; + + const_include_list_iter_t include_pathes_end = pathes.end(); + for (const_include_list_iter_t it = pathes.begin(); + it != include_pathes_end; ++it) + { + fs::path currpath ((*it).string(), fs::native); + currpath /= fs::path(s, fs::native); // append filename + + if (fs::exists(currpath) && + ( 0 == current_file || + strcmp(currpath.native_file_string().c_str(), current_file) + ) + ) + { + // found the required file + s = currpath.string(); + return true; + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// Find an include file by searching the user and system includes in the +// correct sequence (as it was configured by the user of the driver program) +inline bool +include_pathes::find_include_file (std::string &s, bool is_system, + char const *current_file) const +{ + namespace fs = boost::filesystem; + +// if not system include (<...>), then search current directory first + if (!is_system) { + if (!was_sys_include_path) { // set_sys_include_delimiter() not called + // first look in the current directory + fs::path currpath (current_dir.string(), fs::native); + currpath /= fs::path(s, fs::native); + if (fs::exists(currpath) && + ( 0 == current_file || + strcmp(currpath.native_file_string().c_str(), current_file) + ) + ) + { + s = currpath.string(); // found in local directory + return true; + } + + // iterate all user include file directories to find the file + return find_include_file(s, user_include_pathes, current_file); + } + + // iterate all user include file directories to find the file + if (find_include_file(s, user_include_pathes, current_file)) + return true; + + // if nothing found, fall through + // ... + } + +// iterate all system include file directories to find the file + return find_include_file (s, system_include_pathes, current_file); +} + +/////////////////////////////////////////////////////////////////////////////// +// Set current directory from a given file name + +inline +void include_pathes::set_current_directory(char const *path_) +{ + namespace fs = boost::filesystem; + + fs::path filename = fs::complete(fs::path(path_, fs::native), current_dir); + if (fs::exists(filename) && fs::is_directory(filename)) + current_dir = filename; + else + current_dir = filename.branch_path(); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_INCLUDE_PATHES_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED) diff --git a/include/boost/wave/util/cpp_iterator.hpp b/include/boost/wave/util/cpp_iterator.hpp new file mode 100644 index 000000000..ac8405a98 --- /dev/null +++ b/include/boost/wave/util/cpp_iterator.hpp @@ -0,0 +1,1729 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the preprocessor iterator + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED) +#define CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 +#include +#endif + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// retrieve the macro name from the parse tree +template +inline void +retrieve_macroname(ParseNodeT const &node, boost::spirit::parser_id id, + TokenT ¯oname, PositionT const &act_pos) +{ +ParseNodeT const *name_node = 0; + + typedef boost::wave::grammars::cpp_grammar_gen cpp_grammar_type; + using boost::spirit::find_node; + if (!find_node(node, id, &name_node)) + { + // ill formed define statement (unexpected, should not happen) + BOOST_WAVE_THROW(preprocess_exception, bad_define_statement, + "bad parse tree (unexpected)", act_pos); + } + +typename ParseNodeT::children_t const &children = name_node->children; + + if (0 == children.size() || + children[0].value.begin() == children[0].value.end()) + { + // ill formed define statement (unexpected, should not happen) + BOOST_WAVE_THROW(preprocess_exception, bad_define_statement, + "bad parse tree (unexpected)", act_pos); + } + +// retrieve the macro name + macroname = *children[0].value.begin(); +} + +/////////////////////////////////////////////////////////////////////////////// +// retrieve the macro parameters or the macro definition from the parse tree +template +inline bool +retrieve_macrodefinition( + ParseNodeT const &node, boost::spirit::parser_id id, + ContainerT ¯odefinition, TokenT const &/*t*/) +{ + using namespace boost::wave; + typedef typename ParseNodeT::const_tree_iterator const_tree_iterator; + +// find macro parameters/macro definition inside the parse tree +std::pair nodes; + + using boost::spirit::get_node_range; + if (get_node_range(node, id, nodes)) { + // copy all parameters to the supplied container + typename ContainerT::iterator last_nonwhite = macrodefinition.end(); + const_tree_iterator end = nodes.second; + + for (const_tree_iterator cit = nodes.first; cit != end; ++cit) { + if ((*cit).value.begin() != (*cit).value.end()) { + typename ContainerT::iterator inserted = macrodefinition.insert( + macrodefinition.end(), *(*cit).value.begin()); + + if (!IS_CATEGORY(macrodefinition.back(), WhiteSpaceTokenType) && + T_NEWLINE != token_id(macrodefinition.back()) && + T_EOF != token_id(macrodefinition.back())) + { + last_nonwhite = inserted; + } + } + } + + // trim trailing whitespace (leading whitespace is trimmed by the grammar) + if (last_nonwhite != macrodefinition.end()) { + macrodefinition.erase(++last_nonwhite, macrodefinition.end()); + } + return true; + } + return false; +} + +#if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 +/////////////////////////////////////////////////////////////////////////////// +// add an additional predefined macro given by a string (MACRO(x)=definition) +template +bool add_macro_definition(ContextT &ctx, std::string macrostring, + bool is_predefined, boost::wave::language_support language) +{ + typedef typename ContextT::token_type token_type; + typedef typename ContextT::lexer_type lexer_type; + typedef typename token_type::position_type position_type; + typedef boost::wave::grammars::predefined_macros_grammar_gen + predef_macros_type; + + using namespace boost::wave; + using namespace std; // isspace is in std namespace for some systems + +// skip leading whitespace +std::string::iterator begin = macrostring.begin(); +std::string::iterator end = macrostring.end(); + + while(begin != end && isspace(*begin)) + ++begin; + +// parse the macro definition +position_type act_pos("command line", 0); +boost::spirit::tree_parse_info hit = + predef_macros_type::parse_predefined_macro( + lexer_type(begin, end, position_type(), language), lexer_type()); + + if (!hit.match || (!hit.full && T_EOF != token_id(*hit.stop))) { + BOOST_WAVE_THROW(preprocess_exception, bad_macro_definition, macrostring, + act_pos); + } + +// retrieve the macro definition from the parse tree +token_type macroname; +std::vector macroparameters; +typename ContextT::token_sequence_type macrodefinition; +bool has_parameters = false; + + boost::wave::util::retrieve_macroname(*hit.trees.begin(), + predef_macros_type::rule_ids.plain_define_id, macroname, act_pos); + has_parameters = boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(), + predef_macros_type::rule_ids.macro_parameters_id, macroparameters, + token_type()); + boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(), + predef_macros_type::rule_ids.macro_definition_id, macrodefinition, + token_type()); + +// If no macrodefinition is given, and the macro string does not end with a +// '=', then the macro should be defined with the value '1' + if (0 == macrodefinition.size() && + '=' != macrostring[macrostring.size()-1]) + { + macrodefinition.push_back(token_type(T_INTLIT, "1", act_pos)); + } + +// add the new macro to the macromap + return ctx.add_macro_definition(macroname, has_parameters, macroparameters, + macrodefinition, is_predefined); +} +#endif // BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util + +/////////////////////////////////////////////////////////////////////////////// +// forward declaration +template class pp_iterator; + +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// pp_iterator_functor +// +/////////////////////////////////////////////////////////////////////////////// +template +class pp_iterator_functor { + +public: +// interface to the boost::spirit::multi_pass_policies::functor_input policy + typedef typename ContextT::token_type result_type; + +// eof token + static result_type const eof; + +private: + typedef typename ContextT::lexer_type lexer_type; + typedef typename result_type::string_type string_type; + typedef boost::wave::grammars::cpp_grammar_gen + cpp_grammar_type; + +// iteration context related types (an iteration context represents a current +// position in an included file) + typedef base_iteration_context base_iteration_context_type; + typedef + iteration_context + iteration_context_t; + +// parse tree related types + typedef + boost::spirit::node_val_data_factory + node_factory_t; + typedef + boost::spirit::tree_match + parse_tree_match_t; + typedef typename parse_tree_match_t::node_t parse_node_type; // tree_node > + typedef typename parse_tree_match_t::parse_node_t parse_node_value_type; // node_val_data<> + typedef typename parse_tree_match_t::container_t parse_tree_type; // parse_node_type::children_t + +// type of a token sequence + typedef typename ContextT::token_sequence_type token_sequence_type; + +public: + template + pp_iterator_functor(ContextT &ctx_, IteratorT const &first_, + IteratorT const &last_, typename ContextT::position_type const &pos_, + boost::wave::language_support language) + : ctx(ctx_), + iter_ctx(new base_iteration_context_type( + lexer_type(first_, last_, pos_, language), lexer_type(), + pos_.get_file().c_str() + )), + seen_newline(true), must_emit_line_directive(false), + act_pos(ctx_.get_main_pos()), last_line(0) + { + act_pos.set_file(pos_.get_file()); +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + ctx_.set_current_filename(pos_.get_file().c_str()); +#endif + } + +// get the next preprocessed token + result_type const &operator()(); + +// get the last recognized token (for error processing etc.) + result_type const ¤t_token() const { return act_token; } + +protected: + friend class pp_iterator; + void on_include_helper(char const *s, bool is_system, bool include_next); + +protected: + result_type const &get_next_token(); + result_type const &pp_token(bool consider_emitting_line_directive = false); + + bool pp_directive(); + bool dispatch_directive(boost::spirit::tree_parse_info const &hit); + + void on_include(string_type const &s, bool is_system, bool include_next); + void on_include(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end, bool include_next); + + void on_define(parse_node_type const &node); + void on_undefine(result_type const &t); + + void on_ifdef(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end); + void on_ifndef(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end); + void on_else(); + void on_endif(); + void on_illformed(typename result_type::string_type const &s); + + void on_line(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end); + void on_if(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end); + void on_elif(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end); + void on_error(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end); +#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 + void on_warning(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end); +#endif + bool on_pragma(typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end); + + result_type const &emit_line_directive(); + bool returned_from_include(); + + bool interpret_pragma(token_sequence_type const &pragma_body, + token_sequence_type &result); + +private: + ContextT &ctx; // context, this iterator is associated with + boost::shared_ptr iter_ctx; + + bool seen_newline; // needed for recognizing begin of line + bool must_emit_line_directive; // must emit a line directive + result_type act_token; // current token + typename result_type::position_type &act_pos; // current fileposition (references the macromap) + int last_line; // line number of the previous token + + token_sequence_type unput_queue; // tokens to be preprocessed again + token_sequence_type pending_queue; // tokens already preprocessed + + // detect whether to insert additional whitespace in between two adjacent + // tokens, which otherwise would form a different token type, if + // retokenized + boost::wave::util::insert_whitespace_detection whitespace; + + // remove not needed whitespace from the output stream + boost::wave::util::eat_whitespace eater; +}; + +/////////////////////////////////////////////////////////////////////////////// +// eof token +template +typename pp_iterator_functor::result_type const + pp_iterator_functor::eof; + +/////////////////////////////////////////////////////////////////////////////// +// +// returned_from_include() +// +// Tests if it is necessary to pop the include file context (eof inside +// a file was reached). If yes, it pops this context. Preprocessing will +// continue with the next outer file scope. +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +pp_iterator_functor::returned_from_include() +{ + if (iter_ctx->first == iter_ctx->last && ctx.get_iteration_depth() > 0) { + // call the include policy trace function + ctx.get_trace_policy().returning_from_include_file(); + + // restore the previous iteration context after finishing the preprocessing + // of the included file + iter_ctx = ctx.pop_iteration_context(); + + must_emit_line_directive = true; + seen_newline = true; + + // restore current file position + act_pos.set_file(iter_ctx->filename); +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + ctx.set_current_filename(iter_ctx->real_filename.c_str()); +#endif + + last_line = iter_ctx->line; + act_pos.set_line(last_line); + act_pos.set_column(0); + + // restore the actual current directory + ctx.set_current_directory(iter_ctx->real_filename.c_str()); + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// operator()(): get the next preprocessed token +// +// throws a preprocess_exception, if appropriate +// +/////////////////////////////////////////////////////////////////////////////// +template +inline typename pp_iterator_functor::result_type const & +pp_iterator_functor::operator()() +{ + using namespace boost::wave; + +// loop over skippable whitespace until something significant is found +bool skipped_newline = false; +bool was_seen_newline = seen_newline; + + do { + // get_next_token assigns result to act_token member + if (!seen_newline && skipped_newline) + seen_newline = true; + get_next_token(); + + } while (eater.may_skip(act_token, skipped_newline)); + +token_id id = token_id(act_token); + +// if there were skipped any newline, we must emit a #line directive + if ((must_emit_line_directive || (was_seen_newline && skipped_newline)) && + !IS_CATEGORY(id, WhiteSpaceTokenType) && + !IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType)) + { + // must emit a #line directive + emit_line_directive(); + eater.may_skip(act_token, skipped_newline); // feed ws eater FSM + id = token_id(act_token); + } + +// cleanup of certain tokens required + seen_newline = skipped_newline; + switch (id) { + case T_NONREPLACABLE_IDENTIFIER: + act_token.set_token_id(T_IDENTIFIER); + break; + + case T_NEWLINE: + case T_CPPCOMMENT: + seen_newline = true; + ++iter_ctx->emitted_lines; + break; + + case T_EOF: + seen_newline = true; + break; + + default: + break; + } + + if (whitespace.must_insert(id, act_token.get_value())) { + // must insert some whitespace into the output stream to avoid adjacent + // tokens, which would form different (and wrong) tokens + whitespace.shift_tokens(T_SPACE); + pending_queue.push_front(act_token); // push this token back + return act_token = result_type(T_SPACE, + typename result_type::string_type(" "), + act_token.get_position()); + } + whitespace.shift_tokens(id); + return act_token; +} + + +template +inline typename pp_iterator_functor::result_type const & +pp_iterator_functor::get_next_token() +{ + using namespace boost::wave; + +// if there is something in the unput_queue, then return the next token from +// there (all tokens in the queue are preprocessed already) + if (pending_queue.size() > 0 || unput_queue.size() > 0) + return pp_token(); // return next token + +// test for EOF, if there is a pending input context, pop it back and continue +// parsing with it +bool returned_from_include_file = returned_from_include(); + +// try to generate the next token + if (iter_ctx->first != iter_ctx->last) { + do { + // If there are pending tokens in the queue, we'll have to return + // these. This may happen from a #pragma directive, which got replaced + // by some token sequence. + if (!pending_queue.empty()) { + util::on_exit::pop_front + pop_front_token(pending_queue); + + whitespace.shift_tokens(act_token = pending_queue.front()); + return act_token; + } + + // fetch the current token + act_token = *iter_ctx->first; + + // adjust the current position (line and column) + bool was_seen_newline = seen_newline || returned_from_include_file; + int current_line = act_token.get_position().get_line(); + + act_pos.set_line(act_pos.get_line() + current_line - last_line); + act_pos.set_column(act_token.get_position().get_column()); + last_line = current_line; + + // act accordingly on the current token + token_id id = token_id(act_token); + + if (T_EOF == id) { + if (!seen_newline) { + // warn, if this file does not end with a newline + BOOST_WAVE_THROW(preprocess_exception, last_line_not_terminated, + "", act_pos); + } + + // returned from an include file, continue with the next token + whitespace.shift_tokens(T_EOF); + ++iter_ctx->first; + continue; // if this is the main file, the while loop breaks + } + else if (T_NEWLINE == id || T_CPPCOMMENT == id) { + // a newline is to be returned ASAP, a C++ comment too + // (the C++ comment token includes the trailing newline) + seen_newline = true; + ++iter_ctx->first; + whitespace.shift_tokens(T_NEWLINE); // whitespace controller + return act_token; + } + seen_newline = false; + + if (was_seen_newline && pp_directive()) { + // a pp directive was found + seen_newline = true; + must_emit_line_directive = true; + + // loop to the next token to analyze + // simply fall through, since the iterator was already adjusted + // correctly + } + else if (ctx.get_if_block_status()) { + // preprocess this token, eat up more, if appropriate, return + // the next preprocessed token + return pp_token(was_seen_newline); + } + else { + // compilation condition is false: if the current token is a + // newline, account for it, otherwise discard the actual token and + // try the next one + if (T_NEWLINE == act_token) { + seen_newline = true; + must_emit_line_directive = true; + } + + // next token + ++iter_ctx->first; + } + + } while (iter_ctx->first != iter_ctx->last || returned_from_include()); + } + + if (returned_from_include_file) { + // if there was an '#include' statement on the last line of the main file + // we have to return an additional newline token + seen_newline = true; + + whitespace.shift_tokens(T_NEWLINE); // whitespace controller + return act_token = result_type(T_NEWLINE, + typename result_type::string_type("\n"), + cpp_grammar_type::pos_of_newline); + } + +// overall eof reached + if (ctx.get_if_block_depth() > 0) { + // missing endif directive(s) + BOOST_WAVE_THROW(preprocess_exception, missing_matching_endif, "", act_pos); + } + + whitespace.shift_tokens(T_EOF); // whitespace controller + return act_token = eof; // return eof token +} + +/////////////////////////////////////////////////////////////////////////////// +// +// emit_line_directive(): emits a line directive from the act_token data +// +/////////////////////////////////////////////////////////////////////////////// +template +inline typename pp_iterator_functor::result_type const & +pp_iterator_functor::emit_line_directive() +{ + using namespace boost::wave; + +typename ContextT::position_type pos = act_token.get_position(); + + if (must_emit_line_directive || + iter_ctx->emitted_lines != act_pos.get_line()) + { + // unput the current token + pending_queue.push_front(act_token); + pos.set_line(act_pos.get_line()); + + if (!must_emit_line_directive && + iter_ctx->emitted_lines+1 == act_pos.get_line()) + { + // prefer to output a single newline instead of the #line directive + whitespace.shift_tokens(T_NEWLINE); + act_token = result_type(T_NEWLINE, "\n", pos); + } + else { + // account for the here emitted newline + act_pos.set_line(act_pos.get_line()-1); + iter_ctx->emitted_lines = act_pos.get_line(); + --last_line; + + // the #line directive has to be pushed back into the pending queue in + // reverse order + + // unput the complete #line directive + std::string file("\""); + boost::filesystem::path filename(act_pos.get_file().c_str(), + boost::filesystem::native); + + using boost::wave::util::impl::escape_lit; + file += escape_lit(filename.native_file_string()) + "\""; + pending_queue.push_front(result_type(T_NEWLINE, "\n", pos)); + pending_queue.push_front(result_type(T_STRINGLIT, file.c_str(), pos)); + pending_queue.push_front(result_type(T_SPACE, " ", pos)); + + // 21 is the max required size for a 64 bit integer represented as a + // string + char buffer[22]; + + using namespace std; // for some systems sprintf is in namespace std + sprintf (buffer, "%d", pos.get_line()); + pending_queue.push_front(result_type(T_INTLIT, buffer, pos)); + pending_queue.push_front(result_type(T_SPACE, " ", pos)); + + // return the #line token itself + whitespace.shift_tokens(T_PP_LINE); + act_token = result_type(T_PP_LINE, "#line", pos); + } + } + +// we are now in sync + must_emit_line_directive = false; + return act_token; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// pptoken(): return the next preprocessed token +// +/////////////////////////////////////////////////////////////////////////////// +template +inline typename pp_iterator_functor::result_type const & +pp_iterator_functor::pp_token(bool consider_emitting_line_directive) +{ + using namespace boost::wave; + +token_id id = token_id(*iter_ctx->first); + + // eat all T_PLACEHOLDER tokens, eventually slipped through out of the + // macro engine + do { + if (!pending_queue.empty()) { + // if there are pending tokens in the queue, return the first one + act_token = pending_queue.front(); + pending_queue.pop_front(); + } + else if (!unput_queue.empty() + || T_IDENTIFIER == id + || IS_CATEGORY(id, KeywordTokenType)) + { + // call the lexer, preprocess the required number of tokens, put them + // into the unput queue + act_token = ctx.expand_tokensequence(iter_ctx->first, + iter_ctx->last, pending_queue, unput_queue); + } + else { + // simply return the next token + act_token = *iter_ctx->first; + ++iter_ctx->first; + } + id = token_id(act_token); + + } while (T_PLACEHOLDER == id); + + return act_token; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// pp_directive(): recognize a preprocessor directive +// +/////////////////////////////////////////////////////////////////////////////// +namespace { + + template + bool next_token_is_pp_directive(IteratorT &it, IteratorT const &end) + { + using namespace boost::wave; + + token_id id = T_ANY; + for (/**/; it != end; ++it) { + id = token_id(*it); + if (!IS_CATEGORY(id, WhiteSpaceTokenType)) + break; // skip leading whitespace + if (IS_CATEGORY(id, EOLTokenType)) + break; // do not enter a new line + } + BOOST_ASSERT(it == end || id != T_ANY); + return it != end && IS_CATEGORY(id, PPTokenType); + } + + template + bool is_pp_null(IteratorT &it, IteratorT const &end) + { + using namespace boost::wave; + + BOOST_ASSERT(T_POUND == BASE_TOKEN(token_id(*it))); + for (++it; it != end; ++it) { + token_id id = token_id(*it); + + if (T_CPPCOMMENT == id || T_NEWLINE == id) { + ++it; // skip eol/C++ comment + return true; // found pp_null + } + + if (!IS_CATEGORY(id, WhiteSpaceTokenType)) + break; + } + return false; + } + + template + bool skip_to_eol(IteratorT &it, IteratorT const &end) + { + using namespace boost::wave; + + for (/**/; it != end; ++it) { + token_id id = token_id(*it); + + if (T_CPPCOMMENT == id || T_NEWLINE == id) { + ++it; // skip eol/C++ comment + return true; // found pp_null + } + } + return false; + } +} + +template +inline bool +pp_iterator_functor::pp_directive() +{ + using namespace cpplexer; + +// test, if the next non-whitespace token is a pp directive +lexer_type it = iter_ctx->first; + + if (!next_token_is_pp_directive(it, iter_ctx->last)) { + // eventually skip null pp directive (no need to do it via the parser) + if (it != iter_ctx->last && T_POUND == BASE_TOKEN(token_id(*it)) && + is_pp_null(it, iter_ctx->last)) + { + seen_newline = true; + iter_ctx->first = it; // start over with the next line + return true; + } + + // this line does not contain a pp directive, so simply return + return false; + } + + if (it == iter_ctx->last) + return false; + +// ignore all pp directives not related to conditional compilation while +// if block status is false + if (!ctx.get_if_block_status() && + !IS_EXTCATEGORY(*it, PPConditionalTokenType)) + { + seen_newline = true; + skip_to_eol(it, iter_ctx->last); + iter_ctx->first = it; // start over with the next line + return true; + } + +// found a pp directive, so try to identify it, start with the pp_token +bool found_eof = false; +boost::spirit::tree_parse_info hit = + cpp_grammar_type::parse_cpp_grammar(it, iter_ctx->last, found_eof, act_pos); + + if (hit.match) { + // position the iterator past the matched sequence to allow + // resynchronisation, if an error occurs + iter_ctx->first = hit.stop; + + // found a valid pp directive, dispatch to the correct function to handle + // the found pp directive + bool result = dispatch_directive (hit); + + if (found_eof) { + // The line was terminated with an end of file token. + // So trigger a warning, that the last line was not terminated with a + // newline. + BOOST_WAVE_THROW(preprocess_exception, last_line_not_terminated, "", + act_pos); + } + return result; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// dispatch_directive(): dispatch a recognized preprocessor directive +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +pp_iterator_functor::dispatch_directive( + boost::spirit::tree_parse_info const &hit) +{ + using namespace cpplexer; + using namespace boost::spirit; + + typedef typename parse_tree_type::const_iterator const_child_iterator_t; + +// this iterator points to the root node of the parse tree +const_child_iterator_t begin = hit.trees.begin(); + +// decide, which preprocessor directive was found +parse_tree_type const &root = (*begin).children; +parse_node_value_type const &nodeval = get_first_leaf(*root.begin()).value; +//long node_id = nodeval.id().to_long(); + +const_child_iterator_t begin_child_it = (*root.begin()).children.begin(); +const_child_iterator_t end_child_it = (*root.begin()).children.end(); + +token_id id = cpp_grammar_type::found_directive; + + switch (id) { + case T_PP_QHEADER: // #include "..." +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + case T_PP_QHEADER_NEXT: // #include_next "..." +#endif + on_include ((*nodeval.begin()).get_value(), false, + T_PP_QHEADER_NEXT == id); + break; + + case T_PP_HHEADER: // #include <...> +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + case T_PP_HHEADER_NEXT: // #include_next <...> +#endif + on_include ((*nodeval.begin()).get_value(), true, + T_PP_HHEADER_NEXT == id); + break; + + case T_PP_INCLUDE: // #include ... +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + case T_PP_INCLUDE_NEXT: // #include_next ... +#endif + on_include (begin_child_it, end_child_it, T_PP_INCLUDE_NEXT == id); + break; + + case T_PP_DEFINE: // #define + on_define (*begin); + break; + + case T_PP_UNDEF: // #undef + on_undefine(*nodeval.begin()); + break; + + case T_PP_IFDEF: // #ifdef + on_ifdef(begin_child_it, end_child_it); + break; + + case T_PP_IFNDEF: // #ifndef + on_ifndef(begin_child_it, end_child_it); + break; + + case T_PP_IF: // #if + on_if(begin_child_it, end_child_it); + break; + + case T_PP_ELIF: // #elif + on_elif(begin_child_it, end_child_it); + break; + + case T_PP_ELSE: // #else + on_else(); + break; + + case T_PP_ENDIF: // #endif + on_endif(); + break; + + case T_PP_LINE: // #line + on_line(begin_child_it, end_child_it); + break; + + case T_PP_ERROR: // #error + on_error(begin_child_it, end_child_it); + break; + +#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 + case T_PP_WARNING: // #warning + on_warning(begin_child_it, end_child_it); + break; +#endif + + case T_PP_PRAGMA: // #pragma + return on_pragma(begin_child_it, end_child_it); + +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + case T_MSEXT_PP_REGION: + case T_MSEXT_PP_ENDREGION: + break; // ignore these +#endif + + default: // #something else + on_illformed((*nodeval.begin()).get_value()); + break; + } + return true; // return newline only +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_include: handle #include <...> or #include "..." directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_include (string_type const &s, bool is_system, + bool include_next) +{ + BOOST_ASSERT(ctx.get_if_block_status()); + +// strip quotes first, extract filename +typename string_type::size_type pos_end = s.find_last_of(is_system ? '>' : '\"'); + + if (string_type::npos == pos_end) { + BOOST_WAVE_THROW(preprocess_exception, bad_include_statement, s, act_pos); + } + +typename string_type::size_type pos_begin = + s.find_last_of(is_system ? '<' : '\"', pos_end-1); + + if (string_type::npos == pos_begin) { + BOOST_WAVE_THROW(preprocess_exception, bad_include_statement, s, act_pos); + } + +std::string file_path(s.substr(pos_begin+1, pos_end-pos_begin-1).c_str()); + +// finally include the file + on_include_helper(file_path.c_str(), is_system, include_next); +} + +template +inline void +pp_iterator_functor::on_include_helper ( + char const *s, bool is_system, bool include_next) +{ + namespace fs = boost::filesystem; + +// try to locate the given file, searching through the include path lists +std::string file_path(s); +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 +char const *current_name = include_next ? iter_ctx->real_filename.c_str() : 0; +#else +char const *current_name = 0; // never try to match current file name +#endif + + if (!ctx.find_include_file (file_path, is_system, current_name)) { + BOOST_WAVE_THROW(preprocess_exception, bad_include_file, file_path, act_pos); + } + +fs::path native_path(file_path, fs::native); + + if (!fs::exists(native_path)) { + BOOST_WAVE_THROW(preprocess_exception, bad_include_file, file_path, act_pos); + } + +// test, if this file is known through a #pragma once directive +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + if (!ctx.has_pragma_once(native_path.native_file_string())) +#endif + { + // the new include file determines the actual current directory + ctx.set_current_directory(file_path.c_str()); + + // preprocess the opened file + boost::shared_ptr new_iter_ctx ( + new iteration_context_t(native_path.native_file_string().c_str(), + act_pos, ctx.get_language())); + + // call the include policy trace function + ctx.get_trace_policy().opened_include_file(file_path, + ctx.get_iteration_depth(), is_system); + + // store current file position + iter_ctx->filename = act_pos.get_file(); + iter_ctx->line = act_pos.get_line(); + + // push the old iteration context onto the stack and continue with the new + ctx.push_iteration_context(act_pos, iter_ctx); + iter_ctx = new_iter_ctx; + seen_newline = true; // fake a newline to trigger pp_directive + must_emit_line_directive = true; + + act_pos.set_file(iter_ctx->filename); // initialize file position +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + ctx.set_current_filename(iter_ctx->real_filename.c_str()); +#endif + + last_line = iter_ctx->line; + act_pos.set_line(last_line); + act_pos.set_column(0); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_include(): handle #include ... directives +// +/////////////////////////////////////////////////////////////////////////////// + +template +inline void +pp_iterator_functor::on_include( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end, bool include_next) +{ + BOOST_ASSERT(ctx.get_if_block_status()); + +// preprocess the given token sequence (the body of the #include directive) +get_token_value get_value; +token_sequence_type expanded; +token_sequence_type toexpand; + + std::copy(make_ref_transform_iterator(begin, get_value), + make_ref_transform_iterator(end, get_value), + std::inserter(toexpand, toexpand.end())); + + typename token_sequence_type::iterator begin2 = toexpand.begin(); + ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded, + false); + +// now, include the file +string_type s (trim_whitespace(boost::wave::util::impl::as_string(expanded))); +bool is_system = '<' == s[0] && '>' == s[s.size()-1]; + + if (!is_system && !('\"' == s[0] && '\"' == s[s.size()-1])) { + // should resolve into something like <...> or "..." + BOOST_WAVE_THROW(preprocess_exception, bad_include_statement, + s, act_pos); + } + on_include(s, is_system, include_next); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_define(): handle #define directives +// +/////////////////////////////////////////////////////////////////////////////// + +template +inline void +pp_iterator_functor::on_define (parse_node_type const &node) +{ + BOOST_ASSERT(ctx.get_if_block_status()); + +// retrieve the macro definition from the parse tree +result_type macroname; +std::vector macroparameters; +token_sequence_type macrodefinition; +bool has_parameters = false; + + boost::wave::util::retrieve_macroname(node, + cpp_grammar_type::rule_ids.plain_define_id, macroname, + act_token.get_position()); + has_parameters = boost::wave::util::retrieve_macrodefinition(node, + cpp_grammar_type::rule_ids.macro_parameters_id, macroparameters, act_token); + boost::wave::util::retrieve_macrodefinition(node, + cpp_grammar_type::rule_ids.macro_definition_id, macrodefinition, act_token); + + if (has_parameters) { +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (boost::wave::need_variadics(ctx.get_language())) { + // test whether ellipsis are given, and if yes, if these are placed as the + // last argument + using namespace cpplexer; + typedef typename std::vector::iterator + parameter_iterator_t; + + bool seen_ellipses = false; + parameter_iterator_t end = macroparameters.end(); + for (parameter_iterator_t pit = macroparameters.begin(); + pit != end; ++pit) + { + if (seen_ellipses) { + // ellipses are not the last given formal argument + BOOST_WAVE_THROW(preprocess_exception, bad_define_statement, + macroname.get_value(), (*pit).get_position()); + } + if (T_ELLIPSIS == token_id(*pit)) + seen_ellipses = true; + } + + // if there wasn't an ellipsis, then there shouldn't be a __VA_ARGS__ + // placeholder in the definition too [C99 Standard 6.10.3.5] + if (!seen_ellipses) { + typedef typename token_sequence_type::iterator definition_iterator_t; + + bool seen_va_args = false; + definition_iterator_t pend = macrodefinition.end(); + for (definition_iterator_t dit = macrodefinition.begin(); + dit != pend; ++dit) + { + if (T_IDENTIFIER == token_id(*dit) && + "__VA_ARGS__" == (*dit).get_value()) + { + seen_va_args = true; + } + } + if (seen_va_args) { + // must not have seen __VA_ARGS__ placeholder + BOOST_WAVE_THROW(preprocess_exception, bad_define_statement, + macroname.get_value(), act_token.get_position()); + } + } + } + else +#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + { + // test, that there is no T_ELLIPSES given + using namespace cpplexer; + typedef typename std::vector::iterator + parameter_iterator_t; + + parameter_iterator_t end = macroparameters.end(); + for (parameter_iterator_t pit = macroparameters.begin(); + pit != end; ++pit) + { + if (T_ELLIPSIS == token_id(*pit)) { + // if variadics are disabled, no ellipses should be given + BOOST_WAVE_THROW(preprocess_exception, bad_define_statement, + macroname.get_value(), (*pit).get_position()); + } + } + } + } + +// add the new macro to the macromap + ctx.add_macro_definition(macroname, has_parameters, macroparameters, + macrodefinition); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_undefine(): handle #undef directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_undefine (result_type const &token) +{ + BOOST_ASSERT(ctx.get_if_block_status()); + +// retrieve the macro name to undefine from the parse tree + ctx.remove_macro_definition(token.get_value()); // throws for predefined macros +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_ifdef(): handle #ifdef directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_ifdef( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end) +{ +get_token_value get_value; +bool is_defined = ctx.is_defined_macro( + make_ref_transform_iterator((*begin).children.begin(), get_value), + make_ref_transform_iterator((*begin).children.end(), get_value)); + + ctx.enter_if_block(is_defined); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_ifndef(): handle #ifndef directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_ifndef( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end) +{ +get_token_value get_value; +bool is_defined = ctx.is_defined_macro( + make_ref_transform_iterator((*begin).children.begin(), get_value), + make_ref_transform_iterator((*begin).children.end(), get_value)); + + ctx.enter_if_block(!is_defined); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_else(): handle #else directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_else() +{ + if (!ctx.enter_else_block()) { + // #else without matching #if + BOOST_WAVE_THROW(preprocess_exception, missing_matching_if, "#else", + act_pos); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_endif(): handle #endif directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_endif() +{ + if (!ctx.exit_if_block()) { + // #endif without matching #if + BOOST_WAVE_THROW(preprocess_exception, missing_matching_if, "#endif", + act_pos); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_if(): handle #if directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_if( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end) +{ +// preprocess the given sequence into the provided list +get_token_value get_value; +token_sequence_type expanded; +token_sequence_type toexpand; + + std::copy(make_ref_transform_iterator(begin, get_value), + make_ref_transform_iterator(end, get_value), + std::inserter(toexpand, toexpand.end())); + + typename token_sequence_type::iterator begin2 = toexpand.begin(); + ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded); + +// replace all remaining (== undefined) identifiers with a integer lliteral '0' + typename token_sequence_type::iterator exp_end = expanded.end(); + for (typename token_sequence_type::iterator exp_it = expanded.begin(); + exp_it != exp_end; ++exp_it) + { + using namespace boost::wave; + + token_id id = token_id(*exp_it); + if (IS_CATEGORY(id, IdentifierTokenType) || + IS_CATEGORY(id, KeywordTokenType)) + { + (*exp_it).set_token_id(T_INTLIT); + (*exp_it).set_value("0"); + } + } + +#if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0 + { + string_type outstr(boost::wave::util::impl::as_string(toexpand)); + outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")"; + WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#if " << outstr << std::endl; + } +#endif + +// parse the expression and enter the #if block + typedef typename ContextT::token_type token_type; + ctx.enter_if_block(grammars::expression_grammar_gen:: + evaluate(expanded.begin(), expanded.end(), act_pos, + ctx.get_if_block_status())); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_elif(): handle #elif directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_elif( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end) +{ + if (ctx.get_if_block_status()) { + if (!ctx.enter_elif_block(false)) { + // #else without matching #if + BOOST_WAVE_THROW(preprocess_exception, missing_matching_if, "#elif", + act_pos); + } + return; // #if/previous #elif was true, so don't enter this #elif + } + +// preprocess the given sequence into the provided list +get_token_value get_value; +token_sequence_type expanded; +token_sequence_type toexpand; + + std::copy(make_ref_transform_iterator(begin, get_value), + make_ref_transform_iterator(end, get_value), + std::inserter(toexpand, toexpand.end())); + + typename token_sequence_type::iterator begin2 = toexpand.begin(); + ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded); + +// replace all remaining (== undefined) identifiers with a integer lliteral '0' + typename token_sequence_type::iterator exp_end = expanded.end(); + for (typename token_sequence_type::iterator exp_it = expanded.begin(); + exp_it != exp_end; ++exp_it) + { + using namespace boost::wave; + + token_id id = token_id(*exp_it); + if (IS_CATEGORY(id, IdentifierTokenType) || + IS_CATEGORY(id, KeywordTokenType)) + { + (*exp_it).set_token_id(T_INTLIT); + (*exp_it).set_value("0"); + } + } + +#if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0 + { + string_type outstr(boost::wave::util::impl::as_string(toexpand)); + outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")"; + BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#elif " << outstr << std::endl; + } +#endif + +// parse the expression and enter the #elif block + typedef typename ContextT::token_type token_type; + ctx.enter_elif_block(grammars::expression_grammar_gen:: + evaluate(expanded.begin(), expanded.end(), act_pos, + ctx.get_if_block_status())); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_illformed(): handles the illegal directive +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_illformed( + typename result_type::string_type const &s) +{ + BOOST_ASSERT(ctx.get_if_block_status()); + BOOST_WAVE_THROW(preprocess_exception, ill_formed_directive, s, act_pos); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_line(): handle #line directives +// +/////////////////////////////////////////////////////////////////////////////// + +namespace { + + template + bool retrieve_line_info (IteratorT first, IteratorT const &last, + int &line, StringT &file) + { + using namespace boost::wave; + if (T_INTLIT == token_id(*first)) { + // extract line number + using namespace std; // some system have atoi in namespace std + line = atoi((*first).get_value().c_str()); + + // extract file name (if it is given) + while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType)) + /**/; // skip whitespace + + if (first != last) { + if (T_STRINGLIT != token_id(*first)) + return false; + + StringT const &file_lit = (*first).get_value(); + + if ('L' == file_lit[0]) + return false; // shouldn't be a wide character string + + file = file_lit.substr(1, file_lit.size()-2); + } + return true; + } + return false; + } +} + +template +inline void +pp_iterator_functor::on_line( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end) +{ + BOOST_ASSERT(ctx.get_if_block_status()); + +// Try to extract the line number and file name from the given token list +// directly. If that fails, preprocess the whole token sequence and try again +// to extract this information. +token_sequence_type expanded; +get_token_value get_value; + + typedef typename ref_transform_iterator_generator< + get_token_value, + typename parse_tree_type::const_iterator + >::type const_tree_iterator_t; + +const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value); +const_tree_iterator_t last = make_ref_transform_iterator(end, get_value); + +// try to interpret the #line body as a number followed by an optional +// string literal +int line = 0; +string_type file_name; + + if (!retrieve_line_info(first, last, line, file_name)) { + // preprocess the body of this #line message + token_sequence_type toexpand; + + std::copy(first, make_ref_transform_iterator(end, get_value), + std::inserter(toexpand, toexpand.end())); + + typename token_sequence_type::iterator begin2 = toexpand.begin(); + ctx.expand_whole_tokensequence(begin2, toexpand.end(), + expanded, false); + + if (!retrieve_line_info(expanded.begin(), expanded.end(), line, + file_name)) + { + BOOST_WAVE_THROW(preprocess_exception, bad_line_statement, + boost::wave::util::impl::as_string(expanded), act_pos) + } + } + +// the queues should be empty at this point + BOOST_ASSERT(unput_queue.empty()); + BOOST_ASSERT(pending_queue.empty()); + + if (!file_name.empty()) // reuse current file name + act_pos.set_file(file_name.c_str()); + act_pos.set_line(line-1); + last_line = act_token.get_position().get_line(); + + must_emit_line_directive = true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// on_error(): handle #error directives +// +/////////////////////////////////////////////////////////////////////////////// +namespace { + + // trim all whitespace from the begin and the end of the given string + template + inline StringT + trim_whitespace(StringT const &s) + { + typedef typename StringT::size_type size_type; + + size_type first = s.find_first_not_of(" \t\v\f"); + if (StringT::npos == first) + return StringT(); + size_type last = s.find_last_not_of(" \t\v\f"); + return s.substr(first, last-first+1); + } +} + +template +inline void +pp_iterator_functor::on_error( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end) +{ + BOOST_ASSERT(ctx.get_if_block_status()); + +// preprocess the given sequence into the provided list +token_sequence_type expanded; +get_token_value get_value; + +typename ref_transform_iterator_generator< + get_token_value, + typename parse_tree_type::const_iterator + >::type first = make_ref_transform_iterator(begin, get_value); + +#if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0 +// preprocess the body of this #error message +token_sequence_type toexpand; + + std::copy(first, make_ref_transform_iterator(end, get_value), + std::inserter(toexpand, toexpand.end())); + + typename token_sequence_type::iterator begin2 = toexpand.begin(); + ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded, + false); +#else +// simply copy the body of this #error message to the issued diagnostic +// message + std::copy(first, make_ref_transform_iterator(end, get_value), + std::inserter(expanded, expanded.end())); +#endif + +// report the corresponding error + BOOST_WAVE_THROW(preprocess_exception, error_directive, + boost::wave::util::impl::as_string(expanded), act_pos); +} + +#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 +/////////////////////////////////////////////////////////////////////////////// +// +// on_warning(): handle #warning directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +pp_iterator_functor::on_warning( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end) +{ + BOOST_ASSERT(ctx.get_if_block_status()); + +// preprocess the given sequence into the provided list +token_sequence_type expanded; +get_token_value get_value; + +typename ref_transform_iterator_generator< + get_token_value, + typename parse_tree_type::const_iterator + >::type first = make_ref_transform_iterator(begin, get_value); + +#if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0 +// preprocess the body of this #warning message +token_sequence_type toexpand; + + std::copy(first, make_ref_transform_iterator(end, get_value), + std::inserter(toexpand, toexpand.end())); + + typename token_sequence_type::iterator begin2 = toexpand.begin(); + ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded, + false); +#else +// simply copy the body of this #warning message to the issued diagnostic +// message + std::copy(first, make_ref_transform_iterator(end, get_value), + std::inserter(expanded, expanded.end())); +#endif + +// report the corresponding error + BOOST_WAVE_THROW(preprocess_exception, warning_directive, + boost::wave::util::impl::as_string(expanded), act_pos); +} +#endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 + +/////////////////////////////////////////////////////////////////////////////// +// +// on_pragma(): handle #pragma directives +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +pp_iterator_functor::on_pragma( + typename parse_tree_type::const_iterator const &begin, + typename parse_tree_type::const_iterator const &end) +{ + using namespace boost::wave; + + BOOST_ASSERT(ctx.get_if_block_status()); + +// Look at the pragma token sequence and decide, if the first token is STDC +// (see C99 standard [6.10.6.2]), if it is, the sequence must _not_ be +// preprocessed. +token_sequence_type expanded; +get_token_value get_value; + + typedef typename ref_transform_iterator_generator< + get_token_value, + typename parse_tree_type::const_iterator + >::type const_tree_iterator_t; + +const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value); +const_tree_iterator_t last = make_ref_transform_iterator(end, get_value); + + expanded.push_back(result_type(T_PP_PRAGMA, "#pragma", act_token.get_position())); + expanded.push_back(result_type(T_SPACE, " ", act_token.get_position())); + + while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType)) + expanded.push_back(*first); // skip whitespace + + if (first != last) { + if (T_IDENTIFIER == token_id(*first) && + boost::wave::need_c99(ctx.get_language()) && + (*first).get_value() == "STDC") + { + // do _not_ preprocess the token sequence + std::copy(first, last, std::inserter(expanded, expanded.end())); + } + else { +#if BOOST_WAVE_PREPROCESS_PRAGMA_BODY != 0 + // preprocess the given tokensequence + token_sequence_type toexpand; + + std::copy(first, last, std::inserter(toexpand, toexpand.end())); + + typename token_sequence_type::iterator begin2 = toexpand.begin(); + ctx.expand_whole_tokensequence(begin2, toexpand.end(), + expanded, false); +#else + // do _not_ preprocess the token sequence + std::copy(first, last, std::inserter(expanded, expanded.end())); +#endif + } + } + expanded.push_back(result_type(T_NEWLINE, "\n", act_token.get_position())); + +// the queues should be empty at this point + BOOST_ASSERT(unput_queue.empty()); + BOOST_ASSERT(pending_queue.empty()); + +// try to interpret the expanded #pragma body + token_sequence_type pending; + if (interpret_pragma(expanded, pending)) { + // if there is some replacement text, insert it into the pending queue + if (pending.size() > 0) + pending_queue.splice(pending_queue.begin(), pending); + return true; // this #pragma was successfully recognized + } + +#if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0 +// Move the resulting token sequence into the pending_queue, so it will be +// returned to the caller. + pending_queue.splice(pending_queue.begin(), expanded); + return false; // return the whole #pragma directive +#else + return true; // skip the #pragma at all +#endif +} + +template +inline bool +pp_iterator_functor::interpret_pragma( + token_sequence_type const &pragma_body, token_sequence_type &result) +{ + using namespace cpplexer; + + typename token_sequence_type::const_iterator end = pragma_body.end(); + typename token_sequence_type::const_iterator it = pragma_body.begin(); + for (++it; it != end && IS_CATEGORY(*it, WhiteSpaceTokenType); ++it) + /**/; // skip whitespace + + if (it == end) // eof reached + return false; + + return boost::wave::util::interpret_pragma(ctx, act_token, it, end, result); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// +// pp_iterator +// +// The boost::wave::pp_iterator template is the iterator, through which +// the resulting preprocessed input stream is accessible. +// +/////////////////////////////////////////////////////////////////////////////// + +template +class pp_iterator +: public boost::spirit::multi_pass< + boost::wave::impl::pp_iterator_functor, + boost::wave::util::functor_input + > +{ +public: + typedef boost::wave::impl::pp_iterator_functor input_policy_type; + +private: + typedef + boost::spirit::multi_pass + base_t; + typedef pp_iterator self_type; + typedef boost::wave::util::functor_input functor_input_t; + +public: + pp_iterator() + {} + + template + pp_iterator(ContextT &ctx, IteratorT const &first, IteratorT const &last, + typename ContextT::position_type const &pos, + boost::wave::language_support language) + : base_t(input_policy_type(ctx, first, last, pos, language)) + {} + + void force_include(char const *path_, bool is_last) + { + this->get_functor().on_include_helper(path_, false, false); + if (is_last) { + this->functor_input_t:: + template inner::advance_input(); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED) diff --git a/include/boost/wave/util/cpp_macromap.hpp b/include/boost/wave/util/cpp_macromap.hpp new file mode 100644 index 000000000..ac6431f46 --- /dev/null +++ b/include/boost/wave/util/cpp_macromap.hpp @@ -0,0 +1,1643 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Macro expansion engine + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED) +#define CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// +// macromap +// +// This class holds all currently defined macros and on demand expands +// those macrodefinitions +// +/////////////////////////////////////////////////////////////////////////////// +template +class macromap { + + typedef macromap self_type; + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + typedef typename token_type::position_type position_type; + + typedef typename ContextT::token_sequence_type definition_container_type; + typedef std::vector parameter_container_type; + + typedef macro_definition + macro_definition_type; + typedef symbol_table + defined_macros_type; + typedef typename defined_macros_type::value_type::second_type + macro_ref_type; + +public: + macromap(ContextT &ctx_) + : current_macros(0), defined_macros(new defined_macros_type(1)), + main_pos("", 0), ctx(ctx_), macro_uid(1) + { + current_macros = defined_macros.get(); + } + ~macromap() {} + +// Add a new macro to the given macro scope + bool add_macro(token_type const &name, bool has_parameters, + parameter_container_type ¶meters, + definition_container_type &definition, bool is_predefined = false, + defined_macros_type *scope = 0); + +// Tests, whether the given macro name is defined in the given macro scope + bool is_defined(string_type const &name, + typename defined_macros_type::iterator &it, + defined_macros_type *scope = 0) const; + template + bool is_defined(IteratorT const &begin, IteratorT const &end); + +// Remove a macro name from the given macro scope + bool remove_macro(string_type const &name, bool even_predefined = false); + + template + token_type const &expand_tokensequence(IteratorT &first, + IteratorT const &last, ContainerT &pending, ContainerT &expanded, + bool expand_operator_defined); + +// Expand all macros inside the given token sequence + template + void expand_whole_tokensequence(ContainerT &expanded, + IteratorT &first, IteratorT const &last, + bool expand_operator_defined); + +// Init the predefined macros (add them to the given scope) + void init_predefined_macros(char const *fname = "", + defined_macros_type *scope = 0, bool at_global_scope = true); + void predefine_macro(defined_macros_type *scope, string_type const &name, + token_type const &t); + +// Init the internal macro symbol namespace + void reset_macromap(); + + position_type &get_main_pos() { return main_pos; } + +protected: +// Helper functions for expanding all macros in token sequences + template + token_type const &expand_tokensequence_worker(ContainerT &pending, + unput_queue_iterator &first, + unput_queue_iterator const &last, + bool expand_operator_defined); + +// Collect all arguments supplied to a macro invocation + template + typename std::vector::size_type collect_arguments ( + token_type const curr_token, std::vector &arguments, + IteratorT &next, IteratorT const &end, SizeT const ¶meter_count); + +// Expand a single macro name + template + bool expand_macro(ContainerT &pending, token_type const &name, + typename defined_macros_type::iterator it, + IteratorT &first, IteratorT const &last, bool expand_operator_defined, + defined_macros_type *scope = 0, ContainerT *queue_symbol = 0); + +// Expand a predefined macro (__LINE__, __FILE__ and __INCLUDE_LEVEL__) + template + bool expand_predefined_macro(token_type const &curr_token, + ContainerT &expanded); + +// Expand a single macro argument + template + void expand_argument (typename std::vector::size_type arg, + std::vector &arguments, + std::vector &expanded_args, bool expand_operator_defined, + std::vector &has_expanded_args); + +// Expand the replacement list (replaces parameters with arguments) + template + void expand_replacement_list( + macro_definition_type const ¯odefinition, + std::vector &arguments, + bool expand_operator_defined, ContainerT &expanded); + +// Rescans the replacement list for macro expansion + template + void rescan_replacement_list(token_type const &curr_token, + macro_definition_type ¯odef, ContainerT &replacement_list, + ContainerT &expanded, bool expand_operator_defined, + IteratorT &nfirst, IteratorT const &nlast); + +// Resolves the operator defined() and replces the token with "0" or "1" + template + token_type const &resolve_defined(IteratorT &first, IteratorT const &last, + ContainerT &expanded); + +// Resolve operator _Pragma or the #pragma directive + template + bool resolve_operator_pragma(IteratorT &first, + IteratorT const &last, ContainerT &expanded); + +// Handle the concatenation operator '##' + template + void concat_tokensequence(ContainerT &expanded); + + template + bool is_valid_concat(string_type new_value, + position_type const &pos, ContainerT &rescanned); + +private: + defined_macros_type *current_macros; // current symbol table + boost::shared_ptr defined_macros; // global symbol table + + token_type act_token; // current token + position_type main_pos; // last token position in the pp_iterator + ContextT &ctx; // context object associated with the macromap + long macro_uid; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// +// add_macro(): adds a new macro to the macromap +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +macromap::add_macro(token_type const &name, bool has_parameters, + parameter_container_type ¶meters, definition_container_type &definition, + bool is_predefined, defined_macros_type *scope) +{ + if (!is_predefined && impl::is_special_macroname (name.get_value())) { + // exclude special macro names + BOOST_WAVE_THROW(preprocess_exception, illegal_redefinition, + name.get_value(), main_pos); + } + +// try to define the new macro +defined_macros_type *current_scope = scope ? scope : current_macros; +typename defined_macros_type::iterator it = current_scope->find(name.get_value()); + + if (it != current_scope->end()) { + // redefinition, should not be different + if ((*it).second->is_functionlike != has_parameters || + !impl::parameters_equal((*it).second->macroparameters, parameters) || + !impl::definition_equals((*it).second->macrodefinition, definition)) + { + BOOST_WAVE_THROW(preprocess_exception, macro_redefinition, + name.get_value(), main_pos); + } + return false; + } + +// test the validity of the parameter names + if (has_parameters) { + std::set names; + + typedef typename parameter_container_type::iterator + parameter_iterator_type; + typedef typename std::set::iterator + name_iterator_type; + + parameter_iterator_type end = parameters.end(); + for (parameter_iterator_type itp = parameters.begin(); itp != end; ++itp) + { + name_iterator_type pit = names.find((*itp).get_value()); + + if (pit != names.end()) { + // duplicate parameter name + BOOST_WAVE_THROW(preprocess_exception, duplicate_parameter_name, + (*pit), main_pos); + } + names.insert((*itp).get_value()); + } + } + +// insert a new macro node + std::pair p = + current_scope->insert( + typename defined_macros_type::value_type( + name.get_value(), + macro_ref_type(new macro_definition_type(name, + has_parameters, is_predefined, ++macro_uid) + ) + ) + ); + + if (!p.second) { + BOOST_WAVE_THROW(preprocess_exception, macro_insertion_error, + name.get_value(), main_pos); + } + +// add the parameters and the definition + std::swap((*p.first).second->macroparameters, parameters); + std::swap((*p.first).second->macrodefinition, definition); + +// call the context supplied preprocessing hook + ctx.defined_macro(name, has_parameters, parameters, definition, + is_predefined); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// is_defined(): returns, whether a given macro is already defined +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +macromap::is_defined(typename token_type::string_type const &name, + typename defined_macros_type::iterator &it, + defined_macros_type *scope) const +{ + if (0 == scope) scope = current_macros; + + if ((it = scope->find(name)) != scope->end()) + return true; // found in symbol table + +// quick pre-check + if (name.size() < 8 || '_' != name[0] || '_' != name[1]) + return false; // quick check failed + + return name == "__LINE__" || name == "__FILE__" || + name == "__INCLUDE_LEVEL__"; +} + +template +template +inline bool +macromap::is_defined(IteratorT const &begin, + IteratorT const &end) +{ + { + // in normal mode the name under inspection should consist of an identifier + // only + if (T_IDENTIFIER != token_id(*begin) && + !IS_CATEGORY(*begin, KeywordTokenType)) + { + BOOST_WAVE_THROW(preprocess_exception, invalid_macroname, + impl::get_full_name(begin, end), main_pos); + } + + IteratorT it = begin; + string_type name ((*it).get_value()); + typename defined_macros_type::iterator cit( + current_macros -> find(name)); + + if (++it != end) { + // there should be only one token as the inspected name + BOOST_WAVE_THROW(preprocess_exception, invalid_macroname, + impl::get_full_name(begin, end), main_pos); + } + return cit != current_macros -> end(); + } + return false; // not defined +} + +/////////////////////////////////////////////////////////////////////////////// +// +// remove_macro(): remove a macro from the macromap +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +macromap::remove_macro(string_type const &name, + bool even_predefined) +{ + typename defined_macros_type::iterator it = current_macros->find(name); + + if (it != current_macros->end()) { + if ((*it).second->is_predefined) { + if (!even_predefined || impl::is_special_macroname(name)) { + BOOST_WAVE_THROW(preprocess_exception, bad_undefine_statement, + name, main_pos); + } + } + current_macros->erase(it); + + // call the context supplied preprocessing hook function + ctx.undefined_macro(name); + return true; + } + else if (impl::is_special_macroname(name)) { + BOOST_WAVE_THROW(preprocess_exception, bad_undefine_statement, + name, main_pos); + } + return false; // macro was not defined +} + +/////////////////////////////////////////////////////////////////////////////// +// +// expand_tokensequence +// +// This function is a helper function which wraps the given iterator +// range into corresponding unput_iterator's and calls the main workhorse +// of the macro expansion engine (the function expand_tokensequence_worker) +// +// This is the top level macro expansion function called from the +// preprocessing iterator component only. +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline typename ContextT::token_type const & +macromap::expand_tokensequence(IteratorT &first, + IteratorT const &last, ContainerT &pending, ContainerT &expanded, + bool expand_operator_defined) +{ + typedef impl::gen_unput_queue_iterator + gen_type; + typedef typename gen_type::return_type iterator_type; + + iterator_type first_it = gen_type::generate(expanded, first); + iterator_type last_it = gen_type::generate(last); + +on_exit::assign on_exit(first, first_it); + + return expand_tokensequence_worker(pending, first_it, last_it, + expand_operator_defined); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// expand_tokensequence_worker +// +// This function is the main workhorse of the macro expansion engine. It +// expands as much tokens as needed to identify the next preprocessed +// token to return to the caller. +// It returns the next preprocessed token. +// +// The iterator 'first' is adjusted accordingly. +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline typename ContextT::token_type const & +macromap::expand_tokensequence_worker( + ContainerT &pending, + unput_queue_iterator &first, + unput_queue_iterator const &last, + bool expand_operator_defined) +{ +// if there exist pending tokens (tokens, which are already preprocessed), then +// return the next one from there + if (!pending.empty()) { + on_exit::pop_front pop_front_token(pending); + + return act_token = pending.front(); + } + +// analyze the next element of the given sequence, if it is an +// T_IDENTIFIER token, try to replace this as a macro etc. + using namespace boost::wave; + typedef unput_queue_iterator iterator_type; + + if (first != last) { + token_id id = token_id(*first); + + // ignore placeholder tokens + if (T_PLACEHOLDER == id) { + token_type placeholder = *first; + + ++first; + if (first == last) + return act_token = placeholder; + id = token_id(*first); + } + + if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType)) { + // try to replace this identifier as a macro + if (expand_operator_defined && (*first).get_value() == "defined") { + // resolve operator defined() + return resolve_defined(first, last, pending); + } + else if (boost::wave::need_variadics(ctx.get_language()) && + (*first).get_value() == "_Pragma") + { + // in C99 mode only: resolve the operator _Pragma + token_type curr_token = *first; + + if (!resolve_operator_pragma(first, last, pending) || + pending.size() > 0) + { + // unknown to us pragma or supplied replacement, return the + // next token + on_exit::pop_front pop_token(pending); + + return act_token = pending.front(); + } + + // the operator _Pragma() was eaten completely, continue + return act_token = token_type(T_PLACEHOLDER, "_", + curr_token.get_position()); + } + + token_type name_token (*first); + typename defined_macros_type::iterator it; + + if (is_defined(name_token.get_value(), it)) { + // the current token contains an identifier, which is currently + // defined as a macro + if (expand_macro(pending, name_token, it, first, last, + expand_operator_defined)) + { + // the tokens returned by expand_macro should be rescanned + // beginning at the last token of the returned replacement list + if (first != last) { + // splice the last token back into the input queue + typename ContainerT::reverse_iterator rit = pending.rbegin(); + + first.get_unput_queue().splice( + first.get_unput_queue().begin(), pending, + (++rit).base(), pending.end()); + } + + // fall through ... + } + else if (!pending.empty()) { + // return the first token from the pending queue + on_exit::pop_front pop_queue (pending); + + return act_token = pending.front(); + } + else { + // macro expansion reached the eoi + return act_token = token_type(); + } + + // return the next preprocessed token + return expand_tokensequence_worker(pending, first, last, + expand_operator_defined); + } +// else if (expand_operator_defined) { +// // in preprocessing conditionals undefined identifiers and keywords +// // are to be replaced with '0' (see. C++ standard 16.1.4, [cpp.cond]) +// return act_token = +// token_type(T_INTLIT, "0", (*first++).get_position()); +// } + else { + act_token = name_token; + ++first; + return act_token; + } + } + else if (expand_operator_defined && IS_CATEGORY(*first, BoolLiteralTokenType)) { + // expanding a constant expression inside #if/#elif, special handling + // of 'true' and 'false' + + // all remaining identifiers and keywords, except for true and false, + // are replaced with the pp-number 0 (C++ standard 16.1.4, [cpp.cond]) + return act_token = token_type(T_INTLIT, T_TRUE != id ? "0" : "1", + (*first++).get_position()); + } + else { + act_token = *first; + ++first; + return act_token; + } + } + return act_token = token_type(); // eoi +} + +/////////////////////////////////////////////////////////////////////////////// +// +// collect_arguments(): collect the actual arguments of a macro invocation +// +// return the number of successfully detected non-empty arguments +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline typename std::vector::size_type +macromap::collect_arguments (token_type const curr_token, + std::vector &arguments, IteratorT &next, IteratorT const &end, + SizeT const ¶meter_count) +{ + using namespace boost::wave; + + arguments.push_back(ContainerT()); + +// collect the actual arguments +typename std::vector::size_type count_arguments = 0; +int nested_parenthesis_level = 1; +ContainerT *argument = &arguments[0]; +bool was_whitespace = false; +token_type startof_argument_list = *next; + + while (++next != end && nested_parenthesis_level) { + token_id id = token_id(*next); + + if (0 == parameter_count && + !IS_CATEGORY((*next), WhiteSpaceTokenType) && id != T_NEWLINE && + id != T_RIGHTPAREN && id != T_LEFTPAREN) + { + // there shouldn't be any arguments + BOOST_WAVE_THROW(preprocess_exception, too_many_macroarguments, + curr_token.get_value(), main_pos); + } + + switch (id) { + case T_LEFTPAREN: + ++nested_parenthesis_level; + argument->push_back(*next); + was_whitespace = false; + break; + + case T_RIGHTPAREN: + { + if (--nested_parenthesis_level >= 1) + argument->push_back(*next); + else { + // found closing parenthesis +// trim_argument(argument); + if (parameter_count > 0) { + if (argument->empty() || + impl::is_whitespace_only(*argument)) + { +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (boost::wave::need_variadics(ctx.get_language())) { + // store a placemarker as the argument + argument->push_back(token_type(T_PLACEMARKER, "§", + (*next).get_position())); + ++count_arguments; + } +#endif + } + else { + ++count_arguments; + } + } + } + was_whitespace = false; + } + break; + + case T_COMMA: + if (1 == nested_parenthesis_level) { + // next parameter +// trim_argument(argument); + if (argument->empty() || + impl::is_whitespace_only(*argument)) + { +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (boost::wave::need_variadics(ctx.get_language())) { + // store a placemarker as the argument + argument->push_back(token_type(T_PLACEMARKER, "§", + (*next).get_position())); + ++count_arguments; + } +#endif + } + else { + ++count_arguments; + } + arguments.push_back(ContainerT()); // add new arg + argument = &arguments[arguments.size()-1]; + } + else { + // surrounded by parenthesises, so store to current argument + argument->push_back(*next); + } + was_whitespace = false; + break; + + case T_SPACE: + case T_SPACE2: + case T_CCOMMENT: + case T_NEWLINE: + if (!was_whitespace) + argument->push_back(token_type(T_SPACE, " ", (*next).get_position())); + was_whitespace = true; + break; // skip whitespace + + case T_PLACEHOLDER: + break; // ignore placeholder + + default: + argument->push_back(*next); + was_whitespace = false; + break; + } + } + + if (nested_parenthesis_level >= 1) { + // missing ')': improperly terminated macro invocation + BOOST_WAVE_THROW(preprocess_exception, improperly_terminated_macro, + "missing ')'", main_pos); + } + +// if there isn't expected any argument and there really wasn't found any, +// than remove the empty element + if (0 == parameter_count && 0 == count_arguments) { + BOOST_ASSERT(1 == arguments.size()); + arguments.clear(); + } + return count_arguments; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// expand_whole_tokensequence +// +// fully expands a given token sequence +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline void +macromap::expand_whole_tokensequence(ContainerT &expanded, + IteratorT &first, IteratorT const &last, + bool expand_operator_defined) +{ + typedef impl::gen_unput_queue_iterator + gen_type; + typedef typename gen_type::return_type iterator_type; + +iterator_type first_it = gen_type::generate(first); +iterator_type last_it = gen_type::generate(last); + +on_exit::assign on_exit(first, first_it); +bool was_whitespace = false; +ContainerT pending_queue; + + while (!pending_queue.empty() || first_it != last_it) { + token_type t = expand_tokensequence_worker(pending_queue, first_it, + last_it, expand_operator_defined); + bool is_whitespace = IS_CATEGORY(t, WhiteSpaceTokenType) && + T_PLACEHOLDER != token_id(t); + + if (!was_whitespace || !is_whitespace) { + if (is_whitespace && T_SPACE != token_id(t)) { + t.set_token_id(T_SPACE); + t.set_value(" "); + } + expanded.push_back(t); + } + was_whitespace = is_whitespace; + } + +// should have returned all expanded tokens + BOOST_ASSERT(pending_queue.empty()/* && unput_queue.empty()*/); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// expand_argument +// +// fully expands the given argument of a macro call +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline void +macromap::expand_argument ( + typename std::vector::size_type arg, + std::vector &arguments, std::vector &expanded_args, + bool expand_operator_defined, std::vector &has_expanded_args) +{ + if (!has_expanded_args[arg]) { + // expand the argument only once + typedef typename std::vector::value_type::iterator + argument_iterator_type; + + argument_iterator_type begin_it = arguments[arg].begin(); + argument_iterator_type end_it = arguments[arg].end(); + + expand_whole_tokensequence(expanded_args[arg], begin_it, end_it, + expand_operator_defined); + impl::remove_placeholders(expanded_args[arg]); + has_expanded_args[arg] = true; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// expand_replacement_list +// +// fully expands the replacement list of a given macro with the +// actual arguments/expanded arguments +// handles the '#' [cpp.stringize] and the '##' [cpp.concat] operator +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline void +macromap::expand_replacement_list( + macro_definition_type const ¯odef, + std::vector &arguments, bool expand_operator_defined, + ContainerT &expanded) +{ + using namespace boost::wave; + typedef typename macro_definition_type::const_definition_iterator_t + macro_definition_iter_t; + +std::vector expanded_args(arguments.size()); +std::vector has_expanded_args(arguments.size()); +bool seen_concat = false; +bool adjacent_concat = false; +bool adjacent_stringize = false; + + macro_definition_iter_t cend = macrodef.macrodefinition.end(); + for (macro_definition_iter_t cit = macrodef.macrodefinition.begin(); + cit != cend; ++cit) + { + bool use_replaced_arg = true; + token_id base_id = BASE_TOKEN(token_id(*cit)); + + if (T_POUND_POUND == base_id) { + // concatenation operator + adjacent_concat = true; + seen_concat = true; + } + else if (T_POUND == base_id) { + // stringize operator + adjacent_stringize = true; + } + else { + if (adjacent_stringize || adjacent_concat || + T_POUND_POUND == impl::next_token + ::peek(cit, cend)) + { + use_replaced_arg = false; + } + if (adjacent_concat) // spaces after '##' ? + adjacent_concat = IS_CATEGORY(*cit, WhiteSpaceTokenType); + } + + if (IS_CATEGORY((*cit), ParameterTokenType)) { + // copy argument 'i' instead of the parameter token i + typename ContainerT::size_type i; +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + bool is_ellipsis = false; + + if (IS_EXTCATEGORY((*cit), ExtParameterTokenType)) { + BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language())); + i = token_id(*cit) - T_EXTPARAMETERBASE; + is_ellipsis = true; + } + else +#endif + { + i = token_id(*cit) - T_PARAMETERBASE; + } + + BOOST_ASSERT(i < arguments.size()); + if (use_replaced_arg) { + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (is_ellipsis) { + position_type const &pos = (*cit).get_position(); + + BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language())); + + // ensure all variadic arguments to be expanded + for (typename vector::size_type arg = i; + arg < expanded_args.size(); ++arg) + { + expand_argument(arg, arguments, expanded_args, + expand_operator_defined, has_expanded_args); + } + impl::replace_ellipsis(expanded_args, i, expanded, pos); + } + else +#endif + { + // ensure argument i to be expanded + expand_argument(i, arguments, expanded_args, + expand_operator_defined, has_expanded_args); + + // replace argument + ContainerT const &arg = expanded_args[i]; + + std::copy(arg.begin(), arg.end(), + std::inserter(expanded, expanded.end())); + } + } + else if (adjacent_stringize && + !IS_CATEGORY(*cit, WhiteSpaceTokenType)) + { + // stringize the current argument + BOOST_ASSERT(!arguments[i].empty()); + + position_type const &pos = (*arguments[i].begin()).get_position(); + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (is_ellipsis && boost::wave::need_variadics(ctx.get_language())) { + impl::trim_argument_left(arguments[i]); + impl::trim_argument_right(arguments.back()); + expanded.push_back(token_type(T_STRINGLIT, + impl::as_stringlit(arguments, i, pos), pos)); + } + else +#endif + { + impl::trim_argument(arguments[i]); + expanded.push_back(token_type(T_STRINGLIT, + impl::as_stringlit(arguments[i], pos), pos)); + } + adjacent_stringize = false; + } + else { + // simply copy the original argument (adjacent '##' or '#') +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (is_ellipsis) { + position_type const &pos = (*cit).get_position(); + + impl::trim_argument_left(arguments[i]); + impl::trim_argument_right(arguments.back()); + BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language())); + impl::replace_ellipsis(arguments, i, expanded, pos); + } + else +#endif + { + ContainerT &arg = arguments[i]; + + impl::trim_argument(arg); + std::copy(arg.begin(), arg.end(), + std::inserter(expanded, expanded.end())); + } + } + } + else if (!adjacent_stringize || T_POUND != base_id) { + // insert the actual replacement token (if it is not the '#' operator) + expanded.push_back(*cit); + } + } + + if (adjacent_stringize) { + // error, '#' should not be the last token + BOOST_WAVE_THROW(preprocess_exception, ill_formed_operator, + "stringize ('#')", main_pos); + } + +// handle the cpp.concat operator + if (seen_concat) + concat_tokensequence(expanded); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// rescan_replacement_list +// +// As the name implies, this function is used to rescan the replacement list +// after the first macro substitution phase. +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline void +macromap::rescan_replacement_list(token_type const &curr_token, + macro_definition_type ¯o_def, ContainerT &replacement_list, + ContainerT &expanded, bool expand_operator_defined, + IteratorT &nfirst, IteratorT const &nlast) +{ + if (!replacement_list.empty()) { +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + // remove the placemarkers + if (boost::wave::need_variadics(ctx.get_language())) { + typename ContainerT::iterator end = replacement_list.end(); + typename ContainerT::iterator it = replacement_list.begin(); + + while (it != end) { + using namespace boost::wave; + if (T_PLACEMARKER == token_id(*it)) { + typename ContainerT::iterator placemarker = it; + + ++it; + replacement_list.erase(placemarker); + } + else { + ++it; + } + } + } +#endif + + // rescan the replacement list, during this rescan the current macro under + // expansion isn't available as an expandable macro + on_exit::reset on_exit(macro_def.is_available_for_replacement, false); + typename ContainerT::iterator begin_it = replacement_list.begin(); + typename ContainerT::iterator end_it = replacement_list.end(); + + expand_whole_tokensequence(expanded, begin_it, end_it, + expand_operator_defined); + + // trim replacement list, leave placeholder tokens untouched + impl::trim_replacement_list(expanded); + } + + if (expanded.empty()) { + // the resulting replacement list should contain at least a placeholder + // token + expanded.push_back(token_type(T_PLACEHOLDER, "_", curr_token.get_position())); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// expand_macro(): expands a defined macro +// +// This functions tries to expand the macro, to which points the 'first' +// iterator. The functions eats up more tokens, if the macro to expand is +// a function-like macro. +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline bool +macromap::expand_macro(ContainerT &expanded, + token_type const &curr_token, typename defined_macros_type::iterator it, + IteratorT &first, IteratorT const &last, + bool expand_operator_defined, defined_macros_type *scope, + ContainerT *queue_symbol) +{ + using namespace boost::wave; + + if (0 == scope) scope = current_macros; + + BOOST_ASSERT(T_IDENTIFIER == token_id(curr_token) || + IS_CATEGORY(token_id(curr_token), KeywordTokenType)); + + if (it == scope->end()) { + ++first; // advance + + // try to expand a predefined macro (__FILE__, __LINE__ or __INCLUDE_LEVEL__) + if (expand_predefined_macro(curr_token, expanded)) + return false; + + // not defined as a macro + if (0 != queue_symbol) { + expanded.splice(expanded.end(), *queue_symbol); + } + else { + expanded.push_back(curr_token); + } + return false; + } + +// ensure the parameters to be replaced with special parameter tokens +macro_definition_type ¯o_def = *(*it).second.get(); + + macro_def.replace_parameters(); + +// test if this macro is currently available for replacement + if (!macro_def.is_available_for_replacement) { + // this macro is marked as non-replaceable + // copy the macro name itself + if (0 != queue_symbol) { + queue_symbol->push_back(token_type(T_NONREPLACABLE_IDENTIFIER, + curr_token.get_value(), curr_token.get_position())); + expanded.splice(expanded.end(), *queue_symbol); + } + else { + expanded.push_back(token_type(T_NONREPLACABLE_IDENTIFIER, + curr_token.get_value(), curr_token.get_position())); + } + ++first; + return false; + } + +// try to replace the current identifier as a function-like macro +ContainerT replacement_list; + + if (T_LEFTPAREN == impl::next_token::peek(first, last)) { + // called as a function-like macro + impl::skip_to_token(first, last, T_LEFTPAREN); + + if (macro_def.is_functionlike) { + // defined as a function-like macro + + // collect the arguments + std::vector arguments; + typename std::vector::size_type count_args = + collect_arguments (curr_token, arguments, first, last, + macro_def.macroparameters.size()); + + // verify the parameter count + if (count_args < macro_def.macroparameters.size() || + arguments.size() < macro_def.macroparameters.size()) + { + // too few macro arguments + BOOST_WAVE_THROW(preprocess_exception, too_few_macroarguments, + curr_token.get_value(), main_pos); + } + + if (count_args > macro_def.macroparameters.size() || + arguments.size() > macro_def.macroparameters.size()) + { +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (!macro_def.has_ellipsis) +#endif + { + // too many macro arguments + BOOST_WAVE_THROW(preprocess_exception, too_many_macroarguments, + curr_token.get_value(), main_pos); + } + } + + // inject tracing support + ctx.get_trace_policy().expanding_function_like_macro( + macro_def.macroname, macro_def.macroparameters, + macro_def.macrodefinition, curr_token, arguments); + + // expand the replacement list of this macro + expand_replacement_list(macro_def, arguments, expand_operator_defined, + replacement_list); + } + else { + // defined as an object-like macro + ctx.get_trace_policy().expanding_object_like_macro( + macro_def.macroname, macro_def.macrodefinition, curr_token); + + bool found = false; + impl::find_concat_operator concat_tag(found); + + std::remove_copy_if(macro_def.macrodefinition.begin(), + macro_def.macrodefinition.end(), + std::inserter(replacement_list, replacement_list.end()), + concat_tag); + + // handle concatenation operators + if (found) + concat_tokensequence(replacement_list); + } + } + else { + // called as an object like macro + if ((*it).second->is_functionlike) { + // defined as a function-like macro + if (0 != queue_symbol) { + queue_symbol->push_back(curr_token); + expanded.splice(expanded.end(), *queue_symbol); + } + else { + expanded.push_back(curr_token); + } + ++first; // skip macro name + return false; // no further preprocessing required + } + else { + // defined as an object-like macro (expand it) + ctx.get_trace_policy().expanding_object_like_macro( + macro_def.macroname, macro_def.macrodefinition, curr_token); + + bool found = false; + impl::find_concat_operator concat_tag(found); + + std::remove_copy_if(macro_def.macrodefinition.begin(), + macro_def.macrodefinition.end(), + std::inserter(replacement_list, replacement_list.end()), + concat_tag); + + // handle concatenation operators + if (found) + concat_tokensequence(replacement_list); + + ++first; // skip macro name + } + } + +// rescan the replacement list +ContainerT expanded_list; + + ctx.get_trace_policy().expanded_macro(replacement_list); + + rescan_replacement_list(curr_token, macro_def, replacement_list, + expanded_list, expand_operator_defined, first, last); + + ctx.get_trace_policy().rescanned_macro(expanded_list); + expanded.splice(expanded.end(), expanded_list); + return true; // rescan is required +} + +/////////////////////////////////////////////////////////////////////////////// +// +// If the token under inspection points to a certain predefined macro it will +// be expanded, otherwise false is returned. +// (only __FILE__, __LINE__ and __INCLUDE_LEVEL__ macros are expaned here) +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline bool +macromap::expand_predefined_macro(token_type const &curr_token, + ContainerT &expanded) +{ + using namespace boost::wave; + +string_type const &value = curr_token.get_value(); + + if (value.size() < 8 || '_' != value[0] || '_' != value[1]) + return false; // quick check failed + + if (value == "__LINE__") { + // expand the __LINE__ macro + char buffer[22]; // 21 bytes holds all NUL-terminated unsigned 64-bit numbers + + using namespace std; // for some systems sprintf is in namespace std + sprintf(buffer, "%d", main_pos.get_line()); + expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position())); + return true; + } + else if (value == "__FILE__") { + // expand the __FILE__ macro + namespace fs = boost::filesystem; + + std::string file("\""); + fs::path filename(main_pos.get_file().c_str(), fs::native); + + using boost::wave::util::impl::escape_lit; + file += escape_lit(filename.native_file_string()) + "\""; + expanded.push_back(token_type(T_STRINGLIT, file.c_str(), + curr_token.get_position())); + return true; + } + else if (value == "__INCLUDE_LEVEL__") { + // expand the __INCLUDE_LEVEL__ macro + char buffer[22]; // 21 bytes holds all NUL-terminated unsigned 64-bit numbers + + using namespace std; // for some systems sprintf is in namespace std + sprintf(buffer, "%d", ctx.get_iteration_depth()); + expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position())); + return true; + } + return false; // no predefined token +} + +/////////////////////////////////////////////////////////////////////////////// +// +// resolve_defined(): resolve the operator defined() and replace it with the +// correct T_INTLIT token +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline typename ContextT::token_type const & +macromap::resolve_defined(IteratorT &first, + IteratorT const &last, ContainerT &pending) +{ + using namespace boost::wave; + using namespace boost::wave::grammars; + +ContainerT result; +IteratorT start = first; +boost::spirit::parse_info hit = + defined_grammar_gen:: + parse_operator_defined(start, last, result); + + if (!hit.hit) { + BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, + "defined()", main_pos); + } + impl::assign_iterator::do_(first, hit.stop); + +// insert a token, which reflects the outcome + pending.push_back(token_type(T_INTLIT, + is_defined(result.begin(), result.end()) ? "1" : "0", + main_pos)); + +on_exit::pop_front pop_front_token(pending); + + return act_token = pending.front(); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// resolve_operator_pragma(): resolve the operator _Pragma() and dispatch to +// the associated action +// +// This function returns true, if the pragma was correctly interpreted. +// The iterator 'first' is positioned behind the closing ')'. +// This function returnes false, if the _Pragma was not known, the +// preprocessed token sequence is pushed back to the 'pending' sequence. +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline bool +macromap::resolve_operator_pragma(IteratorT &first, + IteratorT const &last, ContainerT &pending) +{ +// isolate the parameter of the operator _Pragma + token_type pragma_token = *first; + + if (!impl::skip_to_token(first, last, T_LEFTPAREN)) { + // misformed operator _Pragma + BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, + "operator _Pragma()", pragma_token.get_position()); + } + + std::vector arguments; + typename std::vector::size_type count_args = + collect_arguments (pragma_token, arguments, first, last, 1); + +// verify the parameter count + if (pragma_token.get_position().get_file().empty()) + pragma_token.set_position(act_token.get_position()); + + if (1 > count_args || 1 > arguments.size()) { + // too few macro arguments + BOOST_WAVE_THROW(preprocess_exception, too_few_macroarguments, + pragma_token.get_value(), pragma_token.get_position()); + } + if (1 < count_args || 1 < arguments.size()) { + // too many macro arguments + BOOST_WAVE_THROW(preprocess_exception, too_many_macroarguments, + pragma_token.get_value(), pragma_token.get_position()); + } + +// preprocess the pragma token body + typedef typename std::vector::value_type::iterator + argument_iterator_type; + + ContainerT expanded; + argument_iterator_type begin_it = arguments[0].begin(); + argument_iterator_type end_it = arguments[0].end(); + expand_whole_tokensequence(expanded, begin_it, end_it, false); + +// unescape the parameter of the operator _Pragma + typedef typename token_type::string_type string_type; + + string_type pragma_cmd; + typename ContainerT::const_iterator end_exp = expanded.end(); + for (typename ContainerT::const_iterator it_exp = expanded.begin(); + it_exp != end_exp; ++it_exp) + { + if (T_EOF == token_id(*it_exp)) + break; + if (IS_CATEGORY(*it_exp, WhiteSpaceTokenType)) + continue; + + if (T_STRINGLIT != token_id(*it_exp)) { + // ill formed operator _Pragma + BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, + "_Pragma", pragma_token.get_position()); + } + + if (pragma_cmd.size() > 0) { + // there should be exactly one string literal (string literals are to + // be concatenated at translation phase 6, but _Pragma operators are + // to be executed at translation phase 4) + BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, + "_Pragma", pragma_token.get_position()); + } + + // remove the '\"' and concat all given string literal-values + string_type token_str = (*it_exp).get_value(); + pragma_cmd += token_str.substr(1, token_str.size() - 2); + } + string_type pragma_cmd_unesc = impl::unescape_lit(pragma_cmd); + +// tokenize the pragma body + typedef typename ContextT::lexer_type lexer_type; + + ContainerT pragma; + std::string pragma_cmd_str(pragma_cmd_unesc.c_str()); + lexer_type it = lexer_type(pragma_cmd_str.begin(), pragma_cmd_str.end(), + pragma_token.get_position(), ctx.get_language()); + lexer_type end = lexer_type(); + for (/**/; it != end; ++it) + pragma.push_back(*it); + +// analyze the preprocessed tokensequence and eventually dispatch to the +// associated action + if (interpret_pragma(ctx, pragma_token, pragma.begin(), pragma.end(), + pending)) + { + return true; // successfully recognized a wave specific pragma + } + +// unknown pragma token sequence, push it back and return to the caller + pending.push_front(token_type(T_SPACE, " ", pragma_token.get_position())); + pending.push_front(token_type(T_RIGHTPAREN, ")", pragma_token.get_position())); + pending.push_front(token_type(T_STRINGLIT, string_type("\"") + pragma_cmd + "\"", + pragma_token.get_position())); + pending.push_front(token_type(T_LEFTPAREN, "(", pragma_token.get_position())); + pending.push_front(pragma_token); + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Test, whether the result of a concat operator is well formed or not. +// +// This is done by re-scanning (re-tokenising) the resulting token sequence, +// which should give back exactly one token. +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline bool +macromap::is_valid_concat(string_type new_value, + position_type const &pos, ContainerT &rescanned) +{ +// retokenise the newly generated string + typedef typename ContextT::lexer_type lexer_type; + + std::string value_to_test(new_value.c_str()); + lexer_type it = lexer_type(value_to_test.begin(), value_to_test.end(), pos, + ctx.get_language()); + lexer_type end = lexer_type(); + for (/**/; it != end && T_EOF != token_id(*it); ++it) + rescanned.push_back(*it); + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (boost::wave::need_variadics(ctx.get_language())) + return true; // in variadics mode token pasting is well defined +#endif + +// test if the newly generated token sequence contains more than 1 token +// the second one is the T_EOF token +// BOOST_ASSERT(T_EOF == token_id(rescanned.back())); + return 1 == rescanned.size(); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Handle all occurences of the concatenation operator '##' inside the given +// token sequence. +// +/////////////////////////////////////////////////////////////////////////////// +template +template +inline void +macromap::concat_tokensequence(ContainerT &expanded) +{ + using namespace boost::wave; + typedef typename ContainerT::iterator iterator_type; + + iterator_type end = expanded.end(); + iterator_type prev = end; + for (iterator_type it = expanded.begin(); it != end; /**/) + { + if (T_POUND_POUND == BASE_TOKEN(token_id(*it))) { + iterator_type next = it; + + ++next; + if (prev == end || next == end) { + // error, '##' should be in between two tokens + BOOST_WAVE_THROW(preprocess_exception, ill_formed_operator, + "concat ('##')", main_pos); + } + + // replace prev##next with the concatenated value, skip whitespace + // before and after the '##' operator + while (IS_CATEGORY(*next, WhiteSpaceTokenType)) { + ++next; + if (next == end) { + // error, '##' should be in between two tokens + BOOST_WAVE_THROW(preprocess_exception, ill_formed_operator, + "concat ('##')", main_pos); + } + } + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (boost::wave::need_variadics(ctx.get_language())) { + if (T_PLACEMARKER == token_id(*next)) { + // remove the '##' and the next tokens from the sequence + iterator_type first_to_delete = prev; + + expanded.erase(++first_to_delete, ++next); + it = next; + continue; + } + else if (T_PLACEMARKER == token_id(*prev)) { + // remove the '##' and the next tokens from the sequence + iterator_type first_to_delete = prev; + + *prev = *next; + expanded.erase(++first_to_delete, ++next); + it = next; + continue; + } + } +#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + + // test if the concat operator has to concatenate two unrelated + // tokens i.e. the result yields more then one token + string_type concat_result; + ContainerT rescanned; + + concat_result = ((*prev).get_value() + (*next).get_value()); + + // Here we have to work around a conflict between the Standards + // requirement, that the preprocessor has to act upon so called + // pp-tokens and the fact, that Wave acts upon C++ tokens. So we have + // eventually to combine the current token with the next tokens + // if these are of type T_IDENTIFIER or T_INTLIT following without any + // interventing whitespace. + // Please note though, that this hack unfortunately doesn't fix all + // problems related with pp-numbers as specified by the Standard. + iterator_type save = next; + + if (IS_CATEGORY(*prev, IdentifierTokenType) && + T_INTLIT == token_id(*save)) + { + token_id id = impl::next_token::peek(next, end, false); + + if (IS_CATEGORY(id, IdentifierTokenType) || + IS_CATEGORY(id, KeywordTokenType)) + { + concat_result += (*++next).get_value(); + } + } + + // analyze the validity of the concatenation result + if (!is_valid_concat(concat_result, (*prev).get_position(), + rescanned) && + !IS_CATEGORY(*prev, WhiteSpaceTokenType) && + !IS_CATEGORY(*next, WhiteSpaceTokenType)) + { + string_type error_string("\""); + + error_string += (*prev).get_value(); + error_string += "\" and \""; + error_string += (*save).get_value(); + error_string += "\""; + BOOST_WAVE_THROW(preprocess_exception, invalid_concat, + error_string, main_pos); + } + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (boost::wave::need_variadics(ctx.get_language())) { + // remove the prev, '##' and the next tokens from the sequence + expanded.erase(prev, ++next); // remove not needed tokens + + // some stl implementations clear() the container if we erased all + // the elements, which orphans all iterators. we re-initialise these + // here + if (expanded.empty()) + end = next = expanded.end(); + + // replace the old token (pointed to by *prev) with the retokenized + // sequence + expanded.splice(next, rescanned); + + // the last token of the inserted sequence is the new previous + prev = next; + if (next != expanded.end()) + --prev; + } + else +#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + { + // we leave the token_id unchanged, but unmark the token as + // disabled, if appropriate + (*prev).set_value(concat_result); + if (T_NONREPLACABLE_IDENTIFIER == token_id(*prev)) + (*prev).set_token_id(T_IDENTIFIER); + + // remove the '##' and the next tokens from the sequence + iterator_type first_to_delete = prev; + + expanded.erase(++first_to_delete, ++next); + } + it = next; + continue; + } + + // save last non-whitespace token position + if (!IS_CATEGORY(*it, WhiteSpaceTokenType)) + prev = it; + + ++it; // next token, please + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// predefined_macro(): predefine a single macro +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +macromap::predefine_macro(defined_macros_type *scope, + string_type const &name, token_type const &t) +{ +definition_container_type macrodefinition; +std::vector param; + + macrodefinition.push_back(t); + add_macro(token_type(T_IDENTIFIER, name, t.get_position()), + false, param, macrodefinition, true, scope); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// init_predefined_macros(): init the predefined macros +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +macromap::init_predefined_macros(char const *fname, + defined_macros_type *scope, bool at_global_scope) +{ + using namespace predefined_macros; + +// if no scope is given, use the current one +defined_macros_type *current_scope = scope ? scope : current_macros; + +// first, add the static macros +position_type pos; + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (boost::wave::need_c99(ctx.get_language())) { + // define C99 specifics + for (int i = 0; 0 != static_data_c99(i).name; ++i) { + predefine_macro(current_scope, static_data_c99(i).name, + token_type(static_data_c99(i).token_id, + static_data_c99(i).value, pos)); + } + } + else +#endif + { + // define C++ specifics + for (int i = 0; 0 != static_data_cpp(i).name; ++i) { + predefine_macro(current_scope, static_data_cpp(i).name, + token_type(static_data_cpp(i).token_id, + static_data_cpp(i).value, pos)); + } + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + // define __WAVE_HAS_VARIADICS__, if appropriate + if (boost::wave::need_variadics(ctx.get_language())) { + predefine_macro(current_scope, "__WAVE_HAS_VARIADICS__", + token_type(T_INTLIT, "1", pos)); + } +#endif + } + +// predefine the __BASE_FILE__ macro which contains the main file name + predefine_macro(current_scope, "__BASE_FILE__", + token_type(T_STRINGLIT, string_type("\"") + fname + "\"", pos)); + +// now add the dynamic macros + for (int j = 0; 0 != dynamic_data(j).name; ++j) { + predefine_macro(current_scope, dynamic_data(j).name, + token_type(dynamic_data(j).token_id, + dynamic_data(j).generator(false), pos)); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// reset_macro_map(): initialise the internal macro symbol namespace +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +macromap::reset_macromap() +{ + current_macros->clear(); + predefined_macros::get_time(true); + predefined_macros::get_date(true); + act_token = token_type(); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED) diff --git a/include/boost/wave/util/cpp_macromap_predef.hpp b/include/boost/wave/util/cpp_macromap_predef.hpp new file mode 100644 index 000000000..d1b339eda --- /dev/null +++ b/include/boost/wave/util/cpp_macromap_predef.hpp @@ -0,0 +1,252 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the predefined macros + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_MACROMAP_PREDEF_HPP_HK041119) +#define CPP_MACROMAP_PREDEF_HPP_HK041119 + +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// This file contains the definition of functions needed for the management +// of static and dynamic predefined macros, such as __DATE__, __TIME__ etc. +// +// Note: __FILE__, __LINE__ and __INCLUDE_LEVEL__ are handled in the file +// cpp_macromap.hpp. +// +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +namespace predefined_macros { + +// list of static predefined macros + struct static_macros { + char const *name; + boost::wave::token_id token_id; + char const *value; + }; + +// C++ mode + inline static_macros const & + static_data_cpp(std::size_t i) + { + static static_macros data[] = { + { "__STDC__", T_INTLIT, "1" }, + { "__cplusplus", T_INTLIT, "199711L" }, + { 0, T_EOF, 0 } + }; + BOOST_ASSERT(i < sizeof(data)/sizeof(data[0])); + return data[i]; + } + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +// C99 mode + inline static_macros const & + static_data_c99(std::size_t i) + { + static static_macros data[] = { + { "__STDC__", T_INTLIT, "1" }, + { "__STDC_VERSION__", T_INTLIT, "199901L" }, + { "__STDC_HOSTED__", T_INTLIT, "0" }, + { "__WAVE_HAS_VARIADICS__", T_INTLIT, "1" }, + { 0, T_EOF, 0 } + }; + BOOST_ASSERT(i < sizeof(data)/sizeof(data[0])); + return data[i]; + } +#endif + +// list of dynamic predefined macros + typedef char const * (* get_dynamic_value)(bool); + +// __DATE__ + inline + char const *get_date(bool reset) + { + static std::string datestr; + static const char *const monthnames[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + if (reset) { + datestr.erase(); + } + else { + // for some systems sprintf, time_t etc. is in namespace std + using namespace std; + + time_t tt = time(0); + struct tm *tb = 0; + + if (tt != (time_t)-1) { + char buffer[sizeof("\"Oct 11 1347\"")+1]; + + tb = localtime (&tt); + sprintf (buffer, "\"%s %2d %4d\"", + monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900); + datestr = buffer; + } + else { + datestr = "\"??? ?? ????\""; + } + } + return datestr.c_str(); + } + +// __TIME__ + inline + char const *get_time(bool reset) + { + static std::string timestr; + + if (reset) { + timestr.erase(); + } + else { + // for some systems sprintf, time_t etc. is in namespace std + using namespace std; + + time_t tt = time(0); + struct tm *tb = 0; + + if (tt != (time_t)-1) { + char buffer[sizeof("\"12:34:56\"")+1]; + + tb = localtime (&tt); + sprintf (buffer, "\"%02d:%02d:%02d\"", tb->tm_hour, + tb->tm_min, tb->tm_sec); + timestr = buffer; + } + else { + timestr = "\"??:??:??\""; + } + } + return timestr.c_str(); + } + +// __SPIRIT_PP__/__WAVE__ + inline + char const *get_version(bool /*reset*/) + { + static std::string versionstr; + char buffer[sizeof("0x0000")+1]; + + using namespace std; // for some systems sprintf is in namespace std + sprintf(buffer, "0x%02d%1d%1d", BOOST_WAVE_VERSION_MAJOR, + BOOST_WAVE_VERSION_MINOR, BOOST_WAVE_VERSION_SUBMINOR); + versionstr = buffer; + return versionstr.c_str(); + } + +// __SPIRIT_PP_VERSION__/__WAVE_VERSION__ + boost::wave::util::time_conversion_helper const + compilation_time(__DATE__ " " __TIME__); + + inline + char const *get_fullversion(bool /*reset*/) + { + static std::string versionstr; + char buffer[sizeof("0x00000000")+1]; + + // for some systems sprintf, time_t etc. is in namespace std + using namespace std; + + // calculate the number of days since Dec 13 2001 + // (the day the Wave project was started) + tm first_day; + + using namespace std; // for some systems memset is in namespace std + memset (&first_day, 0, sizeof(tm)); + first_day.tm_mon = 11; // Dec + first_day.tm_mday = 13; // 13 + first_day.tm_year = 101; // 2001 + + long seconds = long(difftime(compilation_time.get_time(), + mktime(&first_day))); + + sprintf(buffer, "0x%02d%1d%1d%04ld", BOOST_WAVE_VERSION_MAJOR, + BOOST_WAVE_VERSION_MINOR, BOOST_WAVE_VERSION_SUBMINOR, + seconds/(3600*24)); + versionstr = buffer; + return versionstr.c_str(); + } + +// __SPIRIT_PP_VERSION_STR__/__WAVE_VERSION_STR__ + inline + char const *get_versionstr(bool /*reset*/) + { + static std::string versionstr; + char buffer[sizeof("\"00.00.00.0000\"")+1]; + + // for some systems sprintf, time_t etc. is in namespace std + using namespace std; + + // calculate the number of days since Dec 13 2001 + // (the day the Wave project was started) + tm first_day; + + using namespace std; // for some systems memset is in namespace std + memset (&first_day, 0, sizeof(tm)); + first_day.tm_mon = 11; // Dec + first_day.tm_mday = 13; // 13 + first_day.tm_year = 101; // 2001 + + long seconds = long(difftime(compilation_time.get_time(), + mktime(&first_day))); + + sprintf(buffer, "\"%d.%d.%d.%ld\"", BOOST_WAVE_VERSION_MAJOR, + BOOST_WAVE_VERSION_MINOR, BOOST_WAVE_VERSION_SUBMINOR, + seconds/(3600*24)); + versionstr = buffer; + return versionstr.c_str(); + } + + struct dynamic_macros { + char const *name; + boost::wave::token_id token_id; + get_dynamic_value generator; + }; + + inline dynamic_macros const & + dynamic_data(std::size_t i) + { + static dynamic_macros data[] = { + { "__DATE__", T_STRINGLIT, get_date }, + { "__TIME__", T_STRINGLIT, get_time }, + { "__SPIRIT_PP__", T_INTLIT, get_version }, + { "__SPIRIT_PP_VERSION__", T_INTLIT, get_fullversion }, + { "__SPIRIT_PP_VERSION_STR__", T_STRINGLIT, get_versionstr }, + { "__WAVE__", T_INTLIT, get_version }, + { "__WAVE_VERSION__", T_INTLIT, get_fullversion }, + { "__WAVE_VERSION_STR__", T_STRINGLIT, get_versionstr }, + { 0, T_EOF, 0 } + }; + BOOST_ASSERT(i < sizeof(data)/sizeof(data[0])); + return data[i]; + } + +} // namespace predefined_macros + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_MACROMAP_PREDEF_HPP_HK041119) diff --git a/include/boost/wave/util/cpp_macromap_utils.hpp b/include/boost/wave/util/cpp_macromap_utils.hpp new file mode 100644 index 000000000..5a452afd9 --- /dev/null +++ b/include/boost/wave/util/cpp_macromap_utils.hpp @@ -0,0 +1,497 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Token sequence analysis and transformation helper functions + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_MACROMAP_UTIL_HPP_HK041119) +#define CPP_MACROMAP_UTIL_HPP_HK041119 + +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// This file contains the definition of several token sequence analyse +// and transformation utility functions needed during macro handling. +// +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +namespace on_exit { + + /////////////////////////////////////////////////////////////////////////// + // + // On destruction pop the first element of the list given as the argument + // + /////////////////////////////////////////////////////////////////////////// + template + class pop_front { + public: + pop_front(ContainerT &list_) : list(list_) {} + ~pop_front() { list.pop_front(); } + + private: + ContainerT &list; + }; + + /////////////////////////////////////////////////////////////////////////// + // + // Append a given list to the list given as argument + // On destruction pop the first element of the list given as argument + // + /////////////////////////////////////////////////////////////////////////// + template + class splice_pop_front { + public: + splice_pop_front(ContainerT &list_, ContainerT &queue) + : list(list_) + { + list.splice(list.end(), queue); + } + ~splice_pop_front() { list.pop_front(); } + + private: + ContainerT &list; + }; + + /////////////////////////////////////////////////////////////////////////// + // + // On destruction reset a referenced value to its initial state + // + /////////////////////////////////////////////////////////////////////////// + template + class reset { + public: + reset(TypeT &target_value_, TypeT new_value) + : target_value(target_value_), old_value(target_value_) + { + target_value_ = new_value; + } + ~reset() { target_value = old_value; } + + private: + TypeT &target_value; + TypeT old_value; + }; + + /////////////////////////////////////////////////////////////////////////// + // + // On destruction assign the given iterator back + // + /////////////////////////////////////////////////////////////////////////// + template + class assign { + public: + assign(IteratorT &it_, UnputIteratorT const &uit_) + : it(it_), uit(uit_) {} + ~assign() { it = uit.base(); } + + private: + IteratorT ⁢ + UnputIteratorT const &uit; + }; + + template + class assign { + public: + assign(IteratorT &it_, IteratorT const &uit_) + : it(it_), uit(uit_) {} + ~assign() { it = uit; } + + private: + IteratorT ⁢ + IteratorT const &uit; + }; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace on_exit + +/////////////////////////////////////////////////////////////////////////////// +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// Test, whether a given identifier resolves to a predefined name +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +is_special_macroname (StringT const &name) +{ + if (name.size() < 7) + return false; + + if ("defined" == name) + return true; + + if ('_' == name[0] && '_' == name[1]) { + StringT str = name.substr(2); + + if (str == "cplusplus" || str == "STDC__" || + str == "TIME__" || str == "DATE__" || + str == "LINE__" || str == "FILE__" || + str == "INCLUDE_LEVEL__") + { + return true; + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Test, whether two tokens are to be considered equal (different sequences +// of whitespace are considered to be equal) +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +token_equals(TokenT const &left, TokenT const &right) +{ + using namespace boost::wave; + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (T_PARAMETERBASE == token_id(left) || + T_EXTPARAMETERBASE == token_id(left)) +#else + if (T_PARAMETERBASE == token_id(left)) +#endif + { + // if the existing token is of type T_PARAMETERBASE, then the right token + // must be of type T_IDENTIFIER or a keyword + return (T_IDENTIFIER == token_id(right) || + IS_CATEGORY(right, KeywordTokenType)) && + left.get_value() == right.get_value(); + } + + // if the left token has whitespace, the value is irrelevant + return token_id(left) == token_id(right) && ( + IS_CATEGORY(left, WhiteSpaceTokenType) || + left.get_value() == right.get_value() + ); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Tests, whether two macro definitions are equal +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +definition_equals(ContainerT const &definition, + ContainerT const &new_definition) +{ + typedef typename ContainerT::const_iterator const_iterator_type; + +const_iterator_type first1 = definition.begin(); +const_iterator_type last1 = definition.end(); +const_iterator_type first2 = new_definition.begin(); +const_iterator_type last2 = new_definition.end(); + + while (first1 != last1 && token_equals(*first1, *first2)) { + // skip whitespace, if both sequences have a whitespace next + token_id id1 = next_token::peek(first1, last1, false); + token_id id2 = next_token::peek(first2, last2, false); + + if (IS_CATEGORY(id1, WhiteSpaceTokenType) && + IS_CATEGORY(id2, WhiteSpaceTokenType)) + { + // all consecutive whitespace tokens count as one whitespace + // adjust first1 and first2 accordingly + skip_whitespace(first1, last1); + skip_whitespace(first2, last2); + } + else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) && + !IS_CATEGORY(id2, WhiteSpaceTokenType)) + { + ++first1; + ++first2; + } + else { + // the sequences differ + break; + } + } + return (first1 == last1 && first2 == last2) ? true : false; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Tests, whether two given sets of macro parameters are equal +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +parameters_equal(ContainerT const ¶meters, ContainerT const &new_parameters) +{ + if (parameters.size() != new_parameters.size()) + return false; // different parameter count + + typedef typename ContainerT::const_iterator const_iterator_type; + +const_iterator_type first1 = parameters.begin(); +const_iterator_type last1 = parameters.end(); +const_iterator_type first2 = new_parameters.begin(); + + while (first1 != last1) { + // parameters are different, if the corresponding tokens are different + using namespace boost::wave; + if (token_id(*first1) != token_id(*first2) || + (*first1).get_value() != (*first2).get_value()) + { + break; + } + ++first1; + ++first2; + } + return (first1 == last1) ? true : false; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Strip leading and trailing whitespace from the given token sequence +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +trim_replacement_list (ContainerT &replacement_list) +{ + using namespace boost::wave; + +// strip leading whitespace + if (replacement_list.size() > 0) { + typename ContainerT::iterator end = replacement_list.end(); + typename ContainerT::iterator it = replacement_list.begin(); + + while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) { + if (T_PLACEHOLDER != token_id(*it)) { + typename ContainerT::iterator next = it; + ++next; + replacement_list.erase(it); + it = next; + } + else { + ++it; + } + } + } + +// strip trailing whitespace + if (replacement_list.size() > 0) { + typename ContainerT::reverse_iterator rend = replacement_list.rend(); + typename ContainerT::reverse_iterator rit = replacement_list.rbegin(); + + while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType)) + ++rit; + + typename ContainerT::iterator end = replacement_list.end(); + typename ContainerT::iterator it = rit.base(); + + while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) { + if (T_PLACEHOLDER != token_id(*it)) { + typename ContainerT::iterator next = it; + ++next; + replacement_list.erase(it); + it = next; + } + else { + ++it; + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Remove all placeholder tokens from the given token sequence +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +remove_placeholders (ContainerT &replacement_list) +{ + using namespace boost::wave; + +// strip leading whitespace + if (replacement_list.size() > 0) { + typename ContainerT::iterator end = replacement_list.end(); + typename ContainerT::iterator it = replacement_list.begin(); + + while (it != end) { + if (T_PLACEHOLDER == token_id(*it)) { + typename ContainerT::iterator next = it; + ++next; + replacement_list.erase(it); + it = next; + } + else { + ++it; + } + } + + // remove all 'new' leading and trailing whitespace + trim_replacement_list(replacement_list); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Remove all whitespace tokens on the left side of the given token sequence +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +trim_argument_left (ContainerT &argument) +{ + using namespace boost::wave; + +// strip leading whitespace (should be only one token) + if (argument.size() > 0 && + IS_CATEGORY(argument.front(), WhiteSpaceTokenType)) + { + argument.pop_front(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Remove all whitespace tokens on the right side of the given token sequence +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +trim_argument_right (ContainerT &argument) +{ + using namespace boost::wave; + +// strip trailing whitespace (should be only one token) + if (argument.size() > 0 && + IS_CATEGORY(argument.back(), WhiteSpaceTokenType)) + { + argument.pop_back(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Remove all whitespace tokens on the keft and right sides of the given token +// sequence +// +/////////////////////////////////////////////////////////////////////////////// +template +inline void +trim_argument (ContainerT &argument) +{ + trim_argument_left(argument); + trim_argument_right(argument); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Tests, whether the given token sequence consists out of whitespace only +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +is_whitespace_only (ContainerT const &argument) +{ + using namespace cpplexer; + + typename ContainerT::const_iterator end = argument.end(); + for (typename ContainerT::const_iterator it = argument.begin(); + it != end; ++it) + { + if (!IS_CATEGORY(*it, WhiteSpaceTokenType)) + return false; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Skip forward to a given token +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +skip_to_token(IteratorT &it, IteratorT const &end, token_id id) +{ + using namespace boost::wave; + if (token_id(*it) == id) + return true; + if (++it == end) + return false; + + while (IS_CATEGORY(*it, WhiteSpaceTokenType) || + T_NEWLINE == token_id(*it)) + { + if (++it == end) + return false; + } + return token_id(*it) == id; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Get the full name of a given macro name (concatenate the string +// representations of the single tokens). +// +/////////////////////////////////////////////////////////////////////////////// +template +inline std::string +get_full_name(IteratorT const &begin, IteratorT const &end) +{ + std::string full_name; + for (IteratorT err_it = begin; err_it != end; ++err_it) + full_name += (*err_it).get_value().c_str(); + + return full_name; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// The following predicate is used in conjunction with the remove_copy_if +// algorithm to allow the detection of an eventually copied operator ##. +// No removal is performed in any case. +// +/////////////////////////////////////////////////////////////////////////////// +class find_concat_operator { +public: + find_concat_operator(bool &found_) : found_concat(found_) {} + + template + bool operator()(TokenT const &tok) + { + using namespace boost::wave; + if (T_POUND_POUND == BASE_TOKEN(token_id(tok))) + found_concat = true; + return false; + } + +private: + bool &found_concat; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_MACROMAP_UTIL_HPP_HK041119) diff --git a/include/boost/wave/util/eat_whitespace.hpp b/include/boost/wave/util/eat_whitespace.hpp new file mode 100644 index 000000000..6407ef390 --- /dev/null +++ b/include/boost/wave/util/eat_whitespace.hpp @@ -0,0 +1,158 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + Whitespace eater + + http://spirit.sourceforge.net/ + + Copyright (c) 2003 Paul Mensonides + Copyright (c) 2001-2005 Hartmut Kaiser. + 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) +=============================================================================*/ + +#if !defined(EAT_WHITESPACE_HPP_4CE9AD17_F82D_4AB2_A117_555DF0DCC801_INCLUDED) +#define EAT_WHITESPACE_HPP_4CE9AD17_F82D_4AB2_A117_555DF0DCC801_INCLUDED + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +template +class eat_whitespace { + +public: + eat_whitespace(); + + bool may_skip (TokenT &token, bool &skipped_newline); + +private: + typedef bool state_t(TokenT &token, bool &skipped_newline); + state_t eat_whitespace::* state; + state_t general, newline, newline_2nd, whitespace; +}; + +template +inline +eat_whitespace::eat_whitespace() +: state(&eat_whitespace::newline) +{ +} + +template +inline bool +eat_whitespace::may_skip(TokenT &token, bool &skipped_newline) +{ + return (this->*state)(token, skipped_newline); +} + +template +inline bool +eat_whitespace::general(TokenT &token, bool &skipped_newline) +{ + using boost::wave::token_id; + + token_id id = token_id(token); + if (T_NEWLINE == id || T_CPPCOMMENT == id) { + state = &eat_whitespace::newline; + } + else if (T_SPACE == id || T_SPACE2 == id || T_CCOMMENT == id) { + state = &eat_whitespace::whitespace; + + if (T_CCOMMENT == id) { + if (TokenT::string_type::npos != + token.get_value().find_first_of("\n")) + { + skipped_newline = true; + } + } + + if (token.get_value().size() > 1) + token.set_value(" "); // replace with a single space + } + else { + state = &eat_whitespace::general; + } + return false; +} + +template +inline bool +eat_whitespace::newline(TokenT &token, bool &skipped_newline) +{ + using namespace boost::wave; + + token_id id = token_id(token); + if (T_NEWLINE == id || T_CPPCOMMENT == id) { + skipped_newline = true; + state = &eat_whitespace::newline_2nd; + return true; + } + else if (T_SPACE != id && T_SPACE2 != id && T_CCOMMENT != id) { + return general(token, skipped_newline); + } + + if (T_CCOMMENT == id) { + if (TokenT::string_type::npos != + token.get_value().find_first_of("\n")) + { + skipped_newline = true; + } + } + return true; +} + +template +inline bool +eat_whitespace::newline_2nd(TokenT &token, bool &skipped_newline) +{ + using namespace boost::wave; + + token_id id = token_id(token); + if (T_SPACE == id || T_SPACE2 == id) + return true; + if (T_CCOMMENT == id) { + if (TokenT::string_type::npos != + token.get_value().find_first_of("\n")) + { + skipped_newline = true; + } + return true; + } + if (T_NEWLINE != id && T_CPPCOMMENT != id) + return general(token, skipped_newline); + + skipped_newline = true; + return true; +} + +template +inline bool +eat_whitespace::whitespace(TokenT &token, bool &skipped_newline) +{ + using namespace boost::wave; + + token_id id = token_id(token); + if (T_SPACE != id && T_SPACE2 != id && T_CCOMMENT != id) + return general(token, skipped_newline); + + if (T_CCOMMENT == id) { + if (TokenT::string_type::npos != + token.get_value().find_first_of("\n")) + { + skipped_newline = true; + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(EAT_WHITESPACE_HPP_4CE9AD17_F82D_4AB2_A117_555DF0DCC801_INCLUDED) + diff --git a/include/boost/wave/util/file_position.hpp b/include/boost/wave/util/file_position.hpp new file mode 100644 index 000000000..5094cb2e1 --- /dev/null +++ b/include/boost/wave/util/file_position.hpp @@ -0,0 +1,170 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the position_iterator and file_position templates + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(FILE_POSITION_H_52BDEDF7_DAD3_4F24_802F_E66BB8098F68_INCLUDED) +#define FILE_POSITION_H_52BDEDF7_DAD3_4F24_802F_E66BB8098F68_INCLUDED + +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// +// file_position +// +// A structure to hold positional information. This includes the filename, +// line number and column number of a current token position. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct file_position { + +public: + typedef StringT string_type; + + file_position() + : file(), line(1), column(1) + {} + explicit file_position(string_type const& file_, int line_ = 1, + int column_ = 1) + : file(file_), line(line_), column(column_) + {} + +// accessors + string_type const &get_file() const { return file; } + int get_line() const { return line; } + int get_column() const { return column; } + + void set_file(string_type const &file_) { file = file_; } + void set_line(int line_) { line = line_; } + void set_column(int column_) { column = column_; } + +private: + string_type file; + int line; + int column; +}; + +template +bool operator== (file_position const &lhs, + file_position const &rhs) +{ + return lhs.get_column() == rhs.get_column() && + lhs.get_line() == rhs.get_line() && lhs.get_file() == rhs.get_file(); +} + +template +inline std::ostream & +operator<< (std::ostream &o, file_position const &pos) +{ + o << pos.get_file() << "(" << pos.get_line() << ")"; + return o; +} + +typedef file_position file_position_type; + +/////////////////////////////////////////////////////////////////////////////// +// +// position_iterator +// +// The position_iterator used by Wave is now based on the corresponding Spirit +// type. This type is used with our own file_position though. The needed +// specialization of the boost::spirit::position_policy class is provided +// below. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct position_iterator +: boost::spirit::position_iterator +{ + typedef boost::spirit::position_iterator base_t; + + position_iterator() + { + } + + position_iterator(IteratorT const &begin, IteratorT const &end, + PositionT const &pos) + : base_t(begin, end, pos) + { + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave + +/////////////////////////////////////////////////////////////////////////////// + +#if SPIRIT_VERSION >= 0x1700 + +namespace spirit { + +/////////////////////////////////////////////////////////////////////////////// +// +// The boost::spirit::position_policy has to be specialized for our +// file_position class +// +/////////////////////////////////////////////////////////////////////////////// + + template <> + class position_policy { + + public: + position_policy() + : m_CharsPerTab(4) + {} + + void next_line(boost::wave::util::file_position_type &pos) + { + pos.set_line(pos.get_line() + 1); + pos.set_column(1); + } + + void set_tab_chars(unsigned int chars) + { + m_CharsPerTab = chars; + } + + void next_char(boost::wave::util::file_position_type &pos) + { + pos.set_column(pos.get_column() + 1); + } + + void tabulation(boost::wave::util::file_position_type &pos) + { + pos.set_column(pos.get_column() + m_CharsPerTab - + (pos.get_column() - 1) % m_CharsPerTab); + } + + private: + unsigned int m_CharsPerTab; + }; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace spirit + +#endif // SPIRIT_VERSION >= 0x1700 + +} // namespace boost + +#endif // !defined(FILE_POSITION_H_52BDEDF7_DAD3_4F24_802F_E66BB8098F68_INCLUDED) diff --git a/include/boost/wave/util/flex_string.hpp b/include/boost/wave/util/flex_string.hpp new file mode 100644 index 000000000..a027e4707 --- /dev/null +++ b/include/boost/wave/util/flex_string.hpp @@ -0,0 +1,2327 @@ +// This code is taken from +// Generic: A Policy-Based basic_string Implementation +// Copyright(c) Andrei Alexandrescu +// The code is considered to be in the public domain. +// http://www.cuj.com/experts/1906/alexandr.htm?topic=experts +// +// #HK030306: +// - Moved into the namespace boost::wave::util +// - Added a bunch of missing typename(s) +// - Integrated with boost config +// - Added a missing header include +// - Added special constructors and operator= to allow CowString to be +// a real COW-string (removed unnecessary data copying) +// - Fixed a string terminating bug in append +// +// #HK040109: +// - Incorporated the changes from Andrei's latest version of this class + +#ifndef FLEX_STRING_INC_ +#define FLEX_STRING_INC_ + +/* +//////////////////////////////////////////////////////////////////////////////// +template +class StoragePolicy +{ + typedef E value_type; + typedef @ iterator; + typedef @ const_iterator; + typedef A allocator_type; + typedef @ size_type; + + StoragePolicy(const StoragePolicy& s); + StoragePolicy(const A&); + StoragePolicy(const E* s, size_type len, const A&); + StoragePolicy(size_type len, E c, const A&); + ~StoragePolicy(); + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + size_type size() const; + size_type max_size() const; + size_type capacity() const; + + void reserve(size_type res_arg); + + void append(const E* s, size_type sz); + + template + void append(InputIterator b, InputIterator e); + + void resize(size_type newSize, E fill); + + void swap(StoragePolicy& rhs); + + const E* c_str() const; + const E* data() const; + + A get_allocator() const; +}; +//////////////////////////////////////////////////////////////////////////////// +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +namespace flex_string_details +{ + template + inline void pod_fill(Pod* b, Pod* e, T c) + { + switch ((e - b) & 7) + { + case 0: + while (b != e) + { + *b = c; ++b; + case 7: *b = c; ++b; + case 6: *b = c; ++b; + case 5: *b = c; ++b; + case 4: *b = c; ++b; + case 3: *b = c; ++b; + case 2: *b = c; ++b; + case 1: *b = c; ++b; + } + } + } + + template + inline void pod_move(const Pod* b, const Pod* e, Pod* d) + { + using namespace std; + memmove(d, b, (e - b) * sizeof(*b)); + } + + template + inline Pod* pod_copy(const Pod* b, const Pod* e, Pod* d) + { + const size_t s = e - b; + using namespace std; + memcpy(d, b, s * sizeof(*b)); + return d + s; + } + + template struct get_unsigned + { + typedef T result; + }; + + template <> struct get_unsigned + { + typedef unsigned char result; + }; + + template <> struct get_unsigned + { + typedef unsigned char result; + }; + + template <> struct get_unsigned + { + typedef unsigned short int result; + }; + + template <> struct get_unsigned + { + typedef unsigned int result; + }; + + template <> struct get_unsigned + { + typedef unsigned long int result; + }; + + enum Shallow {}; +} + +template class mallocator +{ +public: + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::size_t size_type; + //typedef unsigned int size_type; + //typedef std::ptrdiff_t difference_type; + typedef int difference_type; + + template + struct rebind { typedef mallocator other; }; + + mallocator() {} + mallocator(const mallocator&) {} + //template + //mallocator(const mallocator&) {} + ~mallocator() {} + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const + { + return x; + } + + pointer allocate(size_type n, const_pointer = 0) + { + using namespace std; + void* p = malloc(n * sizeof(T)); + if (!p) throw bad_alloc(); + return static_cast(p); + } + + void deallocate(pointer p, size_type) + { + using namespace std; + free(p); + } + + size_type max_size() const + { + return static_cast(-1) / sizeof(T); + } + + void construct(pointer p, const value_type& x) + { + new(p) value_type(x); + } + + void destroy(pointer p) + { + p->~value_type(); + } + +private: + void operator=(const mallocator&); +}; + +template<> class mallocator +{ + typedef void value_type; + typedef void* pointer; + typedef const void* const_pointer; + + template + struct rebind { typedef mallocator other; }; +}; + +template +inline bool operator==(const mallocator&, + const mallocator&) { + return true; +} + +template +inline bool operator!=(const mallocator&, + const mallocator&) { + return false; +} + +template +typename Allocator::pointer Reallocate( + Allocator& alloc, + typename Allocator::pointer p, + typename Allocator::size_type oldObjCount, + typename Allocator::size_type newObjCount, + void*) +{ + // @@@ not implemented +} + +template +typename Allocator::pointer Reallocate( + Allocator& alloc, + typename Allocator::pointer p, + typename Allocator::size_type oldObjCount, + typename Allocator::size_type newObjCount, + mallocator*) +{ + // @@@ not implemented +} + +//////////////////////////////////////////////////////////////////////////////// +// class template SimpleStringStorage +// Allocates memory with malloc +//////////////////////////////////////////////////////////////////////////////// + +template > +class SimpleStringStorage +{ + // The "public" below exists because MSVC can't do template typedefs +public: + struct Data + { + Data() : pEnd_(buffer_), pEndOfMem_(buffer_) { buffer_[0] = E(0); } + + E* pEnd_; + E* pEndOfMem_; + E buffer_[1]; + }; + static const Data emptyString_; + + typedef typename A::size_type size_type; + +private: + Data* pData_; + + void Init(size_type size, size_type capacity) + { + BOOST_ASSERT(size <= capacity); + if (capacity == 0) + { + pData_ = const_cast(&emptyString_); + } + else + { + // 11-17-2000: comment added: + // No need to allocate (capacity + 1) to + // accomodate the terminating 0, because Data already + // has one one character in there + pData_ = static_cast( + malloc(sizeof(Data) + capacity * sizeof(E))); + if (!pData_) throw std::bad_alloc(); + pData_->pEnd_ = pData_->buffer_ + size; + pData_->pEndOfMem_ = pData_->buffer_ + capacity; + } + } + +private: + // Warning - this doesn't initialize pData_. Used in reserve() + SimpleStringStorage() + { } + +public: + typedef E value_type; + typedef E* iterator; + typedef const E* const_iterator; + typedef A allocator_type; + + SimpleStringStorage(const SimpleStringStorage& rhs) + { + const size_type sz = rhs.size(); + Init(sz, sz); + if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin()); + } + + SimpleStringStorage(const SimpleStringStorage& s, + flex_string_details::Shallow) + : pData_(s.pData_) + { + } + + SimpleStringStorage(const A&) + { pData_ = const_cast(&emptyString_); } + + SimpleStringStorage(const E* s, size_type len, const A&) + { + Init(len, len); + flex_string_details::pod_copy(s, s + len, begin()); + } + + SimpleStringStorage(size_type len, E c, const A&) + { + Init(len, len); + flex_string_details::pod_fill(begin(), end(), c); + } + + SimpleStringStorage& operator=(const SimpleStringStorage& rhs) + { + const size_type sz = rhs.size(); + reserve(sz); + flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin()); + pData_->pEnd_ = &*begin() + sz; + return *this; + } + + ~SimpleStringStorage() + { + BOOST_ASSERT(begin() <= end()); + if (pData_ != &emptyString_) free(pData_); + } + + iterator begin() + { return pData_->buffer_; } + + const_iterator begin() const + { return pData_->buffer_; } + + iterator end() + { return pData_->pEnd_; } + + const_iterator end() const + { return pData_->pEnd_; } + + size_type size() const + { return pData_->pEnd_ - pData_->buffer_; } + + size_type max_size() const + { return size_t(-1) / sizeof(E) - sizeof(Data) - 1; } + + size_type capacity() const + { return pData_->pEndOfMem_ - pData_->buffer_; } + + void reserve(size_type res_arg) + { + if (res_arg <= capacity()) + { + // @@@ insert shrinkage here if you wish + return; + } + + if (pData_ == &emptyString_) + { + Init(0, res_arg); + } + else + { + const size_type sz = size(); + + void* p = realloc(pData_, + sizeof(Data) + res_arg * sizeof(E)); + if (!p) throw std::bad_alloc(); + + if (p != pData_) + { + pData_ = static_cast(p); + pData_->pEnd_ = pData_->buffer_ + sz; + } + pData_->pEndOfMem_ = pData_->buffer_ + res_arg; + } + } + + void append(const E* s, size_type sz) + { + const size_type neededCapacity = size() + sz; + + if (capacity() < neededCapacity) + { + const iterator b = begin(); + static std::less_equal le; + if (le(b, s) && le(s, end())) + { + // aliased + const size_type offset = s - b; + reserve(neededCapacity); + s = begin() + offset; + } + else + { + reserve(neededCapacity); + } + } + flex_string_details::pod_copy(s, s + sz, end()); + pData_->pEnd_ += sz; + } + + template + void append(InputIterator b, InputIterator e) + { + // @@@ todo: optimize this depending on iterator type + for (; b != e; ++b) + { + *this += *b; + } + } + + void resize(size_type newSize, E fill) + { + const int delta = int(newSize - size()); + if (delta == 0) return; + + if (delta > 0) + { + if (newSize > capacity()) + { + reserve(newSize); + } + E* e = &*end(); + flex_string_details::pod_fill(e, e + delta, fill); + } + pData_->pEnd_ = pData_->buffer_ + newSize; + } + + void swap(SimpleStringStorage& rhs) + { + std::swap(pData_, rhs.pData_); + } + + const E* c_str() const + { + if (pData_ != &emptyString_) *pData_->pEnd_ = E(); + return pData_->buffer_; + } + + const E* data() const + { return pData_->buffer_; } + + A get_allocator() const + { return A(); } +}; + +template +const typename SimpleStringStorage::Data +SimpleStringStorage::emptyString_ = typename SimpleStringStorage::Data(); +//{ +// const_cast(SimpleStringStorage::emptyString_.buffer_), +// const_cast(SimpleStringStorage::emptyString_.buffer_), +// { E() } +//}; + +//////////////////////////////////////////////////////////////////////////////// +// class template AllocatorStringStorage +// Allocates with your allocator +// Takes advantage of the Empty Base Optimization if available +//////////////////////////////////////////////////////////////////////////////// + +template > +class AllocatorStringStorage : public A +{ + typedef typename A::size_type size_type; + typedef typename SimpleStringStorage::Data Data; + + void* Alloc(size_type sz, const void* p = 0) + { + return A::allocate(1 + (sz - 1) / sizeof(E), + static_cast(p)); + } + + void* Realloc(void* p, size_type oldSz, size_type newSz) + { + void* r = Alloc(newSz); + flex_string_details::pod_copy(p, p + Min(oldSz, newSz), r); + Free(p, oldSz); + return r; + } + + void Free(void* p, size_type sz) + { + A::deallocate(static_cast(p), sz); + } + + Data* pData_; + + void Init(size_type size, size_type cap) + { + BOOST_ASSERT(size <= cap); + + if (cap == 0) + { + pData_ = const_cast( + &SimpleStringStorage::emptyString_); + } + else + { + pData_ = static_cast(Alloc( + cap * sizeof(E) + sizeof(Data))); + pData_->pEnd_ = pData_->buffer_ + size; + pData_->pEndOfMem_ = pData_->buffer_ + cap; + } + } + +public: + typedef E value_type; + typedef A allocator_type; + typedef typename A::pointer iterator; + typedef typename A::const_pointer const_iterator; + + AllocatorStringStorage(const AllocatorStringStorage& rhs) + : A(rhs.get_allocator()) + { + const size_type sz = rhs.size(); + Init(sz, sz); + if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin()); + } + + AllocatorStringStorage(const AllocatorStringStorage& s, + flex_string_details::Shallow) + : A(s.get_allocator()) + { + pData_ = s.pData_; + } + + AllocatorStringStorage(const A& a) : A(a) + { + pData_ = const_cast( + &SimpleStringStorage::emptyString_); + } + + AllocatorStringStorage(const E* s, size_type len, const A& a) + : A(a) + { + Init(len, len); + flex_string_details::pod_copy(s, s + len, begin()); + } + + AllocatorStringStorage(size_type len, E c, const A& a) + : A(a) + { + Init(len, len); + flex_string_details::pod_fill(&*begin(), &*end(), c); + } + + AllocatorStringStorage& operator=(const AllocatorStringStorage& rhs) + { + const size_type sz = rhs.size(); + reserve(sz); + flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin()); + pData_->pEnd_ = &*begin() + rhs.size(); + return *this; + } + + ~AllocatorStringStorage() + { + if (capacity()) + { + Free(pData_, + sizeof(Data) + capacity() * sizeof(E)); + } + } + + iterator begin() + { return pData_->buffer_; } + + const_iterator begin() const + { return pData_->buffer_; } + + iterator end() + { return pData_->pEnd_; } + + const_iterator end() const + { return pData_->pEnd_; } + + size_type size() const + { return size_type(end() - begin()); } + + size_type max_size() const + { return A::max_size(); } + + size_type capacity() const + { return size_type(pData_->pEndOfMem_ - pData_->buffer_); } + + void resize(size_type n, E c) + { + reserve(n); + iterator newEnd = begin() + n; + iterator oldEnd = end(); + if (newEnd > oldEnd) + { + // Copy the characters + flex_string_details::pod_fill(oldEnd, newEnd, c); + } + if (capacity()) pData_->pEnd_ = newEnd; + } + + void reserve(size_type res_arg) + { + if (res_arg <= capacity()) + { + // @@@ shrink to fit here + return; + } + + A& myAlloc = *this; + AllocatorStringStorage newStr(myAlloc); + newStr.Init(size(), res_arg); + + flex_string_details::pod_copy(begin(), end(), newStr.begin()); + + swap(newStr); + } + + void append(const E* s, size_type sz) + { + const size_type neededCapacity = size() + sz; + + if (capacity() < neededCapacity) + { + const iterator b = begin(); + static std::less_equal le; + if (le(b, s) && le(s, end())) + { + // aliased + const size_type offset = s - b; + reserve(neededCapacity); + s = begin() + offset; + } + else + { + reserve(neededCapacity); + } + } + flex_string_details::pod_copy(s, s + sz, end()); + pData_->pEnd_ += sz; + } + + void swap(AllocatorStringStorage& rhs) + { + // @@@ The following line is commented due to a bug in MSVC + //std::swap(lhsAlloc, rhsAlloc); + std::swap(pData_, rhs.pData_); + } + + const E* c_str() const + { + if (pData_ != &SimpleStringStorage::emptyString_) + { + *pData_->pEnd_ = E(); + } + return &*begin(); + } + + const E* data() const + { return &*begin(); } + + A get_allocator() const + { return *this; } +}; + +//////////////////////////////////////////////////////////////////////////////// +// class template VectorStringStorage +// Uses std::vector +// Takes advantage of the Empty Base Optimization if available +//////////////////////////////////////////////////////////////////////////////// + +template > +class VectorStringStorage : protected std::vector +{ + typedef std::vector base; + +public: // protected: + typedef E value_type; + typedef typename base::iterator iterator; + typedef typename base::const_iterator const_iterator; + typedef A allocator_type; + typedef typename A::size_type size_type; + + VectorStringStorage(const VectorStringStorage& s) : base(s) + { } + + VectorStringStorage(const A& a) : base(1, E(), a) + { } + + VectorStringStorage(const E* s, size_type len, const A& a) + : base(a) + { + base::reserve(len + 1); + base::insert(base::end(), s, s + len); + // Terminating zero + base::insert(base::end(), E()); + } + + VectorStringStorage(size_type len, E c, const A& a) + : base(len + 1, c, a) + { + // Terminating zero + base::back() = E(); + } + + VectorStringStorage& operator=(const VectorStringStorage& rhs) + { + base& v = *this; + v = rhs; + return *this; + } + + iterator begin() + { return base::begin(); } + + const_iterator begin() const + { return base::begin(); } + + iterator end() + { return base::end() - 1; } + + const_iterator end() const + { return base::end() - 1; } + + size_type size() const + { return base::size() - 1; } + + size_type max_size() const + { return base::max_size() - 1; } + + size_type capacity() const + { return base::capacity() - 1; } + + void reserve(size_type res_arg) + { + BOOST_ASSERT(res_arg < max_size()); + base::reserve(res_arg + 1); + } + + void append(const E* s, size_type sz) + { + // Check for aliasing because std::vector doesn't do it. + static std::less_equal le; + if (!base::empty()) + { + const E* start = &base::front(); + if (le(start, s) && le(s, start + size())) + { + // aliased + const size_type offset = s - start; + reserve(size() + sz); + s = &base::front() + offset; + } + } + base::insert(end(), s, s + sz); + } + + template + void append(InputIterator b, InputIterator e) + { + base::insert(end(), b, e); + } + + void resize(size_type n, E c) + { + base::reserve(n + 1); + base::back() = c; + base::resize(n + 1, c); + base::back() = E(); + } + + void swap(VectorStringStorage& rhs) + { base::swap(rhs); } + + const E* c_str() const + { return &*begin(); } + + const E* data() const + { return &*begin(); } + + A get_allocator() const + { return base::get_allocator(); } +}; + +//////////////////////////////////////////////////////////////////////////////// +// class template SmallStringOpt +// Builds the small string optimization over any other storage +//////////////////////////////////////////////////////////////////////////////// + +template +class SmallStringOpt +{ +public: + typedef typename Storage::value_type value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef typename Storage::allocator_type allocator_type; + typedef typename allocator_type::size_type size_type; + +private: + enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage) + ? threshold * sizeof(value_type) + : sizeof(Storage) }; + + enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) }; + +public: + enum { maxSmallString = + (temp2 + sizeof(value_type) - 1) / sizeof(value_type) }; + +private: + enum { magic = maxSmallString + 1 }; + + union + { + mutable value_type buf_[maxSmallString + 1]; + Align align_; + }; + + Storage& GetStorage() + { + BOOST_ASSERT(buf_[maxSmallString] == magic); + Storage* p = reinterpret_cast(&buf_[0]); + return *p; + } + + const Storage& GetStorage() const + { + BOOST_ASSERT(buf_[maxSmallString] == magic); + const Storage *p = reinterpret_cast(&buf_[0]); + return *p; + } + + bool Small() const + { + return buf_[maxSmallString] != magic; + } + +public: + SmallStringOpt(const SmallStringOpt& s) + { + if (s.Small()) + { + flex_string_details::pod_copy( + s.buf_, + s.buf_ + s.size(), + buf_); + } + else + { + new(buf_) Storage(s.GetStorage()); + } + buf_[maxSmallString] = s.buf_[maxSmallString]; + } + + SmallStringOpt(const allocator_type&) + { + buf_[maxSmallString] = maxSmallString; + } + + SmallStringOpt(const value_type* s, size_type len, const allocator_type& a) + { + if (len <= maxSmallString) + { + flex_string_details::pod_copy(s, s + len, buf_); + buf_[maxSmallString] = value_type(maxSmallString - len); + } + else + { + new(buf_) Storage(s, len, a); + buf_[maxSmallString] = magic; + } + } + + SmallStringOpt(size_type len, value_type c, const allocator_type& a) + { + if (len <= maxSmallString) + { + flex_string_details::pod_fill(buf_, buf_ + len, c); + buf_[maxSmallString] = value_type(maxSmallString - len); + } + else + { + new(buf_) Storage(len, c, a); + buf_[maxSmallString] = magic; + } + } + + SmallStringOpt& operator=(const SmallStringOpt& rhs) + { + reserve(rhs.size()); + resize(0, 0); + append(rhs.data(), rhs.size()); + return *this; + } + + ~SmallStringOpt() + { + if (!Small()) GetStorage().~Storage(); + } + + iterator begin() + { + if (Small()) return buf_; + return &*GetStorage().begin(); + } + + const_iterator begin() const + { + if (Small()) return buf_; + return &*GetStorage().begin(); + } + + iterator end() + { + if (Small()) return buf_ + maxSmallString - buf_[maxSmallString]; + return &*GetStorage().end(); + } + + const_iterator end() const + { + if (Small()) return buf_ + maxSmallString - buf_[maxSmallString]; + return &*GetStorage().end(); + } + + size_type size() const + { + BOOST_ASSERT(!Small() || maxSmallString >= buf_[maxSmallString]); + return Small() + ? maxSmallString - buf_[maxSmallString] + : GetStorage().size(); + } + + size_type max_size() const + { return get_allocator().max_size(); } + + size_type capacity() const + { return Small() ? maxSmallString : GetStorage().capacity(); } + + void reserve(size_type res_arg) + { + if (Small()) + { + if (res_arg <= maxSmallString) return; + SmallStringOpt temp(*this); + this->~SmallStringOpt(); + new(buf_) Storage(temp.data(), temp.size(), + temp.get_allocator()); + buf_[maxSmallString] = magic; + GetStorage().reserve(res_arg); + } + else + { + GetStorage().reserve(res_arg); + } + BOOST_ASSERT(capacity() >= res_arg); + } + + void append(const value_type* s, size_type sz) + { + if (!Small()) + { + GetStorage().append(s, sz); + } + else + { + // append to a small string + const size_type neededCapacity = + maxSmallString - buf_[maxSmallString] + sz; + + if (maxSmallString < neededCapacity) + { + // need to change storage strategy + allocator_type alloc; + Storage temp(alloc); + temp.reserve(neededCapacity); + temp.append(buf_, maxSmallString - buf_[maxSmallString]); + temp.append(s, sz); + buf_[maxSmallString] = magic; + new(buf_) Storage(temp.get_allocator()); + GetStorage().swap(temp); + } + else + { + flex_string_details::pod_move(s, s + sz, + buf_ + maxSmallString - buf_[maxSmallString]); + buf_[maxSmallString] -= value_type(sz); + } + } + } + + template + void append(InputIterator b, InputIterator e) + { + // @@@ todo: optimize this depending on iterator type + for (; b != e; ++b) + { + *this += *b; + } + } + + void resize(size_type n, value_type c) + { + if (Small()) + { + if (n > maxSmallString) + { + // Small string resized to big string + SmallStringOpt temp(*this); // can't throw + // 11-17-2001: correct exception safety bug + Storage newString(temp.data(), temp.size(), + temp.get_allocator()); + newString.resize(n, c); + // We make the reasonable assumption that an empty Storage + // constructor won't throw + this->~SmallStringOpt(); + new(&buf_[0]) Storage(temp.get_allocator()); + buf_[maxSmallString] = value_type(magic); + GetStorage().swap(newString); + } + else + { + // Small string resized to small string + // 11-17-2001: bug fix: terminating zero not copied + size_type toFill = n > size() ? n - size() : 0; + flex_string_details::pod_fill(end(), end() + toFill, c); + buf_[maxSmallString] = value_type(maxSmallString - n); + } + } + else + { + if (n > maxSmallString) + { + // Big string resized to big string + GetStorage().resize(n, c); + } + else + { + // Big string resized to small string + // 11-17=2001: bug fix in the BOOST_ASSERTion below + BOOST_ASSERT(capacity() > n); + SmallStringOpt newObj(data(), n, get_allocator()); + newObj.swap(*this); + } + } + } + + void swap(SmallStringOpt& rhs) + { + if (Small()) + { + if (rhs.Small()) + { + // Small swapped with small + std::swap_ranges(buf_, buf_ + maxSmallString + 1, + rhs.buf_); + } + else + { + // Small swapped with big + // Make a copy of myself - can't throw + SmallStringOpt temp(*this); + // Nuke myself + this->~SmallStringOpt(); + // Make an empty storage for myself (likely won't throw) + new(buf_) Storage(0, value_type(), rhs.get_allocator()); + buf_[maxSmallString] = magic; + // Recurse to this same function + swap(rhs); + // Nuke rhs + rhs.~SmallStringOpt(); + // Build the new small string into rhs + new(&rhs) SmallStringOpt(temp); + } + } + else + { + if (rhs.Small()) + { + // Big swapped with small + // Already implemented, recurse with reversed args + rhs.swap(*this); + } + else + { + // Big swapped with big + GetStorage().swap(rhs.GetStorage()); + } + } + } + + const value_type* c_str() const + { + if (!Small()) return GetStorage().c_str(); + buf_[maxSmallString - buf_[maxSmallString]] = value_type(); + return buf_; + } + + const value_type* data() const + { return Small() ? buf_ : GetStorage().data(); } + + allocator_type get_allocator() const + { return allocator_type(); } +}; + +//////////////////////////////////////////////////////////////////////////////// +// class template CowString +// Implements Copy on Write over any storage +//////////////////////////////////////////////////////////////////////////////// + +template +class CowString +{ + typedef typename Storage::value_type E; + typedef typename flex_string_details::get_unsigned::result RefCountType; + +public: + typedef E value_type; + typedef typename Storage::iterator iterator; + typedef typename Storage::const_iterator const_iterator; + typedef typename Storage::allocator_type allocator_type; + typedef typename allocator_type::size_type size_type; + +private: + union + { + mutable char buf_[sizeof(Storage)]; + Align align_; + }; + + Storage& Data() const + { return *reinterpret_cast(buf_); } + + RefCountType GetRefs() const + { + const Storage& d = Data(); + BOOST_ASSERT(d.size() > 0); + BOOST_ASSERT(static_cast(*d.begin()) != 0); + return *d.begin(); + } + + RefCountType& Refs() + { + Storage& d = Data(); + BOOST_ASSERT(d.size() > 0); + return reinterpret_cast(*d.begin()); + } + + void MakeUnique() const + { + BOOST_ASSERT(GetRefs() >= 1); + if (GetRefs() == 1) return; + + union + { + char buf_[sizeof(Storage)]; + Align align_; + } temp; + + new(buf_) Storage( + *new(temp.buf_) Storage(Data()), + flex_string_details::Shallow()); + *Data().begin() = 1; + } + +public: + CowString(const CowString& s) + { + if (s.GetRefs() == std::numeric_limits::max()) + { + // must make a brand new copy + new(buf_) Storage(s.Data()); // non shallow + Refs() = 1; + } + else + { + new(buf_) Storage(s.Data(), flex_string_details::Shallow()); + ++Refs(); + } + BOOST_ASSERT(Data().size() > 0); + } + + CowString(const allocator_type& a) + { + new(buf_) Storage(1, 1, a); + } + + CowString(const E* s, size_type len, const allocator_type& a) + { + // Warning - MSVC's debugger has trouble tracing through the code below. + // It seems to be a const-correctness issue + // + new(buf_) Storage(a); + Data().reserve(len + 1); + Data().resize(1, 1); + Data().append(s, len); + } + + CowString(size_type len, E c, const allocator_type& a) + { + new(buf_) Storage(len + 1, c, a); + Refs() = 1; + } + + CowString& operator=(const CowString& rhs) + { +// CowString(rhs).swap(*this); + if (--Refs() == 0) Data().~Storage(); + if (rhs.GetRefs() == std::numeric_limits::max()) + { + // must make a brand new copy + new(buf_) Storage(rhs.Data()); // non shallow + Refs() = 1; + } + else + { + new(buf_) Storage(rhs.Data(), flex_string_details::Shallow()); + ++Refs(); + } + BOOST_ASSERT(Data().size() > 0); + return *this; + } + + ~CowString() + { + BOOST_ASSERT(Data().size() > 0); + if (--Refs() == 0) Data().~Storage(); + } + + iterator begin() + { + BOOST_ASSERT(Data().size() > 0); + MakeUnique(); + return Data().begin() + 1; + } + + const_iterator begin() const + { + BOOST_ASSERT(Data().size() > 0); + return Data().begin() + 1; + } + + iterator end() + { + MakeUnique(); + return Data().end(); + } + + const_iterator end() const + { + return Data().end(); + } + + size_type size() const + { + BOOST_ASSERT(Data().size() > 0); + return Data().size() - 1; + } + + size_type max_size() const + { + BOOST_ASSERT(Data().max_size() > 0); + return Data().max_size() - 1; + } + + size_type capacity() const + { + BOOST_ASSERT(Data().capacity() > 0); + return Data().capacity() - 1; + } + + void resize(size_type n, E c) + { + BOOST_ASSERT(Data().size() > 0); + MakeUnique(); + Data().resize(n + 1, c); + } + + void append(const E* s, size_type sz) + { + MakeUnique(); + Data().append(s, sz); + } + + template + void append(InputIterator b, InputIterator e) + { + MakeUnique(); + // @@@ todo: optimize this depending on iterator type + for (; b != e; ++b) + { + *this += *b; + } + } + + void reserve(size_type res_arg) + { + if (capacity() > res_arg) return; + MakeUnique(); + Data().reserve(res_arg + 1); + } + + void swap(CowString& rhs) + { + Data().swap(rhs.Data()); + } + + const E* c_str() const + { + BOOST_ASSERT(Data().size() > 0); + return Data().c_str() + 1; + } + + const E* data() const + { + BOOST_ASSERT(Data().size() > 0); + return Data().data() + 1; + } + + allocator_type get_allocator() const + { + return Data().get_allocator(); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// class template flex_string +// a std::basic_string compatible implementation +// Uses a Storage policy +//////////////////////////////////////////////////////////////////////////////// + +template , + class A = std::allocator, + class Storage = AllocatorStringStorage > +class flex_string : private Storage +{ +#if defined(THROW_ON_ENFORCE) + template + static void Enforce(bool condition, Exception*, const char* msg) + { if (!condition) throw Exception(msg); } +#else + template + static inline void Enforce(bool condition, Exception*, const char* msg) + { BOOST_ASSERT(condition && msg); } +#endif // defined(THROW_ON_ENFORCE) + + bool Sane() const + { + return + begin() <= end() && + empty() == (size() == 0) && + empty() == (begin() == end()) && + size() <= max_size() && + capacity() <= max_size() && + size() <= capacity(); + } + + struct Invariant; + friend struct Invariant; + struct Invariant + { + Invariant(const flex_string& s) : s_(s) + { + BOOST_ASSERT(s_.Sane()); + } + ~Invariant() + { + BOOST_ASSERT(s_.Sane()); + } + private: + const flex_string& s_; + }; + +public: + // types + typedef T traits_type; + typedef typename traits_type::char_type value_type; + typedef A allocator_type; + typedef typename A::size_type size_type; + typedef typename A::difference_type difference_type; + + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + + typedef typename Storage::iterator iterator; + typedef typename Storage::const_iterator const_iterator; + + typedef boost::reverse_iterator reverse_iterator; + typedef boost::reverse_iterator const_reverse_iterator; + + static const size_type npos; // = size_type(-1) + +private: + static size_type Min(size_type lhs, size_type rhs) + { return lhs < rhs ? lhs : rhs; } + +public: + // 21.3.1 construct/copy/destroy + explicit flex_string(const A& a = A()) + : Storage(a) + {} + + flex_string(const flex_string& str) + : Storage(str) + { + } + + flex_string(const flex_string& str, size_type pos, + size_type n = npos, const A& a = A()) + : Storage(a) + { + Enforce(pos <= str.size(), (std::out_of_range*)0, ""); + assign(str, pos, n); + } + + flex_string(const value_type* s, const A& a = A()) + : Storage(s, traits_type::length(s), a) + {} + + flex_string(const value_type* s, size_type n, const A& a = A()) + : Storage(s, n, a) + {} + + flex_string(size_type n, value_type c, const A& a = A()) + : Storage(n, c, a) + {} + + template + flex_string(InputIterator begin, InputIterator end, const A& a = A()) + : Storage(a) + { + assign(begin, end); + } + + ~flex_string() + {} + + flex_string& operator=(const flex_string& str) + { + if (this != &str) { + Storage& s = *this; + s = str; + } + return *this; + } + + flex_string& operator=(const value_type* s) + { + assign(s); + return *this; + } + + flex_string& operator=(value_type c) + { + assign(1, c); + return *this; + } + + // 21.3.2 iterators: + iterator begin() + { return Storage::begin(); } + + const_iterator begin() const + { return Storage::begin(); } + + iterator end() + { return Storage::end(); } + + const_iterator end() const + { return Storage::end(); } + + reverse_iterator rbegin() + { return reverse_iterator(end()); } + + const_reverse_iterator rbegin() const + { return const_reverse_iterator(end()); } + + reverse_iterator rend() + { return reverse_iterator(begin()); } + + const_reverse_iterator rend() const + { return const_reverse_iterator(begin()); } + + // 21.3.3 capacity: + size_type size() const + { return Storage::size(); } + + size_type length() const + { return size(); } + + size_type max_size() const + { return Storage::max_size(); } + + void resize(size_type n, value_type c) + { Storage::resize(n, c); } + + void resize(size_type n) + { resize(n, value_type()); } + + size_type capacity() const + { return Storage::capacity(); } + + void reserve(size_type res_arg = 0) + { + Enforce(res_arg <= max_size(), (std::length_error*)0, ""); + Storage::reserve(res_arg); + } + + void clear() + { resize(0); } + + bool empty() const + { return size() == 0; } + + // 21.3.4 element access: + const_reference operator[](size_type pos) const + { return *(begin() + pos); } + + reference operator[](size_type pos) + { return *(begin() + pos); } + + const_reference at(size_type n) const + { + Enforce(n < size(), (std::out_of_range*)0, ""); + return (*this)[n]; + } + + reference at(size_type n) + { + Enforce(n < size(), (std::out_of_range*)0, ""); + return (*this)[n]; + } + + // 21.3.5 modifiers: + flex_string& operator+=(const flex_string& str) + { return append(str); } + + flex_string& operator+=(const value_type* s) + { return append(s); } + + flex_string& operator+=(value_type c) + { + const size_type cap = capacity(); + if (size() == cap) + { + reserve(cap << 1u); + } + resize(size() + 1, c); + return *this; + } + + flex_string& append(const flex_string& str) + { return append(str, 0, npos); } + + flex_string& append(const flex_string& str, size_type pos, + size_type n) + { + const size_type sz = str.size(); + Enforce(pos <= sz, (std::out_of_range*)0, ""); + return append(str.c_str() + pos, Min(n, sz - pos)); + } + + flex_string& append(const value_type* s, size_type n) + { + Storage::append(s, n); + return *this; + } + + flex_string& append(const value_type* s) + { return append(s, traits_type::length(s)); } + + flex_string& append(size_type n, value_type c) + { + resize(size() + n, c); + return *this; + } +/* + template + flex_string& append(InputIterator first, InputIterator last) + { + for (; first != last; ++first) *this += E(*first); + return *this; + } +*/ + void push_back(value_type c) + { + *this += c; + } + + flex_string& assign(const flex_string& str) + { + if (&str == this) return *this; + replace(0, size(), &*str.begin(), str.size()); + return *this; + } + + flex_string& assign(const flex_string& str, size_type pos, + size_type n) + { + Enforce(pos <= str.size(), (std::out_of_range*)0, ""); + return assign(str.data() + pos, Min(n, str.size() - pos)); + } + + flex_string& assign(const value_type* s, size_type n) + { + if (size() >= n) + { + flex_string_details::pod_move(s, s + n, &*begin()); + resize(n, value_type()); + } + else + { + flex_string_details::pod_move(s, s + size(), &*begin()); + Storage::append(s + size(), n - size()); + } + return *this; + } + + flex_string& assign(const value_type* s) + { return assign(s, traits_type::length(s)); } + + flex_string& assign(size_type n, value_type c) + { return replace(begin(), end(), n, c); } + + template + flex_string& assign(InputIterator first, InputIterator last) + { return replace(begin(), end(), first, last); } + + flex_string& insert(size_type pos1, const flex_string& str) + { return insert(pos1, str, 0, npos); } + + flex_string& insert(size_type pos1, const flex_string& str, + size_type pos2, size_type n) + { return replace(pos1, 0, str, pos2, n); } + + flex_string& insert(size_type pos, const value_type* s, size_type n) + { return replace(pos, 0, s, n); } + + flex_string& insert(size_type pos, const value_type* s) + { return insert(pos, s, traits_type::length(s)); } + + flex_string& insert(size_type pos, size_type n, value_type c) + { return replace(pos, 0, n, c); } + + iterator insert(iterator p, value_type c = value_type()) + { + const size_type pos = p - begin(); + insert(pos, &c, 1); + return begin() + pos; + } + + void insert(iterator p, size_type n, value_type c) + { insert(p - begin(), n, c); } + + template + void insert(iterator p, InputIterator first, InputIterator last) + { replace(p, p, first, last); } + + flex_string& erase(size_type pos = 0, size_type n = npos) + { + return replace(pos, Min(n, size() - pos), 0, value_type()); + } + + iterator erase(iterator position) + { + const size_type pos(position - begin()); + erase(pos, 1); + return begin() + pos; + } + + iterator erase(iterator first, iterator last) + { + const size_type pos(first - begin()); + erase(pos, last - first); + return begin() + pos; + } + + // @@@ replace + + flex_string& replace(size_type pos1, size_type n1, const flex_string& str) + { return replace(pos1, n1, str, 0, npos); } + + flex_string& replace(size_type pos1, size_type n1, const flex_string& str, + size_type pos2, size_type n2) + { + Enforce(pos1 <= length() && pos2 <= str.length(), + (std::out_of_range*)0, ""); + return replace(pos1, n1, &*str.begin() + pos2, + Min(n2, str.length() - pos2)); + } + + flex_string& replace(const size_type d, size_type n1, const value_type* s1, + const size_type n2) + { + using namespace flex_string_details; + Enforce(d <= size(), (std::out_of_range*)0, ""); + if (d + n1 > size()) n1 = size() - d; + const int delta = int(n2 - n1); + static const std::less_equal le = + std::less_equal(); + const bool aliased = le(&*begin(), s1) && le(s1, &*end()); + + if (delta > 0) + { + if (capacity() < size() + delta) + { + // realloc the string + if (aliased) + { + const size_type offset = s1 - &*begin(); + reserve(size() + delta); + s1 = &*begin() + offset; + } + else + { + reserve(size() + delta); + } + } + + const value_type* s2 = s1 + n2; + value_type* d1 = &*begin() + d; + value_type* d2 = d1 + n1; + + const int tailLen = int(&*end() - d2); + + if (delta <= tailLen) + { + value_type* oldEnd = &*end(); + // simple case + Storage::append(oldEnd - delta, delta); + + pod_move(d2, d2 + (tailLen - delta), d2 + delta); + if (le(d2, s1)) + { + if (aliased) + { + pod_copy(s1 + delta, s2 + delta, d1); + } + else + { + pod_copy(s1, s2, d1); + } + } + else + { + // d2 > s1 + if (le(d2, s2)) + { + BOOST_ASSERT(aliased); + pod_move(s1, d2, d1); + pod_move(d2 + delta, s2 + delta, d1 + (d2 - s1)); + } + else + { + pod_move(s1, s2, d1); + } + } + } + else + { + const size_type sz = delta - tailLen; + Storage::append(s2 - sz, sz); + Storage::append(d2, tailLen); + pod_move(s1, s2 - (delta - tailLen), d1); + } + } + else + { + pod_move(s1, s1 + n2, &*begin() + d); + pod_move(&*begin() + d + n1, &*end(), &*begin() + d + n1 + delta); + resize(size() + delta); + } + return *this; + } + + flex_string& replace(size_type pos, size_type n1, const value_type* s) + { return replace(pos, n1, s, traits_type::length(s)); } + + flex_string& replace(size_type pos, size_type n1, size_type n2, + value_type c) + { + if (pos + n1 > size()) n1 = size() - pos; + const size_type oldSize = size(); + if (pos + n2 > oldSize) + { + resize(pos + n2, c); + Storage::append(&*begin() + pos + n1, oldSize - pos - n1); + flex_string_details::pod_fill(&*begin() + pos, + &*begin() + oldSize, c); + } + else + { + if (n2 > n1) + { + const size_type delta = n2 - n1; + Storage::append(&*begin() + oldSize - delta, delta); + flex_string_details::pod_move( + &*begin() + pos + n1, + &*begin() + oldSize - delta, + &*begin() + pos + n2); + } + else + { + flex_string_details::pod_move(&*begin() + pos + n1, &*end(), + &*begin() + pos + n2); + resize(oldSize - (n1 - n2)); + } + flex_string_details::pod_fill(&*begin() + pos, + &*begin() + pos + n2, c); + } + return *this; + } + + flex_string& replace(iterator i1, iterator i2, const flex_string& str) + { return replace(i1, i2, str.c_str(), str.length()); } + + flex_string& replace(iterator i1, iterator i2, + const value_type* s, size_type n) + { return replace(i1 - begin(), i2 - i1, s, n); } + + flex_string& replace(iterator i1, iterator i2, const value_type* s) + { return replace(i1, i2, s, traits_type::length(s)); } + + flex_string& replace(iterator i1, iterator i2, + size_type n, value_type c) + { return replace(i1 - begin(), i2 - i1, n, c); } + +private: + template class Selector {}; + + template struct SameType + { + enum { result = false }; + }; + + template struct SameType + { + enum { result = true }; + }; + + template + flex_string& ReplaceImpl(iterator i1, iterator i2, + ReallyAnIntegral n, ReallyAnIntegral c, Selector<1>) + { + return replace(i1, i2, static_cast(n), + static_cast(c)); + } + + template + flex_string& ReplaceImpl(iterator i1, iterator i2, + InputIterator b, InputIterator e, Selector<0>) + { + BOOST_ASSERT(false); + return *this; + } + +public: + template + flex_string& replace(iterator i1, iterator i2, + InputIterator j1, InputIterator j2) + { + return ReplaceImpl(i1, i2, j1, j2, + Selector::is_specialized>()); + } + + size_type copy(value_type* s, size_type n, size_type pos = 0) const + { + Enforce(pos <= size(), (std::out_of_range*)0, ""); + n = Min(n, size() - pos); + + flex_string_details::pod_copy( + &*begin() + pos, + &*begin() + pos + n, + s); + return n; + } + + void swap(flex_string& rhs) + { + Storage& srhs = rhs; + this->Storage::swap(srhs); + } + + // 21.3.6 string operations: + const value_type* c_str() const + { return Storage::c_str(); } + + const value_type* data() const + { return Storage::data(); } + + allocator_type get_allocator() const + { return Storage::get_allocator(); } + + size_type find(const flex_string& str, size_type pos = 0) const + { return find(str.data(), pos, str.length()); } + + size_type find (const value_type* s, size_type pos, size_type n) const + { + for (; pos <= size(); ++pos) + { + if (traits_type::compare(&*begin() + pos, s, n) == 0) + { + return pos; + } + } + return npos; + } + + size_type find (const value_type* s, size_type pos = 0) const + { return find(s, pos, traits_type::length(s)); } + + size_type find (value_type c, size_type pos = 0) const + { return find(&c, pos, 1); } + + size_type rfind(const flex_string& str, size_type pos = npos) const + { return rfind(str.c_str(), pos, str.length()); } + + size_type rfind(const value_type* s, size_type pos, size_type n) const + { + if (n > length()) return npos; + pos = Min(pos, length() - n); + if (n == 0) return pos; + + const_iterator i(begin() + pos); + for (; ; --i) + { + if (traits_type::eq(*i, *s) + && traits_type::compare(&*i, s, n) == 0) + { + return i - begin(); + } + if (i == begin()) break; + } + return npos; + } + + size_type rfind(const value_type* s, size_type pos = npos) const + { return rfind(s, pos, traits_type::length(s)); } + + size_type rfind(value_type c, size_type pos = npos) const + { return rfind(&c, pos, 1); } + + size_type find_first_of(const flex_string& str, size_type pos = 0) const + { return find_first_of(str.c_str(), pos, str.length()); } + + size_type find_first_of(const value_type* s, + size_type pos, size_type n) const + { + if (pos > length() || n == 0) return npos; + const_iterator i(begin() + pos), + finish(end()); + for (; i != finish; ++i) + { + if (traits_type::find(s, n, *i) != 0) + { + return i - begin(); + } + } + return npos; + } + + size_type find_first_of(const value_type* s, size_type pos = 0) const + { return find_first_of(s, pos, traits_type::length(s)); } + + size_type find_first_of(value_type c, size_type pos = 0) const + { return find_first_of(&c, pos, 1); } + + size_type find_last_of (const flex_string& str, + size_type pos = npos) const + { return find_last_of(str.c_str(), pos, str.length()); } + + size_type find_last_of (const value_type* s, size_type pos, + size_type n) const + { + if (!empty() && n > 0) + { + pos = Min(pos, length() - 1); + const_iterator i(begin() + pos); + for (;; --i) + { + if (traits_type::find(s, n, *i) != 0) + { + return i - begin(); + } + if (i == begin()) break; + } + } + return npos; + } + + size_type find_last_of (const value_type* s, + size_type pos = npos) const + { return find_last_of(s, pos, traits_type::length(s)); } + + size_type find_last_of (value_type c, size_type pos = npos) const + { return find_last_of(&c, pos, 1); } + + size_type find_first_not_of(const flex_string& str, + size_type pos = 0) const + { return find_first_not_of(str.data(), pos, str.size()); } + + size_type find_first_not_of(const value_type* s, size_type pos, + size_type n) const + { + if (pos < length()) + { + const_iterator + i(begin() + pos), + finish(end()); + for (; i != finish; ++i) + { + if (traits_type::find(s, n, *i) == 0) + { + return i - begin(); + } + } + } + return npos; + } + + size_type find_first_not_of(const value_type* s, + size_type pos = 0) const + { return find_first_not_of(s, pos, traits_type::length(s)); } + + size_type find_first_not_of(value_type c, size_type pos = 0) const + { return find_first_not_of(&c, pos, 1); } + + size_type find_last_not_of(const flex_string& str, + size_type pos = npos) const + { return find_last_not_of(str.c_str(), pos, str.length()); } + + size_type find_last_not_of(const value_type* s, size_type pos, + size_type n) const + { + if (!empty()) + { + pos = Min(pos, size() - 1); + const_iterator i(begin() + pos); + for (;; --i) + { + if (traits_type::find(s, n, *i) == 0) + { + return i - begin(); + } + if (i == begin()) break; + } + } + return npos; + } + + size_type find_last_not_of(const value_type* s, + size_type pos = npos) const + { return find_last_not_of(s, pos, traits_type::length(s)); } + + size_type find_last_not_of (value_type c, size_type pos = npos) const + { return find_last_not_of(&c, pos, 1); } + + flex_string substr(size_type pos = 0, size_type n = npos) const + { + Enforce(pos <= size(), (std::out_of_range*)0, ""); + return flex_string(data() + pos, Min(n, size() - pos)); + } + + std::ptrdiff_t compare(const flex_string& str) const + { return compare(0, size(), str.data(), str.length()); } + + std::ptrdiff_t compare(size_type pos1, size_type n1, + const flex_string& str) const + { return compare(pos1, n1, str.data(), str.size()); } + + std::ptrdiff_t compare(size_type pos1, size_type n1, + const value_type* s, size_type n2 = npos) const + { + Enforce(pos1 <= size(), (std::out_of_range*)0, ""); + + n1 = Min(size() - pos1, n1); + const std::ptrdiff_t result = traits_type::compare(data() + pos1, s, Min(n1, n2)); + return (result != 0) ? result : int(n1 - n2); + } + + std::ptrdiff_t compare(size_type pos1, size_type n1, + const flex_string& str, + size_type pos2, size_type n2) const + { + Enforce(pos2 <= str.size(), (std::out_of_range*)0, ""); + return compare(pos1, n1, str.data() + pos2, Min(n2, str.size() - pos2)); + } + + std::ptrdiff_t compare(const value_type* s) const + { return compare(0, size(), s, traits_type::length(s)); } +}; + +// non-member functions +template +flex_string operator+(const flex_string& lhs, + const flex_string& rhs) +{ + flex_string result; + result.reserve(lhs.size() + rhs.size()); + result.append(lhs); + result.append(rhs); + return result; +} + +template +flex_string operator+(const typename flex_string::value_type* lhs, + const flex_string& rhs) +{ + flex_string result; + const typename flex_string::size_type len = + flex_string::traits_type::length(lhs); + result.reserve(len + rhs.size()); + result.append(lhs, len); + result.append(rhs); + return result; +} + +template +flex_string operator+( + typename flex_string::value_type lhs, + const flex_string& rhs) +{ + flex_string result; + result.reserve(1 + rhs.size()); + result.push_back(lhs); + result.append(rhs); + return result; +} + +template +flex_string operator+(const flex_string& lhs, + const typename flex_string::value_type* rhs) +{ + typedef typename flex_string::size_type size_type; + typedef typename flex_string::traits_type traits_type; + + flex_string result; + const size_type len = traits_type::length(rhs); + result.reserve(lhs.size() + len); + result.append(lhs); + result.append(rhs, len); + return result; +} + +template +flex_string operator+(const flex_string& lhs, + typename flex_string::value_type rhs) +{ + flex_string result; + result.reserve(lhs.size() + 1); + result.append(lhs); + result.push_back(rhs); + return result; +} + +template +bool operator==(const flex_string& lhs, + const flex_string& rhs) +{ return lhs.compare(rhs) == 0; } + +template +bool operator==(const typename flex_string::value_type* lhs, + const flex_string& rhs) +{ return rhs == lhs; } + +template +bool operator==(const flex_string& lhs, + const typename flex_string::value_type* rhs) +{ return lhs.compare(rhs) == 0; } + +template +bool operator!=(const flex_string& lhs, + const flex_string& rhs) +{ return !(lhs == rhs); } + +template +bool operator!=(const typename flex_string::value_type* lhs, + const flex_string& rhs) +{ return !(lhs == rhs); } + +template +bool operator!=(const flex_string& lhs, + const typename flex_string::value_type* rhs) +{ return !(lhs == rhs); } + +template +bool operator<(const flex_string& lhs, + const flex_string& rhs) +{ return lhs.compare(rhs) < 0; } + +template +bool operator<(const flex_string& lhs, + const typename flex_string::value_type* rhs) +{ return lhs.compare(rhs) < 0; } + +template +bool operator<(const typename flex_string::value_type* lhs, + const flex_string& rhs) +{ return rhs.compare(lhs) > 0; } + +template +bool operator>(const flex_string& lhs, + const flex_string& rhs) +{ return rhs < lhs; } + +template +bool operator>(const flex_string& lhs, + const typename flex_string::value_type* rhs) +{ return rhs < lhs; } + +template +bool operator>(const typename flex_string::value_type* lhs, + const flex_string& rhs) +{ return rhs < lhs; } + +template +bool operator<=(const flex_string& lhs, + const flex_string& rhs) +{ return !(rhs < lhs); } + +template +bool operator<=(const flex_string& lhs, + const typename flex_string::value_type* rhs) +{ return !(rhs < lhs); } + +template +bool operator<=(const typename flex_string::value_type* lhs, + const flex_string& rhs) +{ return !(rhs < lhs); } + +template +bool operator>=(const flex_string& lhs, + const flex_string& rhs) +{ return !(lhs < rhs); } + +template +bool operator>=(const flex_string& lhs, + const typename flex_string::value_type* rhs) +{ return !(lhs < rhs); } + +template +bool operator>=(const typename flex_string::value_type* lhs, + const flex_string& rhs) +{ return !(lhs < rhs); } + +// subclause 21.3.7.8: +//void swap(flex_string& lhs, flex_string& rhs); // to do + +template +std::basic_istream::value_type, + typename flex_string::traits_type>& +operator>>( + std::basic_istream::value_type, + typename flex_string::traits_type>& is, + flex_string& str); + +template +std::basic_ostream::value_type, + typename flex_string::traits_type>& +operator<<( + std::basic_ostream::value_type, + typename flex_string::traits_type>& os, + const flex_string& str) +{ return os << str.c_str(); } + +template +std::basic_istream::value_type, + typename flex_string::traits_type>& +getline( + std::basic_istream::value_type, + typename flex_string::traits_type>& is, + flex_string& str, + typename flex_string::value_type delim); + +template +std::basic_istream::value_type, + typename flex_string::traits_type>& +getline( + std::basic_istream::value_type, + typename flex_string::traits_type>& is, + flex_string& str); + +template +const typename flex_string::size_type +flex_string::npos = (typename flex_string::size_type)(-1); + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // FLEX_STRING_INC_ diff --git a/include/boost/wave/util/functor_input.hpp b/include/boost/wave/util/functor_input.hpp new file mode 100644 index 000000000..3c2b85c10 --- /dev/null +++ b/include/boost/wave/util/functor_input.hpp @@ -0,0 +1,133 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(FUNCTOR_INPUT_HPP_ED3A4C21_8F8A_453F_B438_08214FAC106A_INCLUDED) +#define FUNCTOR_INPUT_HPP_ED3A4C21_8F8A_453F_B438_08214FAC106A_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// +// class functor_input +// +// Implementation of the InputPolicy used by multi_pass +// functor_input gets tokens from a functor +// Note: the functor must have a typedef for result_type +// It also must have a static variable of type result_type defined +// to represent eof that is called eof. +// +// This functor input policy template is essentially the same as the +// predefined multi_pass functor_input policy. The difference is, +// that the first token is not read at initialization time, but only +// just before returning the first token. +// +/////////////////////////////////////////////////////////////////////////////// +struct functor_input { + + template + class inner { + + typedef typename FunctorT::result_type result_type; + + struct Data { + Data(FunctorT const &ftor_) + : ftor(ftor_), was_initialized(false) + {} + + FunctorT ftor; + result_type curtok; + bool was_initialized; + }; + + public: + typedef result_type value_type; + typedef std::ptrdiff_t difference_type; + typedef result_type *pointer; + typedef result_type &reference; + + protected: + inner() + : data(0) + {} + + inner(FunctorT const &x) + : data(new Data(x)) + {} + + inner(inner const &x) + : data(x.data) + {} + + void destroy() + { + delete data; + data = 0; + } + + bool same_input(inner const &x) const + { + return data == x.data; + } + + void swap(inner &x) + { + boost::spirit::impl::mp_swap(data, x.data); + } + + void ensure_initialized() const + { + if (data && !data->was_initialized) { + data->curtok = (data->ftor)(); // get the first token + data->was_initialized = true; + } + } + + public: + reference get_input() const + { + ensure_initialized(); + return data->curtok; + } + + void advance_input() + { + BOOST_SPIRIT_ASSERT(0 != data); + data->curtok = (data->ftor)(); + data->was_initialized = true; + } + + bool input_at_eof() const + { + ensure_initialized(); + return !data || data->curtok == data->ftor.eof; + } + + FunctorT& get_functor() const + { + BOOST_SPIRIT_ASSERT(0 != data); + return data->ftor; + } + + private: + mutable Data *data; + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(FUNCTOR_INPUT_HPP_ED3A4C21_8F8A_453F_B438_08214FAC106A_INCLUDED) diff --git a/include/boost/wave/util/insert_whitespace_detection.hpp b/include/boost/wave/util/insert_whitespace_detection.hpp new file mode 100644 index 000000000..cf2a2e684 --- /dev/null +++ b/include/boost/wave/util/insert_whitespace_detection.hpp @@ -0,0 +1,330 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Detect the need to insert a whitespace token into the output stream + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ +#if !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED) +#define INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +namespace impl { + +// T_IDENTIFIER + template + inline bool + would_form_universal_char (StringT const &value) + { + if ('u' != value[0] && 'U' != value[0]) + return false; + if ('u' == value[0] && value.size() < 5) + return false; + if ('U' == value[0] && value.size() < 9) + return false; + + typename StringT::size_type pos = + value.find_first_not_of("0123456789abcdefABCDEF", 1); + + if (StringT::npos == pos || + ('u' == value[0] && pos > 5) || + ('U' == value[0] && pos > 9)) + { + return true; // would form an universal char + } + return false; + } + template + inline bool + handle_identifier(boost::wave::token_id prev, + boost::wave::token_id before, StringT const &value) + { + using namespace boost::wave; + switch (static_cast(prev)) { + case T_IDENTIFIER: + case T_NONREPLACABLE_IDENTIFIER: + case T_INTLIT: + case T_FLOATLIT: + case T_COMPL_ALT: + case T_OR_ALT: + case T_AND_ALT: + case T_NOT_ALT: + case T_XOR_ALT: + case T_ANDASSIGN_ALT: + case T_ORASSIGN_ALT: + case T_XORASSIGN_ALT: + case T_NOTEQUAL_ALT: + case T_FIXEDPOINTLIT: + return true; + + // avoid constructing universal characters (\u1234) + case TOKEN_FROM_ID('\\', UnknownTokenType): + return would_form_universal_char(value); + } + return false; + } +// T_INTLIT + inline bool + handle_intlit(boost::wave::token_id prev, boost::wave::token_id before) + { + using namespace boost::wave; + switch(prev) { + case T_IDENTIFIER: + case T_NONREPLACABLE_IDENTIFIER: + case T_INTLIT: + case T_FLOATLIT: + case T_FIXEDPOINTLIT: + return true; + } + return false; + } +// T_FLOATLIT + inline bool + handle_floatlit(boost::wave::token_id prev, + boost::wave::token_id before) + { + using namespace boost::wave; + switch(prev) { + case T_IDENTIFIER: + case T_NONREPLACABLE_IDENTIFIER: + case T_INTLIT: + case T_FLOATLIT: + case T_FIXEDPOINTLIT: + return true; + } + return false; + } +// <% T_LEFTBRACE + inline bool + handle_alt_leftbrace(boost::wave::token_id prev, + boost::wave::token_id before) + { + using namespace boost::wave; + switch(prev) { + case T_LESS: // <<% + case T_SHIFTLEFT: // <<<% + return true; + } + return false; + } +// <: T_LEFTBRACKET + inline bool + handle_alt_leftbracket(boost::wave::token_id prev, + boost::wave::token_id before) + { + using namespace boost::wave; + switch(prev) { + case T_LESS: // <<: + case T_SHIFTLEFT: // <<<: + return true; + } + return false; + } +// T_FIXEDPOINTLIT + inline bool + handle_fixedpointlit(boost::wave::token_id prev, + boost::wave::token_id before) + { + using namespace boost::wave; + switch(prev) { + case T_IDENTIFIER: + case T_NONREPLACABLE_IDENTIFIER: + case T_INTLIT: + case T_FLOATLIT: + case T_FIXEDPOINTLIT: + return true; + } + return false; + } +// T_DOT + inline bool + handle_dot(boost::wave::token_id prev, boost::wave::token_id before) + { + using namespace boost::wave; + switch(prev) { + case T_DOT: + if (T_DOT == before) + return true; // ... + break; + } + return false; + } +// T_QUESTION_MARK + inline bool + handle_questionmark(boost::wave::token_id prev, + boost::wave::token_id before) + { + using namespace boost::wave; + switch(static_cast(prev)) { + case TOKEN_FROM_ID('\\', UnknownTokenType): // \? + case T_QUESTION_MARK: // ?? + return true; + } + return false; + } +// T_NEWLINE + inline bool + handle_newline(boost::wave::token_id prev, + boost::wave::token_id before) + { + using namespace boost::wave; + switch(static_cast(prev)) { + case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n + case T_DIVIDE: + if (T_QUESTION_MARK == before) + return true; // ?/\n // may be \\n + break; + } + return false; + } + +} // namespace impl + +class insert_whitespace_detection +{ +public: + insert_whitespace_detection() + : prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF) + {} + + template + bool must_insert(boost::wave::token_id current, StringT const &value) + { + using namespace boost::wave; + switch (current) { + case T_NONREPLACABLE_IDENTIFIER: + case T_IDENTIFIER: + return impl::handle_identifier(prev, beforeprev, value); + case T_INTLIT: + return impl::handle_intlit(prev, beforeprev); + case T_FLOATLIT: + return impl::handle_floatlit(prev, beforeprev); + case T_STRINGLIT: + if (TOKEN_FROM_ID('L', UnknownTokenType) == prev) // 'L' + return true; + break; + case T_LEFTBRACE_ALT: + return impl::handle_alt_leftbrace(prev, beforeprev); + case T_LEFTBRACKET_ALT: + return impl::handle_alt_leftbracket(prev, beforeprev); + case T_FIXEDPOINTLIT: + return impl::handle_fixedpointlit(prev, beforeprev); + case T_DOT: + return impl::handle_dot(prev, beforeprev); + case T_QUESTION_MARK: + return impl::handle_questionmark(prev, beforeprev); + case T_NEWLINE: + return impl::handle_newline(prev, beforeprev); + + case T_LEFTPAREN: + case T_RIGHTPAREN: + case T_LEFTBRACKET: + case T_RIGHTBRACKET: + case T_SEMICOLON: + case T_COMMA: + case T_COLON: + switch (prev) { + case T_LEFTPAREN: + case T_RIGHTPAREN: + case T_LEFTBRACKET: + case T_RIGHTBRACKET: + case T_LEFTBRACE: + case T_RIGHTBRACE: + return false; // no insertion between parens/brackets/braces + + default: + break; + } + break; + + case T_LEFTBRACE: + case T_RIGHTBRACE: + switch (prev) { + case T_LEFTPAREN: + case T_RIGHTPAREN: + case T_LEFTBRACKET: + case T_RIGHTBRACKET: + case T_LEFTBRACE: + case T_RIGHTBRACE: + case T_SEMICOLON: + case T_COMMA: + case T_COLON: + return false; // no insertion between parens/brackets/braces + + case T_QUESTION_MARK: + if (T_QUESTION_MARK == beforeprev) + return true; + break; + + default: + break; + } + break; + + case T_MINUS: + case T_MINUSMINUS: + case T_LESS: + case T_EQUAL: + case T_ASSIGN: + case T_GREATER: + case T_DIVIDE: + case T_CHARLIT: + case T_NOT: + case T_NOTEQUAL: + case T_DIVIDEASSIGN: + case T_MINUSASSIGN: + if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) + return true; // ??{op} + break; + + case T_COMPL_ALT: + case T_OR_ALT: + case T_AND_ALT: + case T_NOT_ALT: + case T_XOR_ALT: + case T_ANDASSIGN_ALT: + case T_ORASSIGN_ALT: + case T_XORASSIGN_ALT: + case T_NOTEQUAL_ALT: + if (T_IDENTIFIER == prev || T_NONREPLACABLE_IDENTIFIER == prev || + IS_CATEGORY(prev, KeywordTokenType)) + return true; + break; + } + + // else, handle operators separately + if (IS_CATEGORY(current, OperatorTokenType) && + IS_CATEGORY(prev, OperatorTokenType)) + { + return true; // operators must be delimited always + } + return false; + } + void shift_tokens (boost::wave::token_id next_id) + { + beforeprev = prev; + prev = next_id; + } + +private: + boost::wave::token_id prev; // the previous analyzed token + boost::wave::token_id beforeprev; // the token before the previous +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED) diff --git a/include/boost/wave/util/interpret_pragma.hpp b/include/boost/wave/util/interpret_pragma.hpp new file mode 100644 index 000000000..8906539e0 --- /dev/null +++ b/include/boost/wave/util/interpret_pragma.hpp @@ -0,0 +1,135 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED) +#define INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED + +#include +#include + +#include +#if SPIRIT_VERSION >= 0x1700 +#include +#include +#endif // SPIRIT_VERSION >= 0x1700 + +#include + +#include +#include + +#include +#include +#include +#include + +#if !defined(spirit_append_actor) +#if SPIRIT_VERSION >= 0x1700 +#define spirit_append_actor(actor) boost::spirit::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::assign_a(actor) +#else +#define spirit_append_actor(actor) boost::spirit::append(actor) +#define spirit_assign_actor(actor) boost::spirit::assign(actor) +#endif // SPIRIT_VERSION >= 0x1700 +#endif // !defined(spirit_append_actor) + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// +// The function interpret_pragma interprets the given token sequence as the +// body of a #pragma directive (or parameter to the _Pragma operator) and +// executes the actions associated with recognized Wave specific options. +// +/////////////////////////////////////////////////////////////////////////////// +template +inline bool +interpret_pragma(ContextT &ctx, typename ContextT::token_type const &act_token, + IteratorT it, IteratorT const &end, ContainerT &pending) +{ + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + + using namespace cpplexer; + if (T_IDENTIFIER == token_id(*it) && "wave" == (*it).get_value()) { + // this is a wave specific option, it should have the form: + // #pragma wave option(value) + // where '(value)' is required only for some pragma directives + // all of the given #pragma operators are forwarded to the supplied + // context_policy + using namespace boost::spirit; + token_type option; + ContainerT values; + + if (!parse (++it, end, + ( ch_p(T_IDENTIFIER) + [spirit_assign_actor(option)] + | pattern_p(KeywordTokenType, TokenTypeMask) + [spirit_assign_actor(option)] + ) + >> !( ch_p(T_LEFTPAREN) + >> lexeme_d[ + *(anychar_p[spirit_append_actor(values)] - ch_p(T_RIGHTPAREN)) + ] + >> ch_p(T_RIGHTPAREN) + ), + pattern_p(WhiteSpaceTokenType, TokenTypeMask)).hit) + { + return false; + } + + // remove the falsely matched closing parenthesis + if (values.size() > 0) { + if (T_RIGHTPAREN == values.back()) { + typename ContainerT::reverse_iterator rit = values.rbegin(); + + values.erase((++rit).base()); + } + else { + BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, + "missing matching ')'", act_token.get_position()); + } + } + + // decode the option (call the context_policy hook) + if (!ctx.interpret_pragma(pending, option, values, act_token)) + { + // unknown #pragma option + string_type option_str (option.get_value()); + + if (values.size() > 0) { + option_str += "("; + option_str += impl::as_string(values); + option_str += ")"; + } + BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, + option_str, act_token.get_position()); + } + return true; + } +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + else if (T_IDENTIFIER == token_id(*it) && "once" == (*it).get_value()) { + // #pragma once + return ctx.add_pragma_once_header(ctx.get_current_filename()); + } +#endif + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED) diff --git a/include/boost/wave/util/iteration_context.hpp b/include/boost/wave/util/iteration_context.hpp new file mode 100644 index 000000000..b2365e125 --- /dev/null +++ b/include/boost/wave/util/iteration_context.hpp @@ -0,0 +1,71 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(ITERATION_CONTEXT_HPP_9556CD16_F11E_4ADC_AC8B_FB9A174BE664_INCLUDED) +#define ITERATION_CONTEXT_HPP_9556CD16_F11E_4ADC_AC8B_FB9A174BE664_INCLUDED + +#include +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +template +class iteration_context_stack +{ + typedef std::stack base_t; + +public: + typedef typename base_t::size_type size_type; + + iteration_context_stack() + : max_include_nesting_depth(BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH) + {} + + void set_max_include_nesting_depth(size_type new_depth) + { max_include_nesting_depth = new_depth; } + size_type get_max_include_nesting_depth() const + { return max_include_nesting_depth; } + + typename base_t::size_type size() const { return iter_ctx.size(); } + typename base_t::value_type &top() { return iter_ctx.top(); } + void pop() { iter_ctx.pop(); } + + template + void push(PositionT const &pos, typename base_t::value_type const &val) + { + if (iter_ctx.size() == max_include_nesting_depth) { + char buffer[22]; // 21 bytes holds all NUL-terminated unsigned 64-bit numbers + + using namespace std; // for some systems ltoa is in namespace std + sprintf(buffer, "%d", max_include_nesting_depth); + BOOST_WAVE_THROW(preprocess_exception, include_nesting_too_deep, buffer, + pos); + } + iter_ctx.push(val); + } + +private: + size_type max_include_nesting_depth; + base_t iter_ctx; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(ITERATION_CONTEXT_HPP_9556CD16_F11E_4ADC_AC8B_FB9A174BE664_INCLUDED) diff --git a/include/boost/wave/util/macro_definition.hpp b/include/boost/wave/util/macro_definition.hpp new file mode 100644 index 000000000..3736ad909 --- /dev/null +++ b/include/boost/wave/util/macro_definition.hpp @@ -0,0 +1,126 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED) +#define MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED + +#include +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// +// macro_definition +// +// This class containes all infos for a defined macro. +// +/////////////////////////////////////////////////////////////////////////////// +template +struct macro_definition { + + typedef std::vector parameter_container_t; + typedef ContainerT definition_container_t; + + typedef typename parameter_container_t::const_iterator + const_parameter_iterator_t; + typedef typename definition_container_t::const_iterator + const_definition_iterator_t; + + macro_definition(TokenT const &token_, bool has_parameters, + bool is_predefined_, long uid_) + : macroname(token_), uid(uid_), is_functionlike(has_parameters), + replaced_parameters(false), is_available_for_replacement(true), + is_predefined(is_predefined_) +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + , has_ellipsis(false) +#endif + { + } + // generated copy constructor + // generated destructor + // generated assignment operator + + // Replace all occurrences of the parameters throughout the macrodefinition + // with special parameter tokens to simplify later macro replacement. + // Additionally mark all occurrences of the macro name itself throughout + // the macro definition + void replace_parameters() + { + using namespace boost::wave; + + if (!replaced_parameters) { + typename definition_container_t::iterator end = macrodefinition.end(); + typename definition_container_t::iterator it = macrodefinition.begin(); + + for (/**/; it != end; ++it) { + if (T_IDENTIFIER == token_id(*it) || + IS_CATEGORY(token_id(*it), KeywordTokenType)) + { + // may be a parameter to replace + const_parameter_iterator_t cend = macroparameters.end(); + const_parameter_iterator_t cit = macroparameters.begin(); + for (typename parameter_container_t::size_type i = 0; + cit != cend; ++cit, ++i) + { + if ((*it).get_value() == (*cit).get_value()) { + (*it).set_token_id(token_id(T_PARAMETERBASE+i)); + break; + } +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + else if (T_ELLIPSIS == token_id(*cit) && + "__VA_ARGS__" == (*it).get_value()) + { + // __VA_ARGS__ requires special handling + (*it).set_token_id(token_id(T_EXTPARAMETERBASE+i)); + break; + } +#endif + } + } + } + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + // we need to know, if the last of the formal arguments is an ellipsis + if (macroparameters.size() > 0 && + T_ELLIPSIS == token_id(macroparameters.back())) + { + has_ellipsis = true; + } +#endif + replaced_parameters = true; // do it only once + } + } + + TokenT macroname; // macro name + parameter_container_t macroparameters; // formal parameters + definition_container_t macrodefinition; // macro definition token sequence + long uid; // unique id of this macro + bool is_functionlike; + bool replaced_parameters; + bool is_available_for_replacement; + bool is_predefined; +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + bool has_ellipsis; +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED) diff --git a/include/boost/wave/util/macro_helpers.hpp b/include/boost/wave/util/macro_helpers.hpp new file mode 100644 index 000000000..e98badf74 --- /dev/null +++ b/include/boost/wave/util/macro_helpers.hpp @@ -0,0 +1,241 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED) +#define MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +namespace impl { + + // escape a string literal (insert '\\' before every '\"', '?' and '\\') + template + inline StringT + escape_lit(StringT const &value) + { + StringT result; + typename StringT::size_type pos = 0; + typename StringT::size_type pos1 = value.find_first_of ("\"\\?", 0); + if (StringT::npos != pos1) { + do { + result += value.substr(pos, pos1-pos) + + StringT("\\") + + StringT(1, value[pos1]); + pos1 = value.find_first_of ("\"\\?", pos = pos1+1); + } while (StringT::npos != pos1); + result += value.substr(pos); + } + else { + result = value; + } + return result; + } + + // un-escape a string literal (remove '\\' just before '\\', '\"' or '?') + template + inline StringT + unescape_lit(StringT const &value) + { + StringT result; + typename StringT::size_type pos = 0; + typename StringT::size_type pos1 = value.find_first_of ("\\", 0); + if (StringT::npos != pos1) { + do { + if ('\\' == value[pos1+1] || '\"' == value[pos1+1] || + '?' == value[pos1+1]) + { + result += value.substr(pos, pos1-pos); + } + pos1 = value.find_first_of ("\\", pos = pos1+1); + } while (pos1 != StringT::npos); + result += value.substr(pos); + } + else { + // the string doesn't contain any escaped character sequences + result = value; + } + return result; + } + + // return the string representation of a token sequence + template + inline typename ContainerT::value_type::string_type + as_stringlit (ContainerT const &token_sequence, PositionT const &pos) + { + using namespace boost::wave; + typedef typename ContainerT::value_type::string_type string_type; + + string_type result("\""); + bool was_whitespace = false; + typename ContainerT::const_iterator end = token_sequence.end(); + for (typename ContainerT::const_iterator it = token_sequence.begin(); + it != end; ++it) + { + token_id id = token_id(*it); + + if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) { + if (!was_whitespace) { + // C++ standard 16.3.2.2 [cpp.stringize] + // Each occurrence of white space between the argument’s + // preprocessing tokens becomes a single space character in the + // character string literal. + result += " "; + was_whitespace = true; + } + } + else if (T_STRINGLIT == id || T_CHARLIT == id) { + // string literals and character literals have to be escaped + result += impl::escape_lit((*it).get_value()); + was_whitespace = false; + } + else +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (T_PLACEMARKER != id) +#endif + { + // now append this token to the string + result += (*it).get_value(); + was_whitespace = false; + } + } + result += "\""; + + // validate the resulting literal to contain no invalid universal character + // value (throws if invalid chars found) + boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(), + pos.get_column(), pos.get_file()); + return result; + } + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + // return the string representation of a token sequence + template + inline typename ContainerT::value_type::string_type + as_stringlit (std::vector const &arguments, + typename std::vector::size_type i, PositionT const &pos) + { + using namespace boost::wave; + typedef typename ContainerT::value_type::string_type string_type; + + BOOST_SPIRIT_ASSERT(0 <= i && i < arguments.size()); + + string_type result("\""); + bool was_whitespace = false; + + for (/**/; i < arguments.size(); ++i) { + // stringize all remaining arguments + typename ContainerT::const_iterator end = arguments[i].end(); + for (typename ContainerT::const_iterator it = arguments[i].begin(); + it != end; ++it) + { + token_id id = token_id(*it); + + if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) { + if (!was_whitespace) { + // C++ standard 16.3.2.2 [cpp.stringize] + // Each occurrence of white space between the argument’s + // preprocessing tokens becomes a single space character in the + // character string literal. + result += " "; + was_whitespace = true; + } + } + else if (T_STRINGLIT == id || T_CHARLIT == id) { + // string literals and character literals have to be escaped + result += impl::escape_lit((*it).get_value()); + was_whitespace = false; + } + else if (T_PLACEMARKER != id) { + // now append this token to the string + result += (*it).get_value(); + was_whitespace = false; + } + } + + // append comma, if not last argument + if (i < arguments.size()-1) { + result += ","; + was_whitespace = false; + } + } + result += "\""; + + // validate the resulting literal to contain no invalid universal character + // value (throws if invalid chars found) + boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(), + pos.get_column(), pos.get_file()); + return result; + } +#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + + // return the string representation of a token sequence + template + inline StringT + as_string(IteratorT it, IteratorT end) + { + StringT result; + for (/**/; it != end; ++it) + { + result += (*it).get_value(); + } + return result; + } + + // return the string representation of a token sequence + template + inline typename ContainerT::value_type::string_type + as_string (ContainerT const &token_sequence) + { + typedef typename ContainerT::value_type::string_type string_type; + return as_string(token_sequence.begin(), token_sequence.end()); + } + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + /////////////////////////////////////////////////////////////////////////// + // + // Copies all arguments beginning with the given index to the output + // sequence. The arguments are separated by commas. + // + template + void replace_ellipsis (std::vector const &arguments, + typename ContainerT::size_type index, + ContainerT &expanded, PositionT const &pos) + { + using namespace cpplexer; + typedef typename ContainerT::value_type token_type; + + token_type comma(T_COMMA, ",", pos); + for (/**/; index < arguments.size(); ++index) { + ContainerT const &arg = arguments[index]; + + std::copy(arg.begin(), arg.end(), + std::inserter(expanded, expanded.end())); + + if (index < arguments.size()-1) + expanded.push_back(comma); + } + } +#endif + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED) diff --git a/include/boost/wave/util/pattern_parser.hpp b/include/boost/wave/util/pattern_parser.hpp new file mode 100644 index 000000000..e7c5204be --- /dev/null +++ b/include/boost/wave/util/pattern_parser.hpp @@ -0,0 +1,55 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Global application configuration + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(BOOST_SPIRIT_PATTERN_PARSER_HPP) +#define BOOST_SPIRIT_PATTERN_PARSER_HPP + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + + /////////////////////////////////////////////////////////////////////////// + // + // pattern_and class + // + /////////////////////////////////////////////////////////////////////////// + template + struct pattern_and : public boost::spirit::char_parser > + { + pattern_and(CharT pattern_, unsigned long pattern_mask_ = 0UL) + : pattern(pattern_), + pattern_mask((0UL != pattern_mask_) ? pattern_mask_ : pattern_) + {} + + template + bool test(T pattern_) const + { return (pattern_ & pattern_mask) == pattern; } + + CharT pattern; + unsigned long pattern_mask; + }; + + template + inline pattern_and + pattern_p(CharT pattern, unsigned long pattern_mask = 0UL) + { return pattern_and(pattern, pattern_mask); } + + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // defined(BOOST_SPIRIT_PATTERN_PARSER_HPP) diff --git a/include/boost/wave/util/symbol_table.hpp b/include/boost/wave/util/symbol_table.hpp new file mode 100644 index 000000000..2830efa92 --- /dev/null +++ b/include/boost/wave/util/symbol_table.hpp @@ -0,0 +1,40 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED) +#define SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// +// The symbol_table class is used for the storage of defined macros. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct symbol_table +: public std::map > +{ + symbol_table(long uid_) + {} +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED) diff --git a/include/boost/wave/util/time_conversion_helper.hpp b/include/boost/wave/util/time_conversion_helper.hpp new file mode 100644 index 000000000..d3f1898cf --- /dev/null +++ b/include/boost/wave/util/time_conversion_helper.hpp @@ -0,0 +1,145 @@ + /*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(TIME_CONVERSION_HELPER_HPP_DA97E389_1797_43BA_82AE_B071064B3EF4_INCLUDED) +#define TIME_CONVERSION_HELPER_HPP_DA97E389_1797_43BA_82AE_B071064B3EF4_INCLUDED + +#include +#include +#include +#if SPIRIT_VERSION >= 0x1700 +#include +#include +#endif // SPIRIT_VERSION >= 0x1700 + +#if !defined(spirit_append_actor) +#if SPIRIT_VERSION >= 0x1700 +#define spirit_append_actor(actor) boost::spirit::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::assign_a(actor) +#else +#define spirit_append_actor(actor) boost::spirit::append(actor) +#define spirit_assign_actor(actor) boost::spirit::assign(actor) +#endif // SPIRIT_VERSION >= 0x1700 +#endif // !defined(spirit_append_actor) + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +namespace time_conversion { + + using namespace std; // some systems have std::tm etc. in namespace std + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CPP_TIME_CONVERSION \ + (BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// Grammar for parsing a date/time string generated by the C++ compiler from +// __DATE__ and __TIME__ + class time_conversion_grammar : + public boost::spirit::grammar + { + public: + time_conversion_grammar() : fYearIsCorrected(false) + { + memset (&time_stamp, 0, sizeof(tm)); + BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME(*this, "time_conversion_grammar", + TRACE_CPP_TIME_CONVERSION); + } + + template + struct definition { + + definition(time_conversion_grammar const &self) + { + using boost::spirit::int_p; + using boost::spirit::add; + + char const *m[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + for (int i = 0; i < 12; ++i) + add (month, m[i], i); + + time_rule // expected format is 'Dec 29 2001 11:23:59' + = month[spirit_assign_actor(self.time_stamp.tm_mon)] + >> int_p[spirit_assign_actor(self.time_stamp.tm_mday)] + >> int_p[spirit_assign_actor(self.time_stamp.tm_year)] + >> int_p[spirit_assign_actor(self.time_stamp.tm_hour)] + >> int_p[spirit_assign_actor(self.time_stamp.tm_min)] + >> int_p[spirit_assign_actor(self.time_stamp.tm_sec)] + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(time_rule, TRACE_CPP_TIME_CONVERSION); + } + + boost::spirit::rule time_rule; + boost::spirit::symbols<> month; + + boost::spirit::rule const& + start() const { return time_rule; } + }; + + void correct_year() + { + if (!fYearIsCorrected) { + time_stamp.tm_year -= 1900; + fYearIsCorrected = true; + } + } + + mutable tm time_stamp; + bool fYearIsCorrected; + }; + +/////////////////////////////////////////////////////////////////////////////// +// calculate the time of the compilation as a std::time_t to ensure correctness +// of the saved dfa table + class time_conversion_helper + { + public: + time_conversion_helper(char const *act_time) : compile_time(0) + { + using namespace boost::spirit; + + time_conversion_grammar g; + + if (parse (act_time, g, space_p | ch_p(':')).full) { + g.correct_year(); + compile_time = mktime(&g.time_stamp); + } + BOOST_ASSERT(0 != compile_time); + } + + time_t get_time() const { return compile_time; } + + private: + time_t compile_time; + }; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_CPP_TIME_CONVERSION +} // namespace time_conversion + +// import time_conversion into the boost::wave::util namespace +using namespace time_conversion; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(TIME_CONVERSION_HELPER_HPP_DA97E389_1797_43BA_82AE_B071064B3EF4_INCLUDED) diff --git a/include/boost/wave/util/transform_iterator.hpp b/include/boost/wave/util/transform_iterator.hpp new file mode 100644 index 000000000..5d5b66219 --- /dev/null +++ b/include/boost/wave/util/transform_iterator.hpp @@ -0,0 +1,158 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(TRANSFORM_ITERATOR_HPP_D492C659_88C7_4258_8C42_192F9AE80EC0_INCLUDED) +#define TRANSFORM_ITERATOR_HPP_D492C659_88C7_4258_8C42_192F9AE80EC0_INCLUDED + +#include +#if BOOST_ITERATOR_ADAPTORS_VERSION >= 0x0200 +#include +#endif // BOOST_ITERATOR_ADAPTORS_VERSION >= 0x0200 + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace impl { + +#if BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + +/////////////////////////////////////////////////////////////////////////////// +// +// Transform Iterator Adaptor +// +// Upon deference, apply some unary function object and return the +// result by reference. +// +// This class is adapted from the Boost.Iterator library, where a similar +// class exists, which returns the next item by value +// +/////////////////////////////////////////////////////////////////////////////// + template + struct ref_transform_iterator_policies + : public boost::default_iterator_policies + { + ref_transform_iterator_policies() + {} + ref_transform_iterator_policies(const AdaptableUnaryFunctionT &f) + : m_f(f) {} + + template + typename IteratorAdaptorT::reference + dereference(const IteratorAdaptorT &iter) const + { return m_f(*iter.base()); } + + AdaptableUnaryFunctionT m_f; + }; + + template + class ref_transform_iterator_generator + { + typedef typename AdaptableUnaryFunctionT::result_type value_type; + + public: + typedef boost::iterator_adaptor< + IteratorT, + ref_transform_iterator_policies, + value_type, value_type const &, value_type const *, + std::input_iterator_tag> + type; + }; + + template + inline + typename ref_transform_iterator_generator< + AdaptableUnaryFunctionT, IteratorT>::type + make_ref_transform_iterator( + IteratorT base, + const AdaptableUnaryFunctionT &f = AdaptableUnaryFunctionT()) + { + typedef typename ref_transform_iterator_generator< + AdaptableUnaryFunctionT, IteratorT>::type + result_t; + return result_t(base, f); + } + + // Retrieve the token value given a parse node + // This is used in conjunction with the ref_transform_iterator above, to + // get the token values while iterating directly over the parse tree. + template + struct get_token_value { + + typedef TokenT result_type; + + TokenT const &operator()(ParseTreeNodeT const &node) const + { + BOOST_ASSERT(1 == std::distance(node.value.begin(), + node.value.end())); + return *node.value.begin(); + } + }; + +#else // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + +/////////////////////////////////////////////////////////////////////////////// +// +// The new Boost.Iterator library already conatins a transform_iterator usable +// for our needs. The code below wraps this up. +// +/////////////////////////////////////////////////////////////////////////////// + template + class ref_transform_iterator_generator + { + typedef typename AdaptableUnaryFunctionT::result_type return_type; + typedef typename AdaptableUnaryFunctionT::argument_type argument_type; + + public: + typedef boost::transform_iterator< + return_type (*)(argument_type), IteratorT, return_type> + type; + }; + + template + inline + typename ref_transform_iterator_generator< + AdaptableUnaryFunctionT, IteratorT>::type + make_ref_transform_iterator( + IteratorT base, AdaptableUnaryFunctionT const &f) + { + typedef typename ref_transform_iterator_generator< + AdaptableUnaryFunctionT, IteratorT>::type + iterator_type; + return iterator_type(base, f.transform); + } + + // Retrieve the token value given a parse node + // This is used in conjunction with the ref_transform_iterator above, to + // get the token values while iterating directly over the parse tree. + template + struct get_token_value { + + typedef TokenT const &result_type; + typedef ParseTreeNodeT const &argument_type; + + static result_type + transform (argument_type node) + { + BOOST_ASSERT(1 == std::distance(node.value.begin(), + node.value.end())); + return *node.value.begin(); + } + }; + +#endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl +} // namespace wave +} // namespace boost + +#endif // !defined(TRANSFORM_ITERATOR_HPP_D492C659_88C7_4258_8C42_192F9AE80EC0_INCLUDED) diff --git a/include/boost/wave/util/unput_queue_iterator.hpp b/include/boost/wave/util/unput_queue_iterator.hpp new file mode 100644 index 000000000..71eb8c770 --- /dev/null +++ b/include/boost/wave/util/unput_queue_iterator.hpp @@ -0,0 +1,455 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the unput queue iterator + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ +#if !defined(UNPUT_QUEUE_ITERATOR_HPP_76DA23D0_4893_4AD5_ABCC_6CED7CFB89BC_INCLUDED) +#define UNPUT_QUEUE_ITERATOR_HPP_76DA23D0_4893_4AD5_ABCC_6CED7CFB89BC_INCLUDED + +#include + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +#if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \ + BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + +template +class unput_queue_policies : public boost::default_iterator_policies +{ +public: + unput_queue_policies(ContainerT &unput_queue_) + : unput_queue(unput_queue_) + {} + + unput_queue_policies &operator= (unput_queue_policies const &rhs) + { + unput_queue = rhs.unput_queue; + return *this; + } + + template + void initialize(BaseT &) + {} + + template + typename IteratorAdaptorT::reference + dereference(const IteratorAdaptorT &x) const + { + if (x.policies().unput_queue.size() > 0) + return x.policies().unput_queue.front(); + return *x.base(); + } + + template + void + increment(IteratorAdaptorT &x) + { + if (x.policies().unput_queue.size() > 0) { + // there exist pending tokens in the unput queue + x.policies().unput_queue.pop_front(); + } + else { + // the unput_queue is empty, so advance the base iterator + ++x.base(); + } + } + + template + bool + equal(const IteratorAdaptorT1 &x, const IteratorAdaptorT2 &y) const + { + // two iterators are equal, if both begin() iterators of the queue objects + // are equal and the base iterators are equal as well + return + (x.policies().unput_queue.begin() == y.policies().unput_queue.begin() || + (0 == x.policies().queuesize() && 0 == y.policies().queuesize())) && + x.base() == y.base(); + } + + typename ContainerT::size_type queuesize() const + { return unput_queue.size(); } + + ContainerT &get_unput_queue() { return unput_queue; } + ContainerT const &get_unput_queue() const { return unput_queue; } + +private: + ContainerT &unput_queue; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// unput_queue_iterator +// +// The unput_queue_iterator templates encapsulates an unput_queue together +// with the direct input to be read after the unput queue is emptied +// +// This version is for the old iterator_adaptors (Boost V1.30.x) +// +/////////////////////////////////////////////////////////////////////////////// +template +class unput_queue_iterator +: public boost::iterator_adaptor< + IteratorT, unput_queue_policies, TokenT, + TokenT const &, TokenT const *> +{ + typedef + boost::iterator_adaptor< + IteratorT, unput_queue_policies, TokenT, + TokenT const &, TokenT const * + > + base_type; + typedef unput_queue_policies policies_type; + +public: + typedef ContainerT container_type; + typedef IteratorT iterator_type; + + unput_queue_iterator(IteratorT const &it, ContainerT &queue) + : base_type(it, policies_type(queue)) + {} + + ContainerT &get_unput_queue() + { return policies().get_unput_queue(); } + ContainerT const &get_unput_queue() const + { return policies().get_unput_queue(); } + IteratorT &get_base_iterator() + { return base(); } + IteratorT const &get_base_iterator() const + { return base(); } +}; + +#else // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + +/////////////////////////////////////////////////////////////////////////////// +// +// unput_queue_iterator +// +// The unput_queue_iterator templates encapsulates an unput_queue together +// with the direct input to be read after the unput queue is emptied +// +// This version is for the new iterator_adaptors (was released with +// Boost V1.31.0) +// +/////////////////////////////////////////////////////////////////////////////// +template +class unput_queue_iterator +: public boost::iterator_adaptor< + unput_queue_iterator, + IteratorT, TokenT const, std::forward_iterator_tag> +{ + typedef boost::iterator_adaptor< + unput_queue_iterator, + IteratorT, TokenT const, std::forward_iterator_tag> + base_type; + +public: + typedef ContainerT container_type; + typedef IteratorT iterator_type; + + unput_queue_iterator(IteratorT const &it, ContainerT &queue) + : base_type(it), unput_queue(queue) + {} + + ContainerT &get_unput_queue() + { return unput_queue; } + ContainerT const &get_unput_queue() const + { return unput_queue; } + IteratorT &get_base_iterator() + { return base_type::base_reference(); } + IteratorT const &get_base_iterator() const + { return base_type::base_reference(); } + + unput_queue_iterator &operator= (unput_queue_iterator const &rhs) + { + if (this != &rhs) { + unput_queue = rhs.unput_queue; + base_type::operator=(rhs); + } + return *this; + } + + typename base_type::reference dereference() const + { + if (!unput_queue.empty()) + return unput_queue.front(); + return *base_type::base_reference(); + } + + void increment() + { + if (!unput_queue.empty()) { + // there exist pending tokens in the unput queue + unput_queue.pop_front(); + } + else { + // the unput_queue is empty, so advance the base iterator + ++base_type::base_reference(); + } + } + + template < + typename OtherDerivedT, typename OtherIteratorT, + typename V, typename C, typename R, typename D + > + bool equal( + boost::iterator_adaptor + const &x) const + { + // two iterators are equal, if both begin() iterators of the queue + // objects are equal and the base iterators are equal as well + OtherDerivedT const &rhs = static_cast(x); + return + (unput_queue.empty() && rhs.unput_queue.empty() || + (&unput_queue == &rhs.unput_queue && + unput_queue.begin() == rhs.unput_queue.begin() + ) + ) && + get_base_iterator() == rhs.get_base_iterator(); + } + +private: + ContainerT &unput_queue; +}; + +#endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + +namespace impl { + + /////////////////////////////////////////////////////////////////////////// + template + struct gen_unput_queue_iterator + { + typedef ContainerT container_type; + typedef IteratorT iterator_type; + typedef unput_queue_iterator + return_type; + + static container_type last; + + static return_type + generate(iterator_type const &it) + { + return return_type(it, last); + } + + static return_type + generate(ContainerT &queue, iterator_type const &it) + { + return return_type(it, queue); + } + }; + + template + typename gen_unput_queue_iterator:: + container_type + gen_unput_queue_iterator::last = + typename gen_unput_queue_iterator:: + container_type(); + + /////////////////////////////////////////////////////////////////////////// + template + struct gen_unput_queue_iterator< + unput_queue_iterator, + TokenT, ContainerT> + { + typedef ContainerT container_type; + typedef unput_queue_iterator + iterator_type; + typedef unput_queue_iterator + return_type; + + static container_type last; + + static return_type + generate(iterator_type &it) + { + return return_t(it.base(), last); + } + + static return_type + generate(ContainerT &queue, iterator_type &it) + { + return return_t(it.base(), queue); + } + }; + + /////////////////////////////////////////////////////////////////////////// + template + struct assign_iterator { + + static void + do_ (IteratorT &dest, IteratorT const &src) + { + dest = src; + } + }; + +#if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \ + BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + + template + struct assign_iterator< + unput_queue_iterator > + { + typedef unput_queue_iterator + iterator_type; + + static void + do_ (iterator_type &dest, iterator_type const &src) + { + dest.base() = src.base(); + dest.policies() = src.policies(); + } + }; + +#endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + + /////////////////////////////////////////////////////////////////////////// + // + // Look for the first non-whitespace token and return this token id. + // Note though, that the embedded unput_queues are not touched in any way! + // + template + struct next_token { + + static boost::wave::token_id + peek(IteratorT it, IteratorT end, bool skip_whitespace = true) + { + using namespace boost::wave; + if (skip_whitespace) { + for (++it; it != end; ++it) { + if (!IS_CATEGORY(*it, WhiteSpaceTokenType) && + T_NEWLINE != token_id(*it)) + { + break; // stop at the first non-whitespace token + } + } + } + else { + ++it; // we have at least to look ahead + } + if (it != end) + return token_id(*it); + return T_EOI; + } + }; + + template + struct next_token< + unput_queue_iterator > { + + typedef unput_queue_iterator iterator_type; + + static boost::wave::token_id + peek(iterator_type it, iterator_type end, bool skip_whitespace = true) + { + using namespace boost::wave; + + typename iterator_type::container_type &queue = it.get_unput_queue(); + + // first try to find it in the unput_queue + if (0 != queue.size()) { + typename iterator_type::container_type::iterator cit = queue.begin(); + typename iterator_type::container_type::iterator cend = queue.end(); + + if (skip_whitespace) { + for (++cit; cit != cend; ++cit) { + if (!IS_CATEGORY(*cit, WhiteSpaceTokenType) && + T_NEWLINE != token_id(*cit)) + { + break; // stop at the first non-whitespace token + } + } + } + else { + ++cit; // we have at least to look ahead + } + if (cit != cend) + return token_id(*cit); + } + + // second try to move on into the base iterator stream + typename iterator_type::iterator_type base_it = it.get_base_iterator(); + typename iterator_type::iterator_type base_end = end.get_base_iterator(); + + if (0 == queue.size()) + ++base_it; // advance, if the unput queue is empty + + if (skip_whitespace) { + for (/**/; base_it != base_end; ++base_it) { + if (!IS_CATEGORY(*base_it, WhiteSpaceTokenType) && + T_NEWLINE != token_id(*base_it)) + { + break; // stop at the first non-whitespace token + } + } + } + if (base_it == base_end) + return T_EOI; + + return token_id(*base_it); + } + }; + + // Skip all whitespace characters and queue the skipped characters into the + // given container + template + inline boost::wave::token_id + skip_whitespace(IteratorT &first, IteratorT const &last) + { + using namespace cpplexer; + + token_id id = next_token::peek(first, last, false); + + if (IS_CATEGORY(id, WhiteSpaceTokenType)) { + do { + ++first; + id = next_token::peek(first, last, false); + } while (IS_CATEGORY(id, WhiteSpaceTokenType)); + } + ++first; + return id; + } + + template + inline boost::wave::token_id + skip_whitespace(IteratorT &first, IteratorT const &last, ContainerT &queue) + { + using namespace cpplexer; + queue.push_back (*first); // queue up the current token + + token_id id = next_token::peek(first, last, false); + + if (IS_CATEGORY(id, WhiteSpaceTokenType)) { + do { + queue.push_back(*++first); // queue up the next whitespace + id = next_token::peek(first, last, false); + } while (IS_CATEGORY(id, WhiteSpaceTokenType)); + } + ++first; + return id; + } + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +#endif // !defined(UNPUT_QUEUE_ITERATOR_HPP_76DA23D0_4893_4AD5_ABCC_6CED7CFB89BC_INCLUDED) diff --git a/include/boost/wave/wave_config.hpp b/include/boost/wave/wave_config.hpp new file mode 100644 index 000000000..3c0a22af5 --- /dev/null +++ b/include/boost/wave/wave_config.hpp @@ -0,0 +1,281 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Global application configuration + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(WAVE_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED) +#define WAVE_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Define the maximal include nesting depth allowed. If this value isn't +// defined it defaults to 1024 +// +// To define a new initial include nesting depth uncomment the following and +// supply a new integer value. +// +#if !defined(BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH) +#define BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH 1024 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to support variadics and placemarkers +// +// To implement support variadics and placemarkers uncomment the following +// +#if !defined(BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS) +#define BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to implement a #warning directive as an extension to the +// C++ Standard (same as #error, but emits a warning, not an error) +// +// To implement #warning directives, uncomment the following +// +#if !defined(BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE) +#define BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to implement #pragma once +// +// To implement #pragma once, uncomment the following +// +#if !defined(BOOST_WAVE_SUPPORT_PRAGMA_ONCE) +#define BOOST_WAVE_SUPPORT_PRAGMA_ONCE 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to implement #include_next +// Please note, that this is an extension to the C++ Standard. +// +// To implement #include_next, uncomment the following +// +#if !defined(BOOST_WAVE_SUPPORT_INCLUDE_NEXT) +#define BOOST_WAVE_SUPPORT_INCLUDE_NEXT 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Undefine the following, to enable some MS specific language extensions: +// __int8, __int16, __int32, __int64, __based, __declspec, __cdecl, +// __fastcall, __stdcall, __try, __except, __finally, __leave, __inline, +// __asm, #region, #endregion +// +// Note: By default this is enabled for Windows based systems, otherwise it's +// disabled. +#if !defined(BOOST_WAVE_SUPPORT_MS_EXTENSIONS) +#if defined(BOOST_WINDOWS) +#define BOOST_WAVE_SUPPORT_MS_EXTENSIONS 1 +#else +#define BOOST_WAVE_SUPPORT_MS_EXTENSIONS 0 +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow the message body of the #error and #warning directives to be +// preprocessed before the diagnostic is issued. +// +// Uncommenting the following will preprocess the message bodies of #error and +// #warning messages before the error (warning) is issued +// +#if !defined(BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY) +#define BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow the #pragma directives to be returned to the caller (optionally after +// preprocessing the body) +// +// Uncommenting the following will skip #pragma directives, so that the caller +// will not see them. +// +#if !defined(BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES) +#define BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow the body of a #pragma directive to be preprocessed before the +// directive is returned to the caller. +// +// Uncommenting the following will preprocess the bodies of #pragma directives +// +#if !defined(BOOST_WAVE_PREPROCESS_PRAGMA_BODY) +#define BOOST_WAVE_PREPROCESS_PRAGMA_BODY 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow to define macros with the command line syntax (-DMACRO(x)=definition) +// +// Uncommenting the following will enable the possibility to define macros +// based on the command line syntax +// +#if !defined(BOOST_WAVE_ENABLE_COMMANDLINE_MACROS) +#define BOOST_WAVE_ENABLE_COMMANDLINE_MACROS 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Define the string type to be used to store the token values and the file +// names inside a file_position template class +// +#if !defined(BOOST_WAVE_STRINGTYPE) + +// use the following, if you have a fast std::allocator +#define BOOST_WAVE_STRINGTYPE boost::wave::util::flex_string< \ + char, std::char_traits, std::allocator, \ + boost::wave::util::CowString \ + > \ + > \ + /**/ + +/* #define BOOST_WAVE_STRINGTYPE boost::wave::util::flex_string< \ + char, std::char_traits, boost::fast_pool_allocator, \ + boost::wave::util::CowString \ + > \ + > \ + > \ +*/ /**/ + +// This include is needed for the flex_string class used in the +// BOOST_WAVE_STRINGTYPE above. +#include + +// This include is needed for the boost::fast_allocator class used in the +// BOOST_WAVE_STRINGTYPE above. +// Configure Boost.Pool thread support (for now: no thread support at all) +//#define BOOST_NO_MT +//#include + +// Use the following, if you want to incorporate Maxim Yegorushkin's +// const_string library (http://sourceforge.net/projects/conststring/), which +// may be even faster, than using the flex_string class from above +//#define BOOST_WAVE_STRINGTYPE boost::const_string +// +//#include +//#include +//#include + +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment the following, if you need debug output, the +// BOOST_SPIRIT_DEBUG_FLAGS_CPP constants below help to fine control the +// amount of the generated debug output. +//#define BOOST_SPIRIT_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// Debug flags for the Wave library, possible flags spcified below. +// +// Note: These flags take effect only if the BOOST_SPIRIT_DEBUG constant +// above is defined as well. +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR 0x0001 +#define BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION 0x0002 +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR 0x0004 +#define BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR 0x0008 +#define BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR 0x0010 +#define BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR 0x0020 +#define BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR 0x0040 + +#if !defined(BOOST_SPIRIT_DEBUG_FLAGS_CPP) +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP 0 // default is no debugging +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// For all recognized preprocessor statements the output parse trees +// formatted as xml are printed. The formatted parse trees are streamed to the +// std::ostream defined by the WAVE_DUMP_PARSE_TREE_OUT constant. +// +// Uncomment the following, if you want to see these parse trees. +// +#if !defined(BOOST_WAVE_DUMP_PARSE_TREE) +#define BOOST_WAVE_DUMP_PARSE_TREE 0 +#endif +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 && !defined(BOOST_WAVE_DUMP_PARSE_TREE_OUT) +#define BOOST_WAVE_DUMP_PARSE_TREE_OUT std::cerr +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// For all #if and #elif directives the preprocessed expressions are printed. +// These expressions are streamed to the std::ostream defined by the +// BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT constant. +// +// Uncomment the following, if you want to see the preprocessed expressions +// +#if !defined(BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS) +#define BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS 0 +#endif +#if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0 && \ + !defined(BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT) +#define BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT std::cerr +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to use the separate compilation model for the instantiation +// of the C++ lexer objects. +// +// If this is defined, you should explicitly instantiate the C++ lexer +// template with the correct parameters in a separate compilation unit of +// your program (see the file instantiate_re2c_lexer.cpp). +// +// To use the lexer inclusion model, uncomment the following +// +#if !defined(BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION) +#define BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to use the separate compilation model for the instantiation +// of the grammar objects. +// +// If this is defined, you should explicitly instantiate the grammar +// templates with the correct parameters in a separate compilation unit of +// your program (see the files instantiate_cpp_grammar.cpp et.al.). +// +// To use the grammar inclusion model, uncomment the following +// +#if !defined(BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION) +#define BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// configure Boost.Pool thread support (for now: no thread support at all) +#if !defined(BOOST_NO_MT) +#define BOOST_NO_MT +#endif // !defined(BOOST_NO_MT) + +/////////////////////////////////////////////////////////////////////////////// +// Auto library naming +#if BOOST_VERSION >= 103100 +// auto link features work beginning from Boost V1.31.0 +#if !defined(BOOST_WAVE_SOURCE) && !defined(BOOST_ALL_NO_LIB) && \ + !defined(BOOST_WAVE_NO_LIB) + +#define BOOST_LIB_NAME boost_wave + +// tell the auto-link code to select a dll when required: +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_WAVE_DYN_LINK) +#define BOOST_DYN_LINK +#endif + +#include + +#endif // auto-linking disabled +#endif // BOOST_VERSION + +#endif // !defined(WAVE_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED) diff --git a/include/boost/wave/wave_version.hpp b/include/boost/wave/wave_version.hpp new file mode 100644 index 000000000..558c2f22f --- /dev/null +++ b/include/boost/wave/wave_version.hpp @@ -0,0 +1,26 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + This is the current version of the Wave library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(WAVE_VERSION_H_9D79ABDB_AC54_4C0A_89B1_F70A2DCFE21E_INCLUDED) +#define WAVE_VERSION_H_9D79ABDB_AC54_4C0A_89B1_F70A2DCFE21E_INCLUDED + +// BOOST_WAVE_VERSION & 0x0000FF is the sub-minor version +// BOOST_WAVE_VERSION & 0x00FF00 is the minor version +// BOOST_WAVE_VERSION & 0xFF0000 is the major version +#define BOOST_WAVE_VERSION 0x010114 + +// The following defines contain the same information as above +#define BOOST_WAVE_VERSION_MAJOR 1 +#define BOOST_WAVE_VERSION_MINOR 1 +#define BOOST_WAVE_VERSION_SUBMINOR 14 + +#endif // !defined(WAVE_VERSION_H_9D79ABDB_AC54_4C0A_89B1_F70A2DCFE21E_INCLUDED) diff --git a/index.html b/index.html new file mode 100644 index 000000000..8628156b9 --- /dev/null +++ b/index.html @@ -0,0 +1,106 @@ + + + +Wave V1.2 + + + + + + + + + + +

Wave + V1.1.13
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table of Contents
Preface
Introduction
Quick Start
Class + References
The Context + Object
The Input + Policy
The Context + Policy
The Lexer Iterator Interface +
The Token + Type
The Token Identifiers
The File + Position
Predefined Macros
Supported Pragma + Directives
The Macro + Expansion Process
Compile Time Configuration
Samples
The Wave Driver Executable
The Wave Driver Command + Line
The Tracing Facility
Acknowledgments
References
+
+
+ + + + + diff --git a/samples/Jamfile.v2 b/samples/Jamfile.v2 new file mode 100644 index 000000000..314358fa1 --- /dev/null +++ b/samples/Jamfile.v2 @@ -0,0 +1,13 @@ +# Copyright Vladimir Prus 2004. +# 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) + +project + : requirements true + ; + +build-project cpp_tokens/build ; +build-project list_includes/build ; +build-project quick_start/build ; +build-project waveidl/build ; diff --git a/samples/cpp_tokens/build/Jamfile b/samples/cpp_tokens/build/Jamfile new file mode 100644 index 000000000..8723f063e --- /dev/null +++ b/samples/cpp_tokens/build/Jamfile @@ -0,0 +1,30 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Sample Build Jamfile (cpp_tokens) +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +subproject libs/wave/samples/cpp_tokens/build ; + +exe cpp_tokens + : ../cpp_tokens.cpp + ../instantiate_cpp_exprgrammar.cpp + ../instantiate_cpp_grammar.cpp + ../instantiate_cpp_literalgrammars.cpp + ../instantiate_defined_grammar.cpp + ../instantiate_slex_lexer.cpp + ../../../build/boost_wave + ../../../../../libs/program_options/build/boost_program_options + ../../../../../libs/filesystem/build/boost_filesystem + : + $(BOOST_ROOT) + <*>off # workaround for compiler bug + : + static + single + ; + diff --git a/samples/cpp_tokens/build/Jamfile.v2 b/samples/cpp_tokens/build/Jamfile.v2 new file mode 100644 index 000000000..ad554551d --- /dev/null +++ b/samples/cpp_tokens/build/Jamfile.v2 @@ -0,0 +1,23 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Sample Build Jamfile (cpp_tokens) +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +exe cpp_tokens + : ../cpp_tokens.cpp + ../instantiate_cpp_exprgrammar.cpp + ../instantiate_cpp_grammar.cpp + ../instantiate_cpp_literalgrammars.cpp + ../instantiate_defined_grammar.cpp + ../instantiate_slex_lexer.cpp + ../../../build//boost_wave + $(BOOST_ROOT)/boost/program_options//boost_program_options + : + msvc-7.1:off # workaround for compiler bug + ; + diff --git a/samples/cpp_tokens/cpp_tokens.cpp b/samples/cpp_tokens/cpp_tokens.cpp new file mode 100644 index 000000000..1575d451d --- /dev/null +++ b/samples/cpp_tokens/cpp_tokens.cpp @@ -0,0 +1,131 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: Print out the preprocessed tokens returned by the Wave iterator + + This sample shows, how it is possible to use a custom lexer type and a + custom token type with the Wave library. + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "cpp_tokens.hpp" // global configuration + +/////////////////////////////////////////////////////////////////////////////// +// Include Wave itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// The following files contain the custom lexer type to use +#include "slex_token.hpp" +#include "slex_iterator.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// include lexer specifics, import lexer names +#if !defined(BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION) +#include "slex/cpp_slex_lexer.hpp" +#endif // !defined(BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION) + +/////////////////////////////////////////////////////////////////////////////// +// import required names +using namespace boost::spirit; + +using std::string; +using std::getline; +using std::ifstream; +using std::cout; +using std::cerr; +using std::endl; +using std::ostream; + +/////////////////////////////////////////////////////////////////////////////// +// main program +int +main(int argc, char *argv[]) +{ + if (2 != argc) { + cout << "Usage: cpp_tokens input_file" << endl; + return 1; + } + +// read the file to analyse into a std::string + ifstream infile(argv[1]); + string teststr; + if (infile.is_open()) { + infile.unsetf(std::ios::skipws); + string line; + for (getline(infile, line); infile.good(); getline(infile, line)) { + teststr += line; + teststr += '\n'; + } + } + else { + teststr = argv[1]; + } + +// The following typedef does the trick. It defines the context type to use, +// which depends on the lexer type (provided by the second template +// parameter). Our lexer type 'slex_iterator<>' depends on a custom token type +// 'slex_token<>'. Our custom token type differs from the original one povided +// by the Wave library only by defining an additional operator<<(), which is +// used to dump the token information carried by a given token (see loop +// below). + typedef boost::wave::cpp_token_sample::slex_token<> token_type; + typedef boost::wave::cpp_token_sample::slex_iterator + lex_iterator_type; + typedef boost::wave::context + context_type; + +// The C++ preprocessor iterator shouldn't be constructed directly. It is to be +// generated through a boost::wave::context<> object. This object is +// additionally to be used to initialize and define different parameters of +// the actual preprocessing. +// The preprocessing of the input stream is done on the fly behind the scenes +// during iteration over the context_type::iterator_type stream. + context_type ctx (teststr.begin(), teststr.end(), argv[1]); + context_type::iterator_type first = ctx.begin(); + context_type::iterator_type last = ctx.end(); + context_type::token_type current_token; + + try { + // Traverse over the tokens generated from the input and dump the token + // contents. + while (first != last) { + // retrieve next token + current_token = *first; + + // output token info + cout << "matched " << current_token << endl; + ++first; + } + } + catch (boost::wave::cpp_exception &e) { + // some preprocessing error + cerr + << e.file_name() << "(" << e.line_no() << "): " + << e.description() << endl; + return 2; + } + catch (std::exception &e) { + // use last recognized token to retrieve the error position + cerr + << current_token.get_position().get_file() + << "(" << current_token.get_position().get_line() << "): " + << "unexpected exception: " << e.what() + << endl; + return 3; + } + catch (...) { + // use last recognized token to retrieve the error position + cerr + << current_token.get_position().get_file() + << "(" << current_token.get_position().get_line() << "): " + << "unexpected exception." << endl; + return 4; + } + return 0; +} diff --git a/samples/cpp_tokens/cpp_tokens.hpp b/samples/cpp_tokens/cpp_tokens.hpp new file mode 100644 index 000000000..c32d5f438 --- /dev/null +++ b/samples/cpp_tokens/cpp_tokens.hpp @@ -0,0 +1,38 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: Print out the preprocessed tokens returned by the Wave iterator + + This sample shows, how it is possible to use a custom lexer object and a + custom token type with the Wave library. + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_TOKENS_HPP_D6A31137_CE14_4869_9779_6357E2C43187_INCLUDED) +#define CPP_TOKENS_HPP_D6A31137_CE14_4869_9779_6357E2C43187_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// include often used files from the stdlib +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// include boost config +#include // global configuration information + +/////////////////////////////////////////////////////////////////////////////// +// configure this app here (global configuration constants) +#include "cpp_tokens_config.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// include required boost libraries +#include +#include + +#endif // !defined(CPP_TOKENS_HPP_D6A31137_CE14_4869_9779_6357E2C43187_INCLUDED) diff --git a/samples/cpp_tokens/cpp_tokens_config.hpp b/samples/cpp_tokens/cpp_tokens_config.hpp new file mode 100644 index 000000000..bab406b94 --- /dev/null +++ b/samples/cpp_tokens/cpp_tokens_config.hpp @@ -0,0 +1,55 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: Print out the preprocessed tokens returned by the Wave iterator + Configuration data + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_TOKENS_HPP_7C0F1F14_6ACA_4439_A073_32C61C0DB6C5_INCLUDED) +#define CPP_TOKENS_HPP_7C0F1F14_6ACA_4439_A073_32C61C0DB6C5_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment the following, if you need debug output, the +// BOOST_SPIRIT_DEBUG_FLAGS constants below help to fine control the amount of +// the generated debug output +//#define BOOST_SPIRIT_DEBUG + +#if defined(BOOST_SPIRIT_DEBUG) +/////////////////////////////////////////////////////////////////////////////// +// debug flags for the pp-iterator library, possible flags (defined in +// wave_config.hpp): +// +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR 0x0001 +// #define BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION 0x0002 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR 0x0004 +// #define BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR 0x0008 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR 0x0010 +// #define BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR 0x0020 +// #define BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR 0x0040 + +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP (\ + /* insert the required flags from above */ \ + ) \ + /**/ +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Include the configuration stuff for the Wave library itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// MSVC specific #pragma's +#if defined(BOOST_MSVC) +#pragma warning (disable: 4355) // 'this' used in base member initializer list +#pragma warning (disable: 4800) // forcing value to bool 'true' or 'false' +#pragma inline_depth(255) +#pragma inline_recursion(on) +#endif // defined(BOOST_MSVC) + +#endif // !defined(CPP_TOKENS_HPP_7C0F1F14_6ACA_4439_A073_32C61C0DB6C5_INCLUDED) diff --git a/samples/cpp_tokens/instantiate_cpp_exprgrammar.cpp b/samples/cpp_tokens/instantiate_cpp_exprgrammar.cpp new file mode 100644 index 000000000..b426ff8e7 --- /dev/null +++ b/samples/cpp_tokens/instantiate_cpp_exprgrammar.cpp @@ -0,0 +1,42 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: prints out the preprocessed tokens returned by the pp iterator + Explicit instantiation of the cpp_expression_grammar parsing + function + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "cpp_tokens.hpp" // config data + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include + +#include "slex_token.hpp" +#include "slex_iterator.hpp" + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the expression_grammar_gen template with the +// correct token type. This instantiates the corresponding parse function, +// which in turn instantiates the expression_grammar object (see +// wave/grammars/cpp_expression_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpp_token_sample::slex_token<> token_type; + +template struct boost::wave::grammars::expression_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/samples/cpp_tokens/instantiate_cpp_grammar.cpp b/samples/cpp_tokens/instantiate_cpp_grammar.cpp new file mode 100644 index 000000000..261536af6 --- /dev/null +++ b/samples/cpp_tokens/instantiate_cpp_grammar.cpp @@ -0,0 +1,42 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: prints out the preprocessed tokens returned by the pp iterator + Explicit instantiation of the cpp_grammar parsing function + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "cpp_tokens.hpp" // config data + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include + +#include "slex_token.hpp" +#include "slex_iterator.hpp" + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the cpp_grammar_gen template with the correct +// token type. This instantiates the corresponding pt_parse function, which +// in turn instantiates the cpp_grammar object +// (see wave/grammars/cpp_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpp_token_sample::slex_iterator< + boost::wave::cpp_token_sample::slex_token<> > + lexer_type; +template struct boost::wave::grammars::cpp_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/samples/cpp_tokens/instantiate_cpp_literalgrammars.cpp b/samples/cpp_tokens/instantiate_cpp_literalgrammars.cpp new file mode 100644 index 000000000..8e82d50d5 --- /dev/null +++ b/samples/cpp_tokens/instantiate_cpp_literalgrammars.cpp @@ -0,0 +1,43 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: prints out the preprocessed tokens returned by the pp iterator + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "cpp_tokens.hpp" // config data + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include + +#include "slex_token.hpp" +#include "slex_iterator.hpp" + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the intlit_grammar_gen, chlit_grammar_gen and +// floatlit_grammar_gen templates with the correct token type. This +// instantiates the corresponding parse function, which in turn instantiates +// the corresponding parser object. +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpp_token_sample::slex_token<> token_type; + +template struct boost::wave::grammars::intlit_grammar_gen; +template struct boost::wave::grammars::chlit_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/samples/cpp_tokens/instantiate_defined_grammar.cpp b/samples/cpp_tokens/instantiate_defined_grammar.cpp new file mode 100644 index 000000000..a30520535 --- /dev/null +++ b/samples/cpp_tokens/instantiate_defined_grammar.cpp @@ -0,0 +1,39 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "cpp_tokens.hpp" // config data + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include + +#include "slex_token.hpp" +#include "slex_iterator.hpp" + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the defined_grammar_gen template +// with the correct token type. This instantiates the corresponding parse +// function, which in turn instantiates the defined_grammar +// object (see wave/grammars/cpp_defined_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpp_token_sample::slex_iterator< + boost::wave::cpp_token_sample::slex_token<> > + lexer_type; +template struct boost::wave::grammars::defined_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/samples/cpp_tokens/instantiate_slex_lexer.cpp b/samples/cpp_tokens/instantiate_slex_lexer.cpp new file mode 100644 index 000000000..c5c7dc94f --- /dev/null +++ b/samples/cpp_tokens/instantiate_slex_lexer.cpp @@ -0,0 +1,47 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: Print out the preprocessed tokens returned by the Wave iterator + Explicit instantiation of the lex_functor generation function + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "cpp_tokens.hpp" // config data + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include + +#include "slex_token.hpp" +#include "slex_iterator.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include "slex/cpp_slex_lexer.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// +// This instantiates the correct 'new_lexer' function, which generates the +// C++ lexer used in this sample. +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the parameters +// supplied while instantiating the context<> template. +// +/////////////////////////////////////////////////////////////////////////////// + +template struct boost::wave::cpp_token_sample::new_lexer_gen< + std::string::iterator>; + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/samples/cpp_tokens/slex/cpp_slex_lexer.hpp b/samples/cpp_tokens/slex/cpp_slex_lexer.hpp new file mode 100644 index 000000000..5c74c6aaf --- /dev/null +++ b/samples/cpp_tokens/slex/cpp_slex_lexer.hpp @@ -0,0 +1,620 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + SLex (Spirit Lex) based C++ lexer + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(SLEX_LEXER_HPP_5E8E1DF0_BB41_4938_B7E5_A4BB68222FF6_INCLUDED) +#define SLEX_LEXER_HPP_5E8E1DF0_BB41_4938_B7E5_A4BB68222FF6_INCLUDED + +#include +#if defined(BOOST_SPIRIT_DEBUG) +#include +#endif // defined(BOOST_SPIRIT_DEBUG) + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../slex_interface.hpp" +#include "../slex_token.hpp" +#include "../slex_iterator.hpp" + +#include "lexer.hpp" // "spirit/lexer.hpp" + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpp_token_sample { +namespace slex { + +/////////////////////////////////////////////////////////////////////////////// +// +// encapsulation of the boost::spirit::slex based cpp lexer +// +/////////////////////////////////////////////////////////////////////////////// + +template +class lexer +: public boost::spirit::lexer< + boost::wave::util::position_iterator > +{ +public: + + typedef boost::wave::util::position_iterator + iterator_type; + typedef typename std::iterator_traits::value_type char_t; + typedef boost::spirit::lexer base_t; + + typedef boost::wave::cpp_token_sample::slex_token token_type; + + lexer(); + void init_dfa(boost::wave::language_support language); + +// get time of last compilation + static std::time_t get_compilation_time() + { return compilation_time.get_time(); } + +private: +// initialization data (regular expressions for the token definitions) + struct lexer_data { + token_id tokenid; // token data + char_t const *tokenregex; // associated token to match + typename base_t::callback_t tokencb; // associated callback function + unsigned int lexerstate; // valid for lexer state + }; + + static lexer_data const init_data[]; // common patterns + static lexer_data const init_data_cpp[]; // C++ only patterns + +// helper for calculation of the time of last compilation + static boost::wave::util::time_conversion_helper compilation_time; +}; + +/////////////////////////////////////////////////////////////////////////////// +// data required for initialization of the lexer (token definitions) +#define OR "|" +#define Q(c) "\\" c +#define TRI(c) Q("?") Q("?") c + +// definition of some subtoken regexps to simplify the regex definitions +#define BLANK "[ \\t]" +#define CCOMMENT \ + Q("/") Q("*") "[^*]*" Q("*") "+" "(" "[^/*][^*]*" Q("*") "+" ")*" Q("/") + +#define PPSPACE "(" BLANK OR CCOMMENT ")*" + +#define OCTALDIGIT "[0-7]" +#define DIGIT "[0-9]" +#define HEXDIGIT "[0-9a-fA-F]" +#define SIGN "[-+]?" +#define EXPONENT "(" "[eE]" SIGN "[0-9]+" ")" + +#define INTEGER_SUFFIX "(" "[uU][lL]?|[lL][uU]?" ")" +#define FLOAT_SUFFIX "(" "[fF][lL]?|[lL][fF]?" ")" +#define CHAR_SPEC "L?" + +#define BACKSLASH "(" Q("\\") OR TRI(Q("/")) ")" +#define ESCAPESEQ BACKSLASH "(" \ + "[abfnrtv?'\"]" OR \ + BACKSLASH OR \ + "x" HEXDIGIT "+" OR \ + OCTALDIGIT OCTALDIGIT "?" OCTALDIGIT "?" \ + ")" +#define HEXQUAD HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT +#define UNIVERSALCHAR BACKSLASH "(" \ + "u" HEXQUAD OR \ + "U" HEXQUAD HEXQUAD \ + ")" + +#define POUNDDEF "(" "#" OR TRI("=") OR Q("%:") ")" +#define NEWLINEDEF "(" "\\n" OR "\\r" OR "\\r\\n" ")" + +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 +#define INCLUDEDEF "(include|include_next)" +#else +#define INCLUDEDEF "include" +#endif + +/////////////////////////////////////////////////////////////////////////////// +// sexer state constants +#define LEXER_STATE_NORMAL 0 +#define LEXER_STATE_PP 1 + +#define NUM_LEXER_STATES 1 + +// helper for initializing token data +#define TOKEN_DATA(id, regex) \ + { T_##id, regex, 0, LEXER_STATE_NORMAL } + +#define TOKEN_DATA_EX(id, regex, callback) \ + { T_##id, regex, callback, LEXER_STATE_NORMAL } + +/////////////////////////////////////////////////////////////////////////////// +// common C++/C99 token definitions +template +typename lexer::lexer_data const +lexer::init_data[] = +{ + TOKEN_DATA(AND, "&"), + TOKEN_DATA(ANDAND, "&&"), + TOKEN_DATA(ASSIGN, "="), + TOKEN_DATA(ANDASSIGN, "&="), + TOKEN_DATA(OR, Q("|")), + TOKEN_DATA(OR_TRIGRAPH, TRI("!")), + TOKEN_DATA(ORASSIGN, Q("|=") OR TRI("!=")), + TOKEN_DATA(XOR, Q("^")), + TOKEN_DATA(XOR_TRIGRAPH, TRI("'")), + TOKEN_DATA(XORASSIGN, Q("^=") OR TRI("'=")), + TOKEN_DATA(COMMA, ","), + TOKEN_DATA(COLON, ":"), + TOKEN_DATA(DIVIDE, Q("/")), + TOKEN_DATA(DIVIDEASSIGN, Q("/=")), + TOKEN_DATA(DOT, Q(".")), + TOKEN_DATA(ELLIPSIS, Q(".") Q(".") Q(".")), + TOKEN_DATA(EQUAL, "=="), + TOKEN_DATA(GREATER, ">"), + TOKEN_DATA(GREATEREQUAL, ">="), + TOKEN_DATA(LEFTBRACE, Q("{")), + TOKEN_DATA(LEFTBRACE_ALT, "<" Q("%")), + TOKEN_DATA(LEFTBRACE_TRIGRAPH, TRI("<")), + TOKEN_DATA(LESS, "<"), + TOKEN_DATA(LESSEQUAL, "<="), + TOKEN_DATA(LEFTPAREN, Q("(")), + TOKEN_DATA(LEFTBRACKET, Q("[")), + TOKEN_DATA(LEFTBRACKET_ALT, "<:"), + TOKEN_DATA(LEFTBRACKET_TRIGRAPH, TRI(Q("("))), + TOKEN_DATA(MINUS, Q("-")), + TOKEN_DATA(MINUSASSIGN, Q("-=")), + TOKEN_DATA(MINUSMINUS, Q("-") Q("-")), + TOKEN_DATA(PERCENT, Q("%")), + TOKEN_DATA(PERCENTASSIGN, Q("%=")), + TOKEN_DATA(NOT, "!"), + TOKEN_DATA(NOTEQUAL, "!="), + TOKEN_DATA(OROR, Q("|") Q("|") OR TRI("!") Q("|") OR Q("|") TRI("!") OR + TRI("!") TRI("!")), + TOKEN_DATA(PLUS, Q("+")), + TOKEN_DATA(PLUSASSIGN, Q("+=")), + TOKEN_DATA(PLUSPLUS, Q("+") Q("+")), + TOKEN_DATA(ARROW, Q("->")), + TOKEN_DATA(QUESTION_MARK, Q("?")), + TOKEN_DATA(RIGHTBRACE, Q("}")), + TOKEN_DATA(RIGHTBRACE_ALT, Q("%>")), + TOKEN_DATA(RIGHTBRACE_TRIGRAPH, TRI(">")), + TOKEN_DATA(RIGHTPAREN, Q(")")), + TOKEN_DATA(RIGHTBRACKET, Q("]")), + TOKEN_DATA(RIGHTBRACKET_ALT, ":>"), + TOKEN_DATA(RIGHTBRACKET_TRIGRAPH, TRI(Q(")"))), + TOKEN_DATA(SEMICOLON, ";"), + TOKEN_DATA(SHIFTLEFT, "<<"), + TOKEN_DATA(SHIFTLEFTASSIGN, "<<="), + TOKEN_DATA(SHIFTRIGHT, ">>"), + TOKEN_DATA(SHIFTRIGHTASSIGN, ">>="), + TOKEN_DATA(STAR, Q("*")), + TOKEN_DATA(COMPL, Q("~")), + TOKEN_DATA(COMPL_TRIGRAPH, TRI("-")), + TOKEN_DATA(STARASSIGN, Q("*=")), + TOKEN_DATA(ASM, "asm"), + TOKEN_DATA(AUTO, "auto"), + TOKEN_DATA(BOOL, "bool"), + TOKEN_DATA(FALSE, "false"), + TOKEN_DATA(TRUE, "true"), + TOKEN_DATA(BREAK, "break"), + TOKEN_DATA(CASE, "case"), + TOKEN_DATA(CATCH, "catch"), + TOKEN_DATA(CHAR, "char"), + TOKEN_DATA(CLASS, "class"), + TOKEN_DATA(CONST, "const"), + TOKEN_DATA(CONSTCAST, "const_cast"), + TOKEN_DATA(CONTINUE, "continue"), + TOKEN_DATA(DEFAULT, "default"), +// TOKEN_DATA(DEFINED, "defined"), + TOKEN_DATA(DELETE, "delete"), + TOKEN_DATA(DO, "do"), + TOKEN_DATA(DOUBLE, "double"), + TOKEN_DATA(DYNAMICCAST, "dynamic_cast"), + TOKEN_DATA(ELSE, "else"), + TOKEN_DATA(ENUM, "enum"), + TOKEN_DATA(EXPLICIT, "explicit"), + TOKEN_DATA(EXPORT, "export"), + TOKEN_DATA(EXTERN, "extern"), + TOKEN_DATA(FLOAT, "float"), + TOKEN_DATA(FOR, "for"), + TOKEN_DATA(FRIEND, "friend"), + TOKEN_DATA(GOTO, "goto"), + TOKEN_DATA(IF, "if"), + TOKEN_DATA(INLINE, "inline"), + TOKEN_DATA(INT, "int"), + TOKEN_DATA(LONG, "long"), + TOKEN_DATA(MUTABLE, "mutable"), + TOKEN_DATA(NAMESPACE, "namespace"), + TOKEN_DATA(NEW, "new"), + TOKEN_DATA(OPERATOR, "operator"), + TOKEN_DATA(PRIVATE, "private"), + TOKEN_DATA(PROTECTED, "protected"), + TOKEN_DATA(PUBLIC, "public"), + TOKEN_DATA(REGISTER, "register"), + TOKEN_DATA(REINTERPRETCAST, "reinterpret_cast"), + TOKEN_DATA(RETURN, "return"), + TOKEN_DATA(SHORT, "short"), + TOKEN_DATA(SIGNED, "signed"), + TOKEN_DATA(SIZEOF, "sizeof"), + TOKEN_DATA(STATIC, "static"), + TOKEN_DATA(STATICCAST, "static_cast"), + TOKEN_DATA(STRUCT, "struct"), + TOKEN_DATA(SWITCH, "switch"), + TOKEN_DATA(TEMPLATE, "template"), + TOKEN_DATA(THIS, "this"), + TOKEN_DATA(THROW, "throw"), + TOKEN_DATA(TRY, "try"), + TOKEN_DATA(TYPEDEF, "typedef"), + TOKEN_DATA(TYPEID, "typeid"), + TOKEN_DATA(TYPENAME, "typename"), + TOKEN_DATA(UNION, "union"), + TOKEN_DATA(UNSIGNED, "unsigned"), + TOKEN_DATA(USING, "using"), + TOKEN_DATA(VIRTUAL, "virtual"), + TOKEN_DATA(VOID, "void"), + TOKEN_DATA(VOLATILE, "volatile"), + TOKEN_DATA(WCHART, "wchar_t"), + TOKEN_DATA(WHILE, "while"), + TOKEN_DATA(PP_DEFINE, POUNDDEF PPSPACE "define"), + TOKEN_DATA(PP_IF, POUNDDEF PPSPACE "if"), + TOKEN_DATA(PP_IFDEF, POUNDDEF PPSPACE "ifdef"), + TOKEN_DATA(PP_IFNDEF, POUNDDEF PPSPACE "ifndef"), + TOKEN_DATA(PP_ELSE, POUNDDEF PPSPACE "else"), + TOKEN_DATA(PP_ELIF, POUNDDEF PPSPACE "elif"), + TOKEN_DATA(PP_ENDIF, POUNDDEF PPSPACE "endif"), + TOKEN_DATA(PP_ERROR, POUNDDEF PPSPACE "error"), + TOKEN_DATA(PP_QHEADER, POUNDDEF PPSPACE \ + INCLUDEDEF PPSPACE Q("\"") "[^\\n\\r\"]+" Q("\"")), + TOKEN_DATA(PP_HHEADER, POUNDDEF PPSPACE \ + INCLUDEDEF PPSPACE "<" "[^\\n\\r>]+" ">"), + TOKEN_DATA(PP_INCLUDE, POUNDDEF PPSPACE \ + INCLUDEDEF PPSPACE), + TOKEN_DATA(PP_LINE, POUNDDEF PPSPACE "line"), + TOKEN_DATA(PP_PRAGMA, POUNDDEF PPSPACE "pragma"), + TOKEN_DATA(PP_UNDEF, POUNDDEF PPSPACE "undef"), + TOKEN_DATA(PP_WARNING, POUNDDEF PPSPACE "warning"), + TOKEN_DATA(IDENTIFIER, "([a-zA-Z_]" OR UNIVERSALCHAR ")([a-zA-Z0-9_]" OR UNIVERSALCHAR ")*"), +// TOKEN_DATA(OCTALINT, "0" OCTALDIGIT "*" INTEGER_SUFFIX "?"), +// TOKEN_DATA(DECIMALINT, "[1-9]" DIGIT "*" INTEGER_SUFFIX "?"), +// TOKEN_DATA(HEXAINT, "(0x|0X)" HEXDIGIT "+" INTEGER_SUFFIX "?"), + TOKEN_DATA(INTLIT, "(" "(0x|0X)" HEXDIGIT "+" OR "0" OCTALDIGIT "*" OR \ + "[1-9]" DIGIT "*" ")" INTEGER_SUFFIX "?"), + TOKEN_DATA(FLOATLIT, + "(" DIGIT "*" Q(".") DIGIT "+" OR DIGIT "+" Q(".") ")" + EXPONENT "?" FLOAT_SUFFIX "?" OR + DIGIT "+" EXPONENT FLOAT_SUFFIX "?"), + TOKEN_DATA(CCOMMENT, CCOMMENT), + TOKEN_DATA(CPPCOMMENT, Q("/") Q("/[^\\n\\r]*") NEWLINEDEF ), + TOKEN_DATA(CHARLIT, CHAR_SPEC "'" + "(" ESCAPESEQ OR "[^\\n\\r']" OR UNIVERSALCHAR ")+" "'"), + TOKEN_DATA(STRINGLIT, CHAR_SPEC Q("\"") + "(" ESCAPESEQ OR "[^\\n\\r\"]" OR UNIVERSALCHAR ")*" Q("\"")), + TOKEN_DATA(SPACE, BLANK "+"), + TOKEN_DATA(SPACE2, "[\\v\\f]+"), + TOKEN_DATA(CONTLINE, Q("\\") "\\n"), + TOKEN_DATA(NEWLINE, NEWLINEDEF), + TOKEN_DATA(POUND_POUND, "##"), + TOKEN_DATA(POUND_POUND_ALT, Q("%:") Q("%:")), + TOKEN_DATA(POUND_POUND_TRIGRAPH, TRI("=") TRI("=")), + TOKEN_DATA(POUND, "#"), + TOKEN_DATA(POUND_ALT, Q("%:")), + TOKEN_DATA(POUND_TRIGRAPH, TRI("=")), + TOKEN_DATA(ANY, "."), +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + TOKEN_DATA(MSEXT_INT8, "__int8"), + TOKEN_DATA(MSEXT_INT16, "__int16"), + TOKEN_DATA(MSEXT_INT32, "__int32"), + TOKEN_DATA(MSEXT_INT64, "__int64"), + TOKEN_DATA(MSEXT_BASED, "_?" "_based"), + TOKEN_DATA(MSEXT_DECLSPEC, "_?" "_declspec"), + TOKEN_DATA(MSEXT_CDECL, "_?" "_cdecl"), + TOKEN_DATA(MSEXT_FASTCALL, "_?" "_fastcall"), + TOKEN_DATA(MSEXT_STDCALL, "_?" "_stdcall"), + TOKEN_DATA(MSEXT_TRY , "__try"), + TOKEN_DATA(MSEXT_EXCEPT, "__except"), + TOKEN_DATA(MSEXT_FINALLY, "__finally"), + TOKEN_DATA(MSEXT_LEAVE, "__leave"), + TOKEN_DATA(MSEXT_INLINE, "_?" "_inline"), + TOKEN_DATA(MSEXT_ASM, "_?" "_asm"), + TOKEN_DATA(MSEXT_PP_REGION, POUNDDEF PPSPACE "region"), + TOKEN_DATA(MSEXT_PP_ENDREGION, POUNDDEF PPSPACE "endregion"), +#endif // BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + { token_id(0) } // this should be the last entry +}; + +/////////////////////////////////////////////////////////////////////////////// +// C++ only token definitions +template +typename lexer::lexer_data const +lexer::init_data_cpp[] = +{ + TOKEN_DATA(AND_ALT, "bitand"), + TOKEN_DATA(ANDAND_ALT, "and"), + TOKEN_DATA(ANDASSIGN_ALT, "and_eq"), + TOKEN_DATA(OR_ALT, "bitor"), + TOKEN_DATA(ORASSIGN_ALT, "or_eq"), + TOKEN_DATA(OROR_ALT, "or"), + TOKEN_DATA(XOR_ALT, "xor"), + TOKEN_DATA(XORASSIGN_ALT, "xor_eq"), + TOKEN_DATA(NOT_ALT, "not"), + TOKEN_DATA(NOTEQUAL_ALT, "not_eq"), + TOKEN_DATA(COMPL_ALT, "compl"), + TOKEN_DATA(ARROWSTAR, Q("->") Q("*")), + TOKEN_DATA(DOTSTAR, Q(".") Q("*")), + TOKEN_DATA(COLON_COLON, "::"), + { token_id(0) } // this should be the last entry +}; + +/////////////////////////////////////////////////////////////////////////////// +// undefine macros, required for regular expression definitions +#undef INCLUDEDEF +#undef POUNDDEF +#undef CCOMMENT +#undef PPSPACE +#undef DIGIT +#undef OCTALDIGIT +#undef HEXDIGIT +#undef SIGN +#undef EXPONENT +#undef INTEGER_SUFFIX +#undef FLOAT_SUFFIX +#undef CHAR_SPEC +#undef BACKSLASH +#undef ESCAPESEQ +#undef HEXQUAD +#undef UNIVERSALCHAR + +#undef Q +#undef TRI +#undef OR + +#undef TOKEN_DATA +#undef TOKEN_DATA_EX + +/////////////////////////////////////////////////////////////////////////////// +// initialize cpp lexer with token data +template +inline +lexer::lexer() +: base_t(NUM_LEXER_STATES) +{ +} + +template +inline void +lexer::init_dfa(boost::wave::language_support lang) +{ + if (has_compiled_dfa()) + return; + + for (int i = 0; 0 != init_data[i].tokenid; ++i) { + this->register_regex(init_data[i].tokenregex, init_data[i].tokenid, + init_data[i].tokencb, init_data[i].lexerstate); + } + +// if in C99 mode, some of the keywords are not valid + if (!boost::wave::need_c99(lang)) { + for (int j = 0; 0 != init_data_cpp[j].tokenid; ++j) { + this->register_regex(init_data_cpp[j].tokenregex, + init_data_cpp[j].tokenid, init_data_cpp[j].tokencb, + init_data_cpp[j].lexerstate); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// get time of last compilation of this file +template +boost::wave::util::time_conversion_helper + lexer::compilation_time(__DATE__ " " __TIME__); + +/////////////////////////////////////////////////////////////////////////////// +// +template +inline void +init_lexer (lexer &lexer, + boost::wave::language_support language, bool force_reinit = false) +{ + if (lexer.has_compiled_dfa()) + return; // nothing to do + + using std::ifstream; + using std::ofstream; + using std::ios; + using std::cerr; + using std::endl; + +ifstream dfa_in("wave_slex_lexer.dfa", ios::in|ios::binary); + + lexer.init_dfa(language); + if (force_reinit || !dfa_in.is_open() || + !lexer.load (dfa_in, (long)lexer.get_compilation_time())) + { +#if defined(BOOST_SPIRIT_DEBUG) + cerr << "Compiling regular expressions for slex ..."; +#endif // defined(BOOST_SPIRIT_DEBUG) + + dfa_in.close(); + lexer.create_dfa(); + + ofstream dfa_out ("wave_slex_lexer.dfa", ios::out|ios::binary|ios::trunc); + + if (dfa_out.is_open()) + lexer.save (dfa_out, (long)lexer.get_compilation_time()); + +#if defined(BOOST_SPIRIT_DEBUG) + cerr << " Done." << endl; +#endif // defined(BOOST_SPIRIT_DEBUG) + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_functor +// +/////////////////////////////////////////////////////////////////////////////// + +template +class slex_functor +: public slex_input_interface::token_type> +{ +public: + + typedef boost::wave::util::position_iterator + iterator_type; + typedef typename std::iterator_traits::value_type char_t; + typedef BOOST_WAVE_STRINGTYPE string_type; + typedef typename lexer::token_type token_type; + + slex_functor(IteratorT const &first_, IteratorT const &last_, + PositionT const &pos_, boost::wave::language_support language) + : first(first_, last_, pos_), at_eof(false) + { + // initialize lexer dfa tables + init_lexer(lexer, language); + } + virtual ~slex_functor() {} + +// get the next token from the input stream + token_type get() + { + token_type token; + + if (!at_eof) { + do { + // generate and return the next token + std::string value; + PositionT pos = first.get_position(); // begin of token position + token_id id = token_id(lexer.next_token(first, last, &value)); + + if ((token_id)(-1) == id) + id = T_EOF; // end of input reached + + string_type token_val(value.c_str()); + + if (T_CONTLINE != id) { + switch (id) { + case T_IDENTIFIER: + // test identifier characters for validity (throws if + // invalid chars found) + using boost::wave::cpplexer::impl::validate_identifier_name; + validate_identifier_name(token_val, + pos.get_line(), pos.get_column(), pos.get_file()); + break; + + case T_STRINGLIT: + case T_CHARLIT: + // test literal characters for validity (throws if invalid + // chars found) + using boost::wave::cpplexer::impl::validate_literal; + validate_literal(token_val, + pos.get_line(), pos.get_column(), pos.get_file()); + break; + +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + case T_PP_HHEADER: + case T_PP_QHEADER: + case T_PP_INCLUDE: + // convert to the corresponding ..._next token, if appropriate + if (string_type::npos != value.find("include_")) + id = token_id(id | AltTokenType); + break; +#endif // BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + + case T_EOF: + // T_EOF is returned as a valid token, the next call will + // return T_EOI, i.e. the actual end of input + at_eof = true; + break; + } + return token_type(id, token_val, pos); + } + + // skip the T_CONTLINE token + } while (true); + } + return token; // return T_EOI + } + void set_position(PositionT const &pos) + { first.set_position(pos); } + +private: + iterator_type first; + iterator_type last; + static lexer lexer; // needed only once + + bool at_eof; +}; + +template +lexer slex_functor::lexer; + +} // namespace slex + +/////////////////////////////////////////////////////////////////////////////// +// +// The 'new_lexer' function allows the opaque generation of a new lexer object. +// It is coupled to the iterator type to allow to decouple the lexer/iterator +// configurations at compile time. +// +// This function is declared inside the cpp_slex_token.hpp file, which is +// referenced by the source file calling the lexer and the source file, which +// instantiates the lex_functor. But is is defined here, so it will be +// instantiated only while compiling the source file, which instantiates the +// lex_functor. While the cpp_slex_token.hpp file may be included everywhere, +// this file (cpp_slex_lexer.hpp) should be included only once. This allows +// to decouple the lexer interface from the lexer implementation and reduces +// compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// +// The new_lexer_gen<>::new_lexer function (declared in cpp_slex_token.hpp) +// should be defined inline, if the lex_functor shouldn't be instantiated +// separately from the lex_iterator. +// +// Separate (explicit) instantiation helps to reduce compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 +#define BOOST_WAVE_SLEX_NEW_LEXER_INLINE +#else +#define BOOST_WAVE_SLEX_NEW_LEXER_INLINE inline +#endif + +template +BOOST_WAVE_SLEX_NEW_LEXER_INLINE +slex_input_interface > * +new_lexer_gen::new_lexer(IteratorT const &first, + IteratorT const &last, PositionT const &pos, + boost::wave::language_support language) +{ + return new slex::slex_functor(first, last, pos, + language); +} + +#undef BOOST_WAVE_SLEX_NEW_LEXER_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpp_token_sample +} // namespace wave +} // namespace boost + +#endif // !defined(SLEX_LEXER_HPP_5E8E1DF0_BB41_4938_B7E5_A4BB68222FF6_INCLUDED) diff --git a/samples/cpp_tokens/slex/lexer.hpp b/samples/cpp_tokens/slex/lexer.hpp new file mode 100644 index 000000000..7ceacbdae --- /dev/null +++ b/samples/cpp_tokens/slex/lexer.hpp @@ -0,0 +1,2892 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Spirit based lexer + + http://spirit.sourceforge.net/ + + Copyright (c) 2001, Daniel C. Nuffer. + Copyright (c) 2001-2005 Hartmut Kaiser. + 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) + + TODO List: + X callback objects (called when a match is made.) + X callback passed first & last iterator, and + a reference to a lexercontrol object that supports some + operations on the lexer. + set state + terminate + state stack (push, pop, top) + set new token return value + ignore the current token + yymore + get length of matched token + get current lexer state + X DFA serialization to save recomputing the DFA. + + lexer states. + organize the file into hpp and ipp. arrange the classes in a logical order. + use buffering - iterator only needs be an input iterator, + lexer & callback are not templatized on iterator type, but char type. + next_token is templatized on iterator type. + beginning/ending contexts. + ^ and $ + DFA minimization. + DFA table compression. + +=============================================================================*/ +#ifndef BOOST_SPIRIT_LEXER_HPP +#define BOOST_SPIRIT_LEXER_HPP + +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include +#include +#include +#include +#include // for pair +#include +#include +#include + +#if SPIRIT_VERSION < 0x1700 && defined(BOOST_MSVC) && (BOOST_MSVC <= 1300) +#include +#endif + +#if defined(BOOST_NO_STD_ITERATOR_TRAITS) +#define BOOST_SPIRIT_IT_NS impl +#else +#define BOOST_SPIRIT_IT_NS std +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace spirit { + +typedef unsigned char uchar; +typedef unsigned int node_id_t; +const node_id_t invalid_node = node_id_t(-1); +typedef std::set node_set; +typedef std::vector uchar_vector; +typedef std::map followpos_t; +typedef std::vector state_match_t; + +template +class lexer_control; + +class bad_regex : public std::exception +{ +}; + +namespace lexerimpl +{ + +class node +{ +public: + + virtual ~node() {} + + virtual node* clone() const = 0; + virtual bool nullable() const = 0; + virtual node_set firstpos() const = 0; + virtual node_set lastpos() const = 0; + virtual void compute_followpos(followpos_t& followpos) const = 0; + virtual void compute_state_match(state_match_t& state_match) const = 0; + virtual void get_eof_ids(node_set& eof_set) const = 0; + virtual void assign_node_ids(node_id_t& node_count) = 0; +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + virtual void dump(std::ostream& out) const = 0; +#endif + +}; + +class char_node : public node +{ + +public: + + char_node(const uchar c); + char_node(const char_node& x); + virtual ~char_node(){} + + virtual node* clone() const; + virtual bool nullable() const; + virtual node_set firstpos() const; + virtual node_set lastpos() const; + virtual void compute_followpos(followpos_t& followpos) const; + virtual void compute_state_match(state_match_t& state_match ) const; + virtual void get_eof_ids(node_set& eof_set) const; + virtual void assign_node_ids(node_id_t& node_count); +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + virtual void dump(std::ostream& out) const; +#endif + +private: + + uchar m_char; + node_id_t m_node_num; +}; + +inline +char_node::char_node(const uchar c) + : node() + , m_char(c) + , m_node_num(0) +{ +} + +inline +char_node::char_node(const char_node& x) + : node(x) + , m_char(x.m_char) + , m_node_num(x.m_node_num) +{ +} + +inline node * +char_node::clone() const +{ + return new char_node(*this); +} + +inline bool +char_node::nullable() const +{ + return false; +} + +inline node_set +char_node::firstpos() const +{ + node_set rval; + rval.insert(m_node_num); + return rval; +} + +inline node_set +char_node::lastpos() const +{ + return firstpos(); +} + +inline void +char_node::compute_followpos(followpos_t&) const +{ + return; +} + +inline void +char_node::compute_state_match(state_match_t& state_match) const +{ + if (state_match.size() < m_node_num + 1) + state_match.resize(m_node_num + 1); + state_match[m_node_num].resize(256); + state_match[m_node_num][m_char] = 1; +} + +inline void +char_node::get_eof_ids(node_set&) const +{ + return; +} + +inline void +char_node::assign_node_ids(node_id_t& node_count) +{ + m_node_num = node_count++; +} + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) +inline void +char_node::dump(std::ostream& out) const +{ + out << "\nchar_node m_char = " << m_char; + out << " m_node_num = " << m_node_num; + out << " nullable() = " << (nullable() ? "true" : "false"); + out << " firstpos() = "; + node_set fp = firstpos(); + std::copy(fp.begin(), fp.end(), + std::ostream_iterator(out, ",")); + + out << " lastpos() = "; + node_set lp = lastpos(); + std::copy(lp.begin(), lp.end(), + std::ostream_iterator(out, ",")); +} +#endif + + +class epsilon_node : public node +{ + +public: + + epsilon_node(); + epsilon_node(const epsilon_node& x); + virtual ~epsilon_node(){} + + virtual node* clone() const; + virtual bool nullable() const; + virtual node_set firstpos() const; + virtual node_set lastpos() const; + virtual void compute_followpos(followpos_t& followpos) const; + virtual void compute_state_match(state_match_t& state_match ) const; + virtual void get_eof_ids(node_set& eof_set) const; + virtual void assign_node_ids(node_id_t& node_count); +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + virtual void dump(std::ostream& out) const; +#endif + +private: + + node_id_t m_node_num; +}; + +inline +epsilon_node::epsilon_node() + : node() + , m_node_num(0) +{ +} + +inline +epsilon_node::epsilon_node(const epsilon_node& x) + : node(x) + , m_node_num(x.m_node_num) +{ +} + +inline node * +epsilon_node::clone() const +{ + return new epsilon_node(*this); +} + +inline bool +epsilon_node::nullable() const +{ + return true; +} + +inline node_set +epsilon_node::firstpos() const +{ + return node_set(); +} + +inline node_set +epsilon_node::lastpos() const +{ + return node_set(); +} + +inline void +epsilon_node::compute_followpos(followpos_t&) const +{ + return; +} + +inline void +epsilon_node::compute_state_match(state_match_t& state_match) const +{ + if (state_match.size() < m_node_num + 1) + state_match.resize(m_node_num + 1); + state_match[m_node_num].resize(256, 1); +} + +inline void +epsilon_node::get_eof_ids(node_set&) const +{ + return; +} + +inline void +epsilon_node::assign_node_ids(node_id_t& node_count) +{ + m_node_num = node_count++; +} + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) +inline void +epsilon_node::dump(std::ostream& out) const +{ + out << "\nepsilon_node"; + out << " m_node_num = " << m_node_num; + out << " nullable() = " << (nullable() ? "true" : "false"); + out << " firstpos() = "; + node_set fp = firstpos(); + std::copy(fp.begin(), fp.end(), + std::ostream_iterator(out, ",")); + + out << " lastpos() = "; + node_set lp = lastpos(); + std::copy(lp.begin(), lp.end(), + std::ostream_iterator(out, ",")); +} +#endif + + +class or_node : public node +{ + +public: + + or_node(node* left, node* right); + or_node(const or_node& x); + virtual ~or_node(){} + + virtual node* clone() const; + virtual bool nullable() const; + virtual node_set firstpos() const; + virtual node_set lastpos() const; + virtual void compute_followpos(followpos_t& followpos) const; + virtual void compute_state_match(state_match_t& state_match ) const; + virtual void get_eof_ids(node_set& eof_set) const; + virtual void assign_node_ids(node_id_t& node_count); +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + virtual void dump(std::ostream& out) const; +#endif + +private: + + std::auto_ptr m_left; + std::auto_ptr m_right; +}; + +inline +or_node::or_node(node* left, node* right) + : node() + , m_left(left) + , m_right(right) +{ +} + +inline +or_node::or_node(const or_node& x) + : node(x) + , m_left(x.m_left->clone()) + , m_right(x.m_right->clone()) +{ +} + +inline node * +or_node::clone() const +{ + return new or_node(m_left->clone(), m_right->clone()); +} + +inline bool +or_node::nullable() const +{ + return m_left->nullable() || m_right->nullable(); +} + +inline node_set +or_node::firstpos() const +{ + node_set rval; + node_set l = m_left->firstpos(); + node_set r = m_right->firstpos(); + std::set_union(l.begin(), l.end(), r.begin(), r.end(), + std::inserter(rval, rval.begin())); + return rval; +} + +inline node_set +or_node::lastpos() const +{ + node_set rval; + node_set l = m_left->lastpos(); + node_set r = m_right->lastpos(); + std::set_union(l.begin(), l.end(), r.begin(), r.end(), + std::inserter(rval, rval.begin())); + return rval; +} + +inline void +or_node::compute_followpos(followpos_t& followpos) const +{ + m_left->compute_followpos(followpos); + m_right->compute_followpos(followpos); +} + +inline void +or_node::compute_state_match(state_match_t& state_match) const +{ + m_left->compute_state_match(state_match); + m_right->compute_state_match(state_match); +} + +inline void +or_node::get_eof_ids(node_set& eof_nodes) const +{ + m_left->get_eof_ids(eof_nodes); + m_right->get_eof_ids(eof_nodes); +} + +inline void +or_node::assign_node_ids(node_id_t& node_count) +{ + m_left->assign_node_ids(node_count); + m_right->assign_node_ids(node_count); +} + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) +inline void +or_node::dump(std::ostream& out) const +{ + m_left->dump(out); + + out << "\nor_node"; + out << " nullable() = " << (nullable() ? "true" : "false"); + out << " firstpos() = "; + node_set fp = firstpos(); + std::copy(fp.begin(), fp.end(), + std::ostream_iterator(out, ",")); + + out << " lastpos() = "; + node_set lp = lastpos(); + std::copy(lp.begin(), lp.end(), + std::ostream_iterator(out, ",")); + + m_right->dump(out); +} +#endif + + +class cat_node : public node +{ + +public: + + cat_node(node* left, node* right); + cat_node(const cat_node& x); + virtual ~cat_node(){} + + virtual node* clone() const; + virtual bool nullable() const; + virtual node_set firstpos() const; + virtual node_set lastpos() const; + virtual void compute_followpos(followpos_t& followpos) const; + virtual void compute_state_match(state_match_t& state_match ) const; + virtual void get_eof_ids(node_set& eof_set) const; + virtual void assign_node_ids(node_id_t& node_count); +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + virtual void dump(std::ostream& out) const; +#endif + +private: + + std::auto_ptr m_left; + std::auto_ptr m_right; +}; + +inline +cat_node::cat_node(node* left, node* right) + : node() + , m_left(left) + , m_right(right) +{ +} + +inline +cat_node::cat_node(const cat_node& x) + : node(x) + , m_left(x.m_left->clone()) + , m_right(x.m_right->clone()) +{ +} + +inline node * +cat_node::clone() const +{ + return new cat_node(m_left->clone(), m_right->clone()); +} + +inline bool +cat_node::nullable() const +{ + return m_left->nullable() && m_right->nullable(); +} + +inline node_set +cat_node::firstpos() const +{ + if (m_left->nullable()) + { + node_set rval; + node_set l = m_left->firstpos(); + node_set r = m_right->firstpos(); + std::set_union(l.begin(), l.end(), r.begin(), r.end(), + std::inserter(rval, rval.begin())); + return rval; + } + else + { + return m_left->firstpos(); + } +} + +inline node_set +cat_node::lastpos() const +{ + if (m_right->nullable()) + { + node_set rval; + node_set l = m_left->lastpos(); + node_set r = m_right->lastpos(); + std::set_union(l.begin(), l.end(), r.begin(), r.end(), + std::inserter(rval, rval.begin())); + return rval; + } + else + { + return m_right->lastpos(); + } +} + +inline void +cat_node::compute_followpos(followpos_t& followpos) const +{ + node_set l = m_left->lastpos(); + for (node_set::iterator i = l.begin(); + i != l.end(); + ++i) + { + node_set rf = m_right->firstpos(); + followpos[*i].insert(rf.begin(), rf.end()); + } + + m_left->compute_followpos(followpos); + m_right->compute_followpos(followpos); +} + +inline void +cat_node::compute_state_match(state_match_t& state_match) const +{ + m_left->compute_state_match(state_match); + m_right->compute_state_match(state_match); +} + +inline void +cat_node::get_eof_ids(node_set& eof_nodes) const +{ + m_left->get_eof_ids(eof_nodes); + m_right->get_eof_ids(eof_nodes); +} + +inline void +cat_node::assign_node_ids(node_id_t& node_count) +{ + m_left->assign_node_ids(node_count); + m_right->assign_node_ids(node_count); +} + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) +inline void +cat_node::dump(std::ostream& out) const +{ + m_left->dump(out); + + out << "\ncat_node"; + out << " nullable() = " << (nullable() ? "true" : "false"); + out << " firstpos() = "; + node_set fp = firstpos(); + std::copy(fp.begin(), fp.end(), + std::ostream_iterator(out, ",")); + + out << " lastpos() = "; + node_set lp = lastpos(); + std::copy(lp.begin(), lp.end(), + std::ostream_iterator(out, ",")); + + m_right->dump(out); +} +#endif + + +class star_node : public node +{ + +public: + + star_node(node* left); + star_node(const star_node& x); + virtual ~star_node(){} + + virtual node* clone() const; + virtual bool nullable() const; + virtual node_set firstpos() const; + virtual node_set lastpos() const; + virtual void compute_followpos(followpos_t& followpos) const; + virtual void compute_state_match(state_match_t& state_match ) const; + virtual void get_eof_ids(node_set& eof_set) const; + virtual void assign_node_ids(node_id_t& node_count); +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + virtual void dump(std::ostream& out) const; +#endif + +private: + + std::auto_ptr m_left; +}; + +inline +star_node::star_node(node* left) + : node() + , m_left(left) +{ +} + +inline +star_node::star_node(const star_node& x) + : node(x) + , m_left(x.m_left->clone()) +{ +} + +inline node * +star_node::clone() const +{ + return new star_node(m_left->clone()); +} + +inline bool +star_node::nullable() const +{ + return true; +} + +inline node_set +star_node::firstpos() const +{ + return m_left->firstpos(); +} + +inline node_set +star_node::lastpos() const +{ + return m_left->lastpos(); +} + +inline void +star_node::compute_followpos(followpos_t& followpos) const +{ + node_set lp = this->lastpos(); + for (node_set::iterator i = lp.begin(); + i != lp.end(); + ++i) + { + node_set fp = this->firstpos(); + followpos[*i].insert(fp.begin(), fp.end()); + } + + m_left->compute_followpos(followpos); +} + +inline void +star_node::compute_state_match(state_match_t& state_match) const +{ + m_left->compute_state_match(state_match); +} + +inline void +star_node::get_eof_ids(node_set& eof_nodes) const +{ + m_left->get_eof_ids(eof_nodes); +} + +inline void +star_node::assign_node_ids(node_id_t& node_count) +{ + m_left->assign_node_ids(node_count); +} + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) +inline void +star_node::dump(std::ostream& out) const +{ + m_left->dump(out); + + out << "\nstar_node"; + out << " nullable() = " << (nullable() ? "true" : "false"); + out << " firstpos() = "; + node_set fp = firstpos(); + std::copy(fp.begin(), fp.end(), + std::ostream_iterator(out, ",")); + + out << " lastpos() = "; + node_set lp = lastpos(); + std::copy(lp.begin(), lp.end(), + std::ostream_iterator(out, ",")); + +} +#endif + + +class eof_node : public node +{ + +public: + + eof_node(); + eof_node(const eof_node& x); + virtual ~eof_node(){} + + virtual node* clone() const; + virtual bool nullable() const; + virtual node_set firstpos() const; + virtual node_set lastpos() const; + virtual void compute_followpos(followpos_t& followpos) const; + virtual void compute_state_match(state_match_t& state_match ) const; + virtual void get_eof_ids(node_set& eof_set) const; + virtual void assign_node_ids(node_id_t& node_count); +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + virtual void dump(std::ostream& out) const; +#endif + +private: + + node_id_t m_node_num; +}; + +inline +eof_node::eof_node() + : node() + , m_node_num(0) +{ +} + +inline +eof_node::eof_node(const eof_node& x) + : node(x) + , m_node_num(x.m_node_num) +{ +} + +inline node * +eof_node::clone() const +{ + return new eof_node(*this); +} + +inline bool +eof_node::nullable() const +{ + return false; +} + +inline node_set +eof_node::firstpos() const +{ + node_set rval; + rval.insert(m_node_num); + return rval; +} + +inline node_set +eof_node::lastpos() const +{ + node_set rval; + rval.insert(m_node_num); + return rval; +} + +inline void +eof_node::compute_followpos(followpos_t&) const +{ + return; +} + +inline void +eof_node::compute_state_match(state_match_t& state_match) const +{ + if (state_match.size() < m_node_num + 1) + state_match.resize(m_node_num + 1); + state_match[m_node_num].resize(256, 0); +} + +inline void +eof_node::get_eof_ids(node_set& eof_nodes) const +{ + eof_nodes.insert(m_node_num); +} + +inline void +eof_node::assign_node_ids(node_id_t& node_count) +{ + m_node_num = node_count++; +} + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) +inline void +eof_node::dump(std::ostream& out) const +{ + out << "\neof_node"; + out << " m_node_num = " << m_node_num; + out << " nullable() = " << (nullable() ? "true" : "false"); + out << " firstpos() = "; + node_set fp = firstpos(); + std::copy(fp.begin(), fp.end(), + std::ostream_iterator(out, ",")); + + out << " lastpos() = "; + node_set lp = lastpos(); + std::copy(lp.begin(), lp.end(), + std::ostream_iterator(out, ",")); +} +#endif + +class ccl_node : public node +{ + +public: + + ccl_node(const std::vector& v); + ccl_node(const uchar c1, const uchar c2); + ccl_node(const ccl_node& x); + virtual ~ccl_node(){} + + virtual node* clone() const; + virtual bool nullable() const; + virtual node_set firstpos() const; + virtual node_set lastpos() const; + virtual void compute_followpos(followpos_t& followpos) const; + virtual void compute_state_match(state_match_t& state_match ) const; + virtual void get_eof_ids(node_set& eof_set) const; + virtual void assign_node_ids(node_id_t& node_count); +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + virtual void dump(std::ostream& out) const; +#endif + +private: + + std::vector m_match; + node_id_t m_node_num; +}; + +inline +ccl_node::ccl_node(const std::vector& v) + : node() + , m_match(v) + , m_node_num(0) +{ + m_match.resize(256); // make sure it's the right size +} + +inline +ccl_node::ccl_node(const uchar c1, const uchar c2) + : node() + , m_match(256, 0) + , m_node_num(0) +{ + BOOST_SPIRIT_ASSERT(c1 < c2); + for (size_t i = c1; i <= size_t(c2); ++i) + { + m_match[i] = 1; + } +} + +inline +ccl_node::ccl_node(const ccl_node& x) + : node(x) + , m_match(x.m_match) + , m_node_num(x.m_node_num) +{ +} + +inline node * +ccl_node::clone() const +{ + return new ccl_node(*this); +} + +inline bool +ccl_node::nullable() const +{ + return false; +} + +inline node_set +ccl_node::firstpos() const +{ + node_set rval; + rval.insert(m_node_num); + return rval; +} + +inline node_set +ccl_node::lastpos() const +{ + return firstpos(); +} + +inline void +ccl_node::compute_followpos(followpos_t&) const +{ + return; +} + +inline void +ccl_node::compute_state_match(state_match_t& state_match) const +{ + if (state_match.size() < m_node_num + 1) + state_match.resize(m_node_num + 1); + state_match[m_node_num] = m_match; +} + +inline void +ccl_node::get_eof_ids(node_set&) const +{ + return; +} + +inline void +ccl_node::assign_node_ids(node_id_t& node_count) +{ + m_node_num = node_count++; +} + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) +inline void +ccl_node::dump(std::ostream& out) const +{ + out << "\nccl_node m_match = "; + for (size_t i = 0; i < m_match.size(); ++i) + { + if (m_match[i]) + out << i << ", "; + } + out << " m_node_num = " << m_node_num; + out << " nullable() = " << (nullable() ? "true" : "false"); + out << " firstpos() = "; + node_set fp = firstpos(); + std::copy(fp.begin(), fp.end(), + std::ostream_iterator(out, ",")); + + out << " lastpos() = "; + node_set lp = lastpos(); + std::copy(lp.begin(), lp.end(), + std::ostream_iterator(out, ",")); +} +#endif + +template +class make_concat +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + + make_concat(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(iterator_type const &, iterator_type const &) const + { + node* right = m_stack.top(); + m_stack.pop(); + node* left = m_stack.top(); + m_stack.pop(); + node* newnode = new cat_node(left, right); + m_stack.push(newnode); + } + + std::stack& m_stack; +}; + +template +struct get_byte_aux; + +template<> +struct get_byte_aux<1> +{ + template + unsigned char operator()(CharT c, unsigned int byte) + { + BOOST_SPIRIT_ASSERT(byte == 0); + return c; + } +}; + +template<> +struct get_byte_aux<2> +{ + template + unsigned char operator()(CharT c, unsigned int byte) + { + static unsigned long mask[] = + { + 0xFF00, + 0x00FF + }; + + BOOST_SPIRIT_ASSERT(byte < 2); + return (c & mask[byte]) >> ((sizeof(c) - 1 - byte) * 8); + } +}; + +template<> +struct get_byte_aux<4> +{ + template + unsigned char operator()(CharT c, unsigned int byte) + { + static unsigned long mask[] = + { + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF + }; + + BOOST_SPIRIT_ASSERT(byte < 4); + return (c & mask[byte]) >> ((sizeof(c) - 1 - byte) * 8); + } +}; + +template +inline unsigned char +get_byte(CharT c, unsigned int byte) +{ + return get_byte_aux()(c, byte); +} + +template +class make_star +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + make_star(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(const char_t) const + { + node* left = m_stack.top(); + m_stack.pop(); + node* newnode = new star_node(left); + m_stack.push(newnode); + } + + std::stack& m_stack; +}; + +template +class make_or +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + + make_or(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(iterator_type const&, iterator_type const&) const + { + node* right = m_stack.top(); + m_stack.pop(); + node* left = m_stack.top(); + m_stack.pop(); + node* newnode = new or_node(left, right); + m_stack.push(newnode); + } + + std::stack& m_stack; +}; + +template +class make_plus +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + make_plus(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(const char_t) const + { + node* left = m_stack.top(); + m_stack.pop(); + + node* copy = left->clone(); + + node* new_star = new star_node(copy); + node* new_cat = new cat_node(left, new_star); + m_stack.push(new_cat); + } + + std::stack& m_stack; +}; + +template +class make_optional +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + make_optional(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(const char_t) const + { + node* left = m_stack.top(); + m_stack.pop(); + + node* new_or = new or_node(left, new epsilon_node()); + m_stack.push(new_or); + } + + std::stack& m_stack; +}; + +/////////////////////////////////////////////////////////////////////////////// +// utility function +template +inline utility::impl::range const& +full_range() +{ + static utility::impl::range full((std::numeric_limits::min)(), + (std::numeric_limits::max)()); + return full; +} + +namespace ccl_utils +{ + template + inline utility::impl::range_run + negate_range_run( + const utility::impl::range_run& rr) + { + utility::impl::range_run newrr; + newrr.set(full_range()); + for (typename utility::impl::range_run::const_iterator iter = rr.begin(); + iter != rr.end(); ++iter) + newrr.clear(*iter); + return newrr; + } + + template + inline node* + create_mb_node_seq(char_t c) + { + node* newnode = new char_node(get_byte(c, 0)); + for (unsigned int i = 1; i < sizeof(c); ++i) + { + node* cnode = new char_node(get_byte(c, i)); + node* top_node = new cat_node(newnode, cnode); + newnode = top_node; + } + return newnode; + } + + template + inline void + handle_mb_char(char_t c, bool first_time, + std::stack& stack) + { + node* newnode = create_mb_node_seq(c); + + if (first_time) + { + stack.push(newnode); + } + else + { + node* top = stack.top(); + stack.pop(); + + node* newtop = new or_node(top, newnode); + stack.push(newtop); + } + } + + // forward decl only + template + inline void + handle_mb_range(char_t c1, char_t c2, bool first_time, + std::stack& stack); + + template + inline void + create_nodes(const utility::impl::range_run& rr, + std::stack& stack) + { + + if (sizeof(char_t) == 1) + { + std::vector ccl; + ccl.resize(256); + for (typename utility::impl::range_run::const_iterator iter = rr.begin(); + iter != rr.end(); ++iter) + { + for (int i = iter->first; i <= iter->last; ++i) + { + BOOST_SPIRIT_ASSERT(uchar(i) < 256 && ccl.size() == 256); + ccl[uchar(i)] = 1; + } + } + + node* new_ccl = new ccl_node(ccl); + stack.push(new_ccl); + } + else + { + bool mb_first_time = true; + for (typename utility::impl::range_run::const_iterator iter = rr.begin(); + iter != rr.end(); ++iter) + { + if (iter->first == iter->last) + { + handle_mb_char(iter->first, mb_first_time, stack); + } + else + { + handle_mb_range(iter->first, iter->last, mb_first_time, stack); + } + mb_first_time = false; + } + } + } + + template + inline size_t + compute_differing_byte(char_t c1, char_t c2) + { + size_t rval = 0; + while (rval < sizeof(c1) && + get_byte(c1, (unsigned int)rval) == get_byte(c2, (unsigned int)rval)) + { + ++rval; + } + return rval; + } + + template + inline node* + create_mb_node_type1(size_t j, char_t c1, char_t c2) + { + size_t diff = get_byte(c2, (unsigned int)j) - get_byte(c1, (unsigned int)j); + if (diff == 1) { + return 0; + } + else if (diff == 2) { + return new char_node(get_byte(c1, (unsigned int)j)+1); + } + else { + return new ccl_node(get_byte(c1, (unsigned int)j)+1, + get_byte(c2, (unsigned int)j)-1); + } + } + + template + inline node * + create_mb_node_for_byte(size_t i, size_t j, size_t sizem1, + size_t differing_byte, char_t c1, char_t c2, node* newnode) + { + node* cnode; + if (i == sizem1 && j == differing_byte && j != sizem1) + { + node* tmp = create_mb_node_type1(j, c1, c2); + if (tmp == 0) + { + delete newnode; + return 0; + } + else + cnode = tmp; + } + else if (i == differing_byte && j == sizem1) + { + if (i != sizem1) { + cnode = new ccl_node(get_byte(c1, (unsigned int)j), 0xFF); + } + else { + cnode = new ccl_node(get_byte(c1, (unsigned int)j), + get_byte(c2, (unsigned int)j)); + } + } + else if (i != differing_byte && i != sizem1 && + j == (sizem1 - i + differing_byte)) + { + cnode = new ccl_node(get_byte(c1, (unsigned int)j)+1, 0xFF); + } + else if (i + j - differing_byte > sizem1) { + cnode = new ccl_node(0, 0xFF); + } + else {//if (is plain) + cnode = new char_node(get_byte(c1, (unsigned int)j)); + } + + node* top_node = new cat_node(newnode, cnode); + return top_node; + } + +// On platforms, where wchar_t is a typedef for unsigned short, the +// comparision for a negative value is pointless + template + struct correct_char_aux { + }; + + template <> + struct correct_char_aux { + + template + static char_t correct(char_t c) { if (c < 0) c = 0; return c; } + }; + + template <> + struct correct_char_aux { + + template + static char_t correct(char_t c) { return c; } + }; + + template + struct correct_char + { + static char_t correct(char_t c) + { + return correct_char_aux::is_signed >:: + correct(c); + } + }; + + template + inline void + handle_mb_range(char_t c1, char_t c2, bool first_time, + std::stack& stack) + { + // The algorithm can't handle negative value chars, which don't make + // much sense anyway. This comparision is pointless for wchar_t's on + // platforms, where wchar_t is a typedef for unsigned short + + c1 = correct_char::correct(c1); + //if (c1 < 0) + // c1 = 0; + + BOOST_SPIRIT_ASSERT(c1 < c2); + node* newnode = 0; + node* savednode = 0; + const size_t differing_byte = compute_differing_byte(c1, c2); + const size_t sizem1 = sizeof(c1) - 1; + const size_t ndb = sizem1 - differing_byte; + for (size_t i = differing_byte; i < sizeof(c1); ++i) + { + // generate node for the first byte + if (differing_byte == 0 && i == ndb) + { + node* tmp = create_mb_node_type1(0, c1, c2); + if (tmp == 0) + continue; + else + newnode = tmp; + } + else + { + newnode = new char_node(get_byte(c1, 0)); + } + for (size_t j = 1; j < sizeof(c1); ++j) + { + newnode = create_mb_node_for_byte(i, j, sizem1, differing_byte, + c1, c2, newnode); + if (newnode == 0) + goto end_outer_for; + } + + // or together the various parts + if (savednode) + { + node* top_node = new or_node(savednode, newnode); + savednode = top_node; + } + else + { + savednode = newnode; + } +end_outer_for: + continue; + } + + for (size_t k = 0; k < ndb; ++k) + { + newnode = new char_node(get_byte(c2, 0)); + for (size_t j = 1; j < sizeof(c2); ++j) + { + node* cnode; + if (k == differing_byte && j == sizem1 && k != sizem1) + cnode = new ccl_node(0, get_byte(c2, (unsigned int)j)); + + else if (k != differing_byte && k != sizem1 && + j == (sizem1 - k + differing_byte)) + cnode = new ccl_node(0, get_byte(c2, (unsigned int)j)-1); + + else if (k + j - differing_byte > sizem1) + cnode = new ccl_node(0, 0xFF); + + else //if (is plain) + cnode = new char_node(get_byte(c2, (unsigned int)j)); + + + node* top_node = new cat_node(newnode, cnode); + newnode = top_node; + } + + // or together the various parts + if (savednode) + { + node* top_node = new or_node(savednode, newnode); + savednode = top_node; + } + else + { + savednode = newnode; + } + } + + + if (first_time) + { + stack.push(savednode); + } + else + { + node* top = stack.top(); + stack.pop(); + + node* newtop = new or_node(top, savednode); + stack.push(newtop); + } + } +} // namespace ccl_utils + +template +class make_char +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + make_char(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(iterator_type const& first, iterator_type const& last) const + { + const escape_char_parser lex_escape_ch = + escape_char_parser(); + char_t the_char; + iterator_type first_ = first; + ScannerT scan(first_, last); + lex_escape_ch[assign(the_char)].parse(scan); + node* newnode = ccl_utils::create_mb_node_seq(the_char); + m_stack.push(newnode); + } + + std::stack& m_stack; +}; + + +template +class make_ccl +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + make_ccl(std::stack& the_stack) + : m_stack(the_stack) + {} + + static bool is_equal_to_string(iterator_type first, + iterator_type const & last, const char* str) + { + while (first != last &&*str &&*first ==*str) + { + ++first; + ++str; + } + return*str == 0; + } + + template + static void fill_ccl(utility::impl::range_run& rr, const ParserT& parser) + { + for (int i = 0; i < 256; ++i) + { + if (parser.test(static_cast(uchar(i)))) + rr.set(utility::impl::range(i, i)); + } + } + + void operator()(iterator_type const& first_, iterator_type const& last) const + { + BOOST_SPIRIT_ASSERT(*first_ == '['); + + iterator_type first = first_; + ++first; // skip over '[' + bool negated_ccl = false; + if (*first == '^') + { + negated_ccl = true; + ++first; + } + + utility::impl::range_run rr; + while (first != last &&*first != ']') + { + if (*first == '[') // it's a ccl_expr like [:space:] + { + // check for [:space:], etc. + if (is_equal_to_string(first, last, "[:alnum:]")) + { + fill_ccl(rr, alnum_p); + } + else if (is_equal_to_string(first, last, "[:alpha:]")) + { + fill_ccl(rr, alpha_p); + } + else if (is_equal_to_string(first, last, "[:blank:]")) + { + fill_ccl(rr, blank_p); + } + else if (is_equal_to_string(first, last, "[:cntrl:]")) + { + fill_ccl(rr, cntrl_p); + } + else if (is_equal_to_string(first, last, "[:digit:]")) + { + fill_ccl(rr, digit_p); + } + else if (is_equal_to_string(first, last, "[:graph:]")) + { + fill_ccl(rr, graph_p); + } + else if (is_equal_to_string(first, last, "[:lower:]")) + { + fill_ccl(rr, lower_p); + } + else if (is_equal_to_string(first, last, "[:print:]")) + { + fill_ccl(rr, print_p); + } + else if (is_equal_to_string(first, last, "[:punct:]")) + { + fill_ccl(rr, punct_p); + } + else if (is_equal_to_string(first, last, "[:space:]")) + { + fill_ccl(rr, space_p); + } + else if (is_equal_to_string(first, last, "[:upper:]")) + { + fill_ccl(rr, upper_p); + } + else if (is_equal_to_string(first, last, "[:xdigit:]")) + { + fill_ccl(rr, xdigit_p); + } + // this can't happen, because it's parsed before we get here. + //else + // throw bad_regex(); + + // Advance past the character class expression + while (first != last &&*first != ']') + ++first; + BOOST_SPIRIT_ASSERT(*first == ']'); + ++first; + } + else { + const escape_char_parser lex_escape_ch = + escape_char_parser(); + + char_t c1; + ScannerT scan(first, last); + lex_escape_ch[assign(c1)].parse(scan); + if (*scan.first == '-') // insert a range + { + ++scan.first; + char_t c2; + lex_escape_ch[assign(c2)].parse(scan); + BOOST_SPIRIT_ASSERT(c1 < c2); // Throw exception? + rr.set(utility::impl::range(c1, c2)); + } + else // insert 1 char + { + rr.set(utility::impl::range(c1, c1)); + } + } + } + + if (negated_ccl) + { + rr = ccl_utils::negate_range_run(rr); + } + + ccl_utils::create_nodes(rr, m_stack); + } + + std::stack& m_stack; +}; + +template +class make_any_char +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + std::stack& m_stack; + + make_any_char(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(const char_t c) const + { + BOOST_SPIRIT_ASSERT(c == '.'); + do_any_char(); + } + + void do_any_char() const + { + static utility::impl::range_run rr; + rr.set(full_range()); + char_t newline = '\n'; + rr.clear(utility::impl::range(newline, newline)); + + ccl_utils::create_nodes(rr, m_stack); + } +}; + +template +class make_string +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + std::stack& m_stack; + + make_string(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(iterator_type const& first, iterator_type const& last) const + { + BOOST_SPIRIT_ASSERT(*first == '"'); + + iterator_type first_ = first; + ScannerT scan(first_, last); + ++scan.first; // skip over '"' + + // empty string not allowed + if (*scan.first == '"') + { + throw bad_regex(); + } + + const escape_char_parser lex_escape_ch = + escape_char_parser(); + + char_t c; + lex_escape_ch[assign(c)].parse(scan); + node* top_node = ccl_utils::create_mb_node_seq(c); + + while (*scan.first != '"' && scan.first != scan.last) + { + lex_escape_ch[assign(c)].parse(scan); + node* cur_node = ccl_utils::create_mb_node_seq(c); + top_node = new cat_node(top_node, cur_node); + } + m_stack.push(top_node); + } +}; + +inline +node* repeat_node(node* n, int num) +{ + node* list_of_nodes = n; + for (int i = 1; i < num; ++i) + { + list_of_nodes = new cat_node(list_of_nodes, n->clone()); + } + return list_of_nodes; +} + +inline +node* optional_node(node* n) +{ + return new or_node(n, new epsilon_node()); +} + +template +class make_rep1 +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + std::stack& m_stack; + + make_rep1(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(iterator_type const& first, iterator_type const& last) const + { + BOOST_SPIRIT_ASSERT(*first == '{'); + + iterator_type first_ = first; + ScannerT scan(first_, last); + ++scan.first; // skip over '{' + + unsigned int count; + uint_p[assign(count)].parse(scan); + if (count == 0) + throw bad_regex(); + + node* top_node = m_stack.top(); + m_stack.pop(); + top_node = repeat_node(top_node, count); + m_stack.push(top_node); + } +}; + +template +class make_rep2 +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + std::stack& m_stack; + + make_rep2(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(iterator_type const& first, iterator_type const& last) const + { + BOOST_SPIRIT_ASSERT(*first == '{'); + + iterator_type first_ = first; + ScannerT scan (first_, last); + ++scan.first; // skip over '{' + + unsigned int count; + uint_p[assign(count)].parse(scan); + if (count == 0) + throw bad_regex(); + + node* top_node = m_stack.top(); + m_stack.pop(); + top_node = new cat_node(repeat_node(top_node, count), + new star_node(top_node->clone())); + m_stack.push(top_node); + + } +}; + +template +class make_rep3 +{ + typedef typename ScannerT::iterator_t iterator_type; + +public: + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + std::stack& m_stack; + + make_rep3(std::stack& the_stack) + : m_stack(the_stack) + {} + + void operator()(iterator_type const& first, iterator_type const& last) const + { + BOOST_SPIRIT_ASSERT(*first == '{'); + + iterator_type first_ = first; + ScannerT scan(first_, last); + ++scan.first; // skip over '{' + + unsigned int count1, count2; + uint_p[assign(count1)].parse(scan); + if (count1 == 0) + throw bad_regex(); + + ++scan.first; // skip over ',' + + uint_p[assign(count2)].parse(scan); + if (count2 <= count1) + throw bad_regex(); + + node* top_node = m_stack.top(); + m_stack.pop(); + node* repeats = repeat_node(top_node, count1); + top_node = new cat_node(repeats, + repeat_node(optional_node(top_node->clone()), + count2 - count1)); + + m_stack.push(top_node); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Lexer grammar +// +// Defines the grammar, which mandates the syntax of the understood +// lexeme definitions passed to lexer::register_regex. +// +/////////////////////////////////////////////////////////////////////////////// +class lexer_grammar : public boost::spirit::grammar +{ +public: + lexer_grammar(std::stack &node_stack_) + : node_stack(node_stack_) {} + + template + struct definition + { + typedef rule rule_t; + typedef typename ScannerT::iterator_t iterator_type; + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + rule_t regex, re, series, singleton, singleton2, fullccl, ccl, string, + escseq, ccl_char; + symbols<> ccl_expr; + + definition(lexer_grammar const &self) + { + regex = + re >> !('/' >> re) >> !ch_p('$') + ; + + re = + series + >>*( ('|' >> series)[make_or(self.node_stack)] ) + ; + + series = + singleton + >>*( singleton[make_concat(self.node_stack)] ) + ; + + singleton = + ch_p('.')[make_any_char(self.node_stack)] + >> singleton2 + | fullccl + >> singleton2 + | ('"' >> string >> '"') + [ + make_string(self.node_stack) + ] + >> singleton2 + | '(' >> re >> ')' + >> singleton2 + | ((anychar_p - chset<>("/|*+?.(){}\\")) | escseq) + [ + make_char(self.node_stack) + ] + >> singleton2 + ; + + singleton2 = + ch_p('*')[make_star(self.node_stack)] + >> singleton2 + | ch_p('+')[make_plus(self.node_stack)] + >> singleton2 + | ch_p('?')[make_optional(self.node_stack)] + >> singleton2 + | ('{' >> uint_p >> '}') + [ + make_rep1(self.node_stack) + ] + >> singleton2 + | ('{' >> uint_p >> ',' >> '}') + [ + make_rep2(self.node_stack) + ] + >> singleton2 + | ('{' >> uint_p >> ',' >> uint_p >> '}') + [ + make_rep3(self.node_stack) + ] + >> singleton2 + | epsilon_p + ; + + fullccl = + ('[' >> !ch_p('^') >> ccl >> ']') + [ + make_ccl(self.node_stack) + ] + ; + + ccl = + *(ccl_expr | (ccl_char >> !('-' >> ccl_char))) + ; + + ccl_char = + ( (anychar_p - chset<>("\\\n]")) | escseq ) + ; + + ccl_expr = + "[:alnum:]", + "[:alpha:]", + "[:blank:]", + "[:cntrl:]", + "[:digit:]", + "[:graph:]", + "[:lower:]", + "[:print:]", + "[:punct:]", + "[:space:]", + "[:upper:]", + "[:xdigit:]" + ; + + string = + +( (anychar_p - chset<>("\"\\")) | escseq ) + ; + + typedef + uint_parser::digits / 3 + 1 + > oct_parser_t; + typedef + uint_parser::digits / 4 + 1 + > hex_parser_t; + + escseq = + ch_p('\\') + >> ( + oct_parser_t() + | as_lower_d['x'] >> hex_parser_t() + | (anychar_p - chset<>('\n')) + ) + ; + +#define BOOST_SLEX_DEBUG (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + + BOOST_SPIRIT_DEBUG_TRACE_RULE(regex, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(re, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(series, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(singleton, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(singleton2, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(fullccl, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ccl, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(string, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(escseq, BOOST_SLEX_DEBUG); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ccl_char, BOOST_SLEX_DEBUG); + +#undef BOOST_SLEX_DEBUG + } + + rule const& + start() const { return regex; } + }; + + std::stack &node_stack; + +}; // class lexer_grammar + +template +inline node * +parse(lexer_grammar& g, StringT const& str) +{ + typedef + scanner > + scanner_t; + typedef typename rule::template result::type + result_t; + + typename StringT::const_iterator first = str.begin(); + typename StringT::const_iterator last = str.end(); + + scanner_t scan(first, last); +// typename rule::result_t hit = g.parse(scan); + result_t hit = g.parse(scan); + if (!hit || !scan.at_end()) + { + while (g.node_stack.size()) + { + delete g.node_stack.top(); + g.node_stack.pop(); + } + return 0; + } + + BOOST_SPIRIT_ASSERT(g.node_stack.size() == 1); + node* rval = g.node_stack.top(); + g.node_stack.pop(); + node* an_eof_node = new eof_node(); + rval = new cat_node(rval, an_eof_node); + return rval; +} + +inline +void make_case_insensitive(state_match_t& state_match) +{ + // TODO: Fix this. + // This doesn't take into account foreign languages, figure out how to + // do that. Also this approach is broken for this implementation of + // wide chars. + for (state_match_t::iterator iter = state_match.begin(); + iter != state_match.end(); ++iter) + { + int i, j; + for (i = 'A', j = 'a'; i <= 'Z'; ++i, ++j) + { + // if either is set, turn them both on + (*iter)[i] = (*iter)[j] = (*iter)[i] | (*iter)[j]; + } + } +} + +template +struct regex_match_helper; + +template<> +struct regex_match_helper // single byte char +{ + template + static bool + do_match(DfaT const& dfa, IteratorT &first, IteratorT const& last, + int& regex_index, + std::basic_string< + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + > *token) + { + typedef std::basic_string< + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + > string_type; + + node_id_t s = 0; + node_id_t last_accepting_index = invalid_node; + IteratorT p = first; + IteratorT last_accepting_cpos = first; + while (p != last) + { + s = dfa.transition_table[s][(uchar)*p]; + if (s == invalid_node) + break; + if (token) token->append((string_type::size_type)1, *p); + ++p; + if (dfa.acceptance_index[s] != invalid_node) + { + last_accepting_index = s; + last_accepting_cpos = p; + } + } + if (last_accepting_index != invalid_node) + { +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + std::cout << "dfa.acceptance_index[" << last_accepting_index << "] = " << + dfa.acceptance_index[last_accepting_index] << '\n'; +#endif + + first = last_accepting_cpos; + regex_index = dfa.acceptance_index[last_accepting_index]; + return true; + } + else + return false; + } +}; + +template<> +struct regex_match_helper // wide char +{ + template + static bool + do_match(DfaT const& dfa, IteratorT &first, IteratorT const& last, + int& regex_index, + std::basic_string< + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + > *token) + { + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + typedef std::basic_string string_type; + + node_id_t s = 0; + node_id_t last_accepting_index = invalid_node; + IteratorT wp = first; + IteratorT last_accepting_cpos = first; + + while (wp != last) + { + for (unsigned int i = 0; i < sizeof(char_t); ++i) + { + s = dfa.transition_table[s][get_byte(*wp,i)]; + if (s == invalid_node) + { + goto break_while; + } + } + if (token) token->append((string_type::size_type)1, *wp); + ++wp; + if (dfa.acceptance_index[s] != invalid_node) + { + last_accepting_index = s; + last_accepting_cpos = wp; + } + + } + + break_while: + if (last_accepting_index != invalid_node) + { +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + std::cout << "dfa.acceptance_index[" << last_accepting_index << "] = " << + dfa.acceptance_index[last_accepting_index] << '\n'; +#endif + first = last_accepting_cpos; + regex_index = dfa.acceptance_index[last_accepting_index]; + + return true; + } + else + return false; + } +}; + +template +struct regex_match +{ + static bool + do_match(DfaT const& dfa, IteratorT &first, IteratorT const& last, + int& regex_index, + std::basic_string< + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + > *token) + { + return regex_match_helper::do_match( + dfa, first, last, regex_index, token); + } +}; + +} // namespace lexerimpl + +/////////////////////////////////////////////////////////////////////////////// +// +template &)> +class lexer +{ +public: + typedef CallbackT callback_t; + typedef + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + char_t; + + struct regex_info + { + std::basic_string str; + TokenT token; + CallbackT callback; + + regex_info(const std::basic_string& _str, + const TokenT& _token, + const CallbackT& _callback) + : str(_str) + , token(_token) + , callback(_callback) + {} + + }; + + struct dfa_table + { + std::vector > transition_table; + std::vector acceptance_index; + }; + typedef std::vector node_table_t; + typedef std::vector transition_table_t; + typedef std::vector dfa_t; + + + lexer(unsigned int states = 1); + + void register_regex(const std::basic_string& regex, + const TokenT& id, const CallbackT& cb = CallbackT(), + unsigned int state = 0); + + TokenT next_token(IteratorT &first, IteratorT const &last, + std::basic_string *token = 0); + + void create_dfa(); + bool has_compiled_dfa() { return m_compiled_dfa; } + + void set_case_insensitive(bool insensitive); + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + void dump(std::ostream& out); +#endif + typedef std::vector > regex_list_t; + + bool load (std::ifstream &in, long unique_id = 0); + bool save (std::ofstream &out, long unique_id = 0); + enum { + SLEX_SIGNATURE = 0x58454C53, // "SLEX" + SLEX_VERSION_100 = 0x0100, // persistance version + SLEX_LAST_KNOWN_VERSION = SLEX_VERSION_100, + SLEX_MINOR_VERSION_MASK = 0xFF + }; + +private: + + void create_dfa_for_state(int state); + + static bool regex_match(const dfa_t& dfa, IteratorT& first, + IteratorT& last, int& regex_index); + + mutable std::stack node_stack; + lexerimpl::lexer_grammar g; + + mutable bool m_compiled_dfa; + mutable dfa_t m_dfa; + + regex_list_t m_regex_list; + bool m_case_insensitive; + + unsigned int m_state; + std::stack m_state_stack; + unsigned int m_num_states; +}; + + +template +inline +lexer::lexer(unsigned int states) + : g(node_stack) + , m_compiled_dfa(false) + , m_regex_list(states) + , m_case_insensitive(false) + , m_state(0) + , m_state_stack() + , m_num_states(states) +{ + BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME(g, "slex::lexer", + BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX); +} + +template +inline void +lexer::register_regex( + const std::basic_string& regex, const TokenT& id, + const CallbackT& callback, unsigned int state) +{ + if (state > m_num_states) { + m_regex_list.resize(state); + m_num_states = state; + } + m_regex_list[state].push_back(regex_info(regex, id, callback)); +} + +template +inline TokenT +lexer::next_token( + IteratorT &first, IteratorT const& last, + std::basic_string< + typename BOOST_SPIRIT_IT_NS::iterator_traits::value_type + > *token) +{ + if (!m_compiled_dfa) + { + create_dfa(); + } + + IteratorT saved = first; + int regex_index; + if (!lexerimpl::regex_match 1)>:: + do_match(m_dfa[m_state], first, last, regex_index, token)) + return -1; // TODO: can't return -1, need to return some invalid token. + // how to figure this out? We can use traits I guess. + else + { + regex_info regex = m_regex_list[m_state][regex_index]; + TokenT rval = regex.token; + if (regex.callback) + { + // execute corresponding callback + lexer_control controller(rval, m_state, m_state_stack); + regex.callback(saved, first, last, regex.token, controller); + if (controller.ignore_current_token_set()) { + if (token) + token->erase(); + return next_token(first, last, token); + } + } + return rval; + } +} + +namespace lexerimpl +{ + +inline +bool find_acceptance_state(const node_set& eof_node_ids, + const node_set& current_set, + node_id_t& acceptance_node_id) +{ + for(node_set::const_iterator nsi = eof_node_ids.begin(); + nsi != eof_node_ids.end(); ++nsi) + { + node_id_t eof_node_id =*nsi; + if (current_set.end() != current_set.find(eof_node_id)) + { + // store the first one we come to as the + // matched pattern + acceptance_node_id = eof_node_id; + // don't bother searching for more + return true; + } + } + return false; +} + +template +inline std::auto_ptr +parse_regexes(const RegexListT& regex_list, GrammarT& g) +{ + // parse the expressions into a tree + if (regex_list.begin() == regex_list.end()) + throw bad_regex(); + + typename RegexListT::const_iterator ri = regex_list.begin(); + std::auto_ptr tree(lexerimpl::parse(g, (*ri).str)); + if (tree.get() == 0) + throw bad_regex(); + + ++ri; + for (/**/; ri != regex_list.end(); ++ri) + { + std::auto_ptr next_tree(lexerimpl::parse(g, (*ri).str)); + if (next_tree.get() == 0) + throw bad_regex(); + std::auto_ptr newnode(new or_node(tree.release(), next_tree.release())); + tree = newnode; + } + return tree; +} + +} //namespace lexerimpl + +template +inline void +lexer::create_dfa() +{ + m_dfa.resize(m_num_states); + for (unsigned int i = 0; i < m_num_states; ++i) + create_dfa_for_state(i); +} + +// Algorithm from Compilers: Principles, Techniques, and Tools p. 141 +template +inline void +lexer::create_dfa_for_state(int state) +{ + using lexerimpl::node; + std::auto_ptr tree = lexerimpl::parse_regexes(m_regex_list[state], g); + node_id_t dummy = 0; + tree->assign_node_ids(dummy); + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) + tree->dump(std::cout); +#endif + + // compute followpos(root) + followpos_t followpos; + tree->compute_followpos(followpos); + + // the dfa states <-> nfa state groups + std::map dstates1; + std::map dstates2; + + // the dfa transitions + m_dfa[state].transition_table.push_back( + std::vector(256, invalid_node)); + m_dfa[state].acceptance_index.push_back(invalid_node); + + // whether the dfa state has been processed yet + std::vector marked; + + // used to give a unique id to each dfa state + node_id_t num_states = 0; + + // initially, the only unmarked state in Dstates is firstpos(root). + marked.push_back(0); + node_set fpr = tree->firstpos(); + dstates1[fpr] = 0; + dstates2[0] = fpr; + state_match_t state_match; + tree->compute_state_match(state_match); + + if (m_case_insensitive) + lexerimpl::make_case_insensitive(state_match); + + node_set eof_node_ids; + tree->get_eof_ids(eof_node_ids); + // translate the eof_node_ids into a 0-based index + std::map eof_node_id_map; + unsigned int x = 0; + for (node_set::iterator node_id_it = eof_node_ids.begin(); + node_id_it != eof_node_ids.end(); + ++node_id_it) + { + eof_node_id_map[*node_id_it] = x++; + } + + // figure out if this is an acceptance state + node_id_t eof_node_id; + if (lexerimpl::find_acceptance_state(eof_node_ids, fpr, eof_node_id)) + { + m_dfa[state].acceptance_index[0] = eof_node_id_map[eof_node_id]; + } + + std::vector::iterator i = std::find(marked.begin(), marked.end(), + node_id_t(0)); + while (marked.end() != i) + { + *i = 1; + node_id_t T = node_id_t(std::distance(marked.begin(), i)); + BOOST_SPIRIT_ASSERT(T < dstates2.size()); + node_set Tstates = dstates2[T]; + for (node_id_t j = 0; j < 256; ++j) + { + node_set U; + for (node_set::iterator k = Tstates.begin(); + k != Tstates.end(); ++k) + { + node_id_t p =*k; + BOOST_SPIRIT_ASSERT(p < state_match.size()); + BOOST_SPIRIT_ASSERT(j < state_match[p].size()); + if (state_match[p][j]) + { + node_set fpp = followpos[p]; + U.insert(fpp.begin(), fpp.end()); + } + } + if (U.size() > 0) + { + std::map::iterator l = dstates1.find(U); + node_id_t target_state; + if (l == dstates1.end()) // not in the states yet + { + ++num_states; + dstates1[U] = target_state = num_states; + dstates2[target_state] = U; + marked.push_back(0); + m_dfa[state].transition_table.push_back( + std::vector(256, invalid_node)); + m_dfa[state].acceptance_index.push_back(invalid_node); + // figure out if this is an acceptance state + node_id_t eof_node_id; + if (lexerimpl::find_acceptance_state(eof_node_ids, U, eof_node_id)) + { + m_dfa[state].acceptance_index[target_state] = + eof_node_id_map[eof_node_id]; + } + } + else + { + target_state = dstates1[U]; + } + + BOOST_SPIRIT_ASSERT(T < m_dfa[state].transition_table.size()); + BOOST_SPIRIT_ASSERT(j < m_dfa[state].transition_table[T].size()); + m_dfa[state].transition_table[T][j] = target_state; + } + + } + + i = std::find(marked.begin(), marked.end(), node_id_t(0)); + } + m_compiled_dfa = true; +} + +template +inline void +lexer::set_case_insensitive(bool insensitive) +{ + m_case_insensitive = insensitive; +} + + +#if defined(BOOST_SPIRIT_DEBUG) && (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_SLEX) +template +inline void +lexer::dump(std::ostream& out) +{ + for (unsigned x = 0; x < m_dfa.size(); ++x) + { + out << "\nm_dfa[" << x << "] has " << m_dfa[x].transition_table.size() << " states\n"; + for (node_id_t i = 0; i < m_dfa[x].transition_table.size(); ++i) + { + out << "state " << i << ":"; + for (node_id_t j = 0; j < m_dfa[x].transition_table[i].size(); ++j) + { + if (m_dfa[x].transition_table[i][j] != invalid_node) + out << j << "->" << m_dfa[x].transition_table[i][j] << " "; + } + out << "\n"; + } + out << "acceptance states: "; + for(unsigned int k = 0; k < m_dfa[x].acceptance_index.size(); ++k) + { + if (m_dfa[x].acceptance_index[k] != invalid_node) + out << '<' << k << ',' << m_dfa[x].acceptance_index[k] << "> "; + } + out << endl; + } +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// load the lexer tables +#define slex_in(strm, val) \ + strm.read((char*)&val, sizeof(val)); \ + if (std::ios::goodbit != strm.rdstate()) return false + +template +inline bool +lexer::load (std::ifstream &in, long unique_id) +{ +// ensure correct signature and version +long signature = 0; + + slex_in (in, signature); + if (signature != SLEX_SIGNATURE) + return false; // not for us + +long version = 0; + + slex_in (in, version); + if ((version & ~SLEX_MINOR_VERSION_MASK) > SLEX_LAST_KNOWN_VERSION) + return false; // to new for us + +long uid = 0; + + slex_in (in, uid); + if (uid != unique_id) + return false; // not saved by us + +// load auxiliary members +int num_states = 0; + + slex_in (in, num_states); + +// load the dfa tables +dfa_t in_dfa; +size_t dfa_size = 0; + + slex_in (in, dfa_size); + in_dfa.resize(dfa_size); + for (size_t dfa = 0; dfa < dfa_size; ++dfa) + { + // load the transition tables + size_t tt_size = 0; + transition_table_t &tt_table = in_dfa[dfa].transition_table; + + slex_in (in, tt_size); + tt_table.resize(tt_size); + for (size_t tt = 0; tt < tt_size; ++tt) + { + size_t nt_size = 0; + node_table_t &nt_table = tt_table[tt]; + + slex_in (in, nt_size); + nt_table.resize(nt_size); + for (size_t nt = 0; nt < nt_size; ++nt) + { + slex_in (in, nt_table[nt]); + } + } + + // load the acceptance index table + size_t ai_size = 0; + node_table_t &ai_table = in_dfa[dfa].acceptance_index; + + slex_in (in, ai_size); + ai_table.resize(ai_size); + for (size_t ai = 0; ai < ai_size; ++ai) + { + slex_in (in, ai_table[ai]); + } + } + + m_dfa.swap(in_dfa); // success, swap in the read values + m_num_states = num_states; + + m_compiled_dfa = true; + return true; +} + +#undef slex_in + +/////////////////////////////////////////////////////////////////////////////// +// save the lexer tables +#define slex_out(strm, val) \ + strm.write((char*)&val, sizeof(val)); \ + if (std::ios::goodbit != strm.rdstate()) return false + +template +inline bool +lexer::save (std::ofstream &out, long unique_id) +{ +// save signature and version information +long out_long = SLEX_SIGNATURE; + + slex_out(out, out_long); + out_long = SLEX_VERSION_100; + slex_out(out, out_long); + slex_out(out, unique_id); + +// save auxiliary members + slex_out(out, m_num_states); + +// save the dfa tables + typedef typename dfa_t::const_iterator dfa_iter_t; + typedef transition_table_t::const_iterator transition_table_iter_t; + typedef node_table_t::const_iterator node_table_iter_t; + + size_t out_size_t = m_dfa.size(); + slex_out(out, out_size_t); + + dfa_iter_t end = m_dfa.end(); + for (dfa_iter_t it = m_dfa.begin(); it != end; ++it) + { + // save the transition table + out_size_t = (*it).transition_table.size(); + slex_out(out, out_size_t); + + transition_table_iter_t tt_end = (*it).transition_table.end(); + for (transition_table_iter_t tt_it = (*it).transition_table.begin(); + tt_it != tt_end; + ++tt_it) + { + out_size_t = (*tt_it).size(); + slex_out(out, out_size_t); + + node_table_iter_t nt_end = (*tt_it).end(); + for (node_table_iter_t nt_it = (*tt_it).begin(); + nt_it != nt_end; + ++nt_it) + { + slex_out(out, (*nt_it)); + } + } + + // save the acceptance index table + out_size_t = (*it).acceptance_index.size(); + slex_out(out, out_size_t); + + node_table_iter_t nt_end = (*it).acceptance_index.end(); + for (node_table_iter_t nt_it = (*it).acceptance_index.begin(); + nt_it != nt_end; + ++nt_it) + { + slex_out(out, (*nt_it)); + } + } + return true; +} + +#undef slex_out + +/* +a lexer_control object supports some operations on the lexer. + get current lexer state + set state + terminate + state stack (push, pop, top) + set new token return value + ignore the current token + yymore + get length of matched token +*/ +template +class lexer_control +{ +public: + + lexer_control(TokenT& token, unsigned int& current_state, + std::stack& state_stack); + // functions dealing with the lexer state + + // set the state to state + void set_state(unsigned int state); + + // get the current state + unsigned int get_state(); + + // pushes the current state onto the top of the state stack and + // switches to new_state + void push_state(unsigned int new_state); + + // pops the top of the state stack and switches to it. + void pop_state(); + + // returns the top of the stack without altering the stack's contents. + unsigned int top_state(); + + // functions dealing with the token returned. + + // set a new TokenT return value, overriding that one that was + // registered via. register_regex() + void set_token(const TokenT& token); + + // tell the lexer to return an invalid token, signifying termination. + void terminate(); + + // ignore the current token, and move on to the next one. The current + // token will NOT be returned from next_token() + void ignore_current_token(); + + // returns true if ignore_current_token() has been called, + // false otherwise. + bool ignore_current_token_set(); + +private: + TokenT& m_token; + bool m_ignore_current_token; + unsigned int& m_current_state; + std::stack& m_state_stack; +}; + +template +inline +lexer_control::lexer_control(TokenT& token, unsigned int& current_state, + std::stack& state_stack) + : m_token(token) + , m_ignore_current_token(false) + , m_current_state(current_state) + , m_state_stack(state_stack) +{ +} + +template +inline void +lexer_control::set_state(unsigned int state) +{ + m_current_state = state; +} + +template +inline unsigned int +lexer_control::get_state() +{ + return m_current_state; +} + +template +inline void +lexer_control::push_state(unsigned int new_state) +{ + m_state_stack.push(m_current_state); + m_current_state = new_state; +} + +template +inline void +lexer_control::pop_state() +{ + m_current_state = m_state_stack.top(); + m_state_stack.pop(); +} + +template +inline unsigned int +lexer_control::top_state() +{ + return m_state_stack.top(); +} + +template +inline void +lexer_control::set_token(const TokenT& token) +{ + m_token = token; +} + +template +inline void +lexer_control::terminate() +{ + m_token = -1; // TOOD: fix this, need to be determined by traits +} + +template +inline void +lexer_control::ignore_current_token() +{ + m_ignore_current_token = true; +} + +template +inline bool +lexer_control::ignore_current_token_set() +{ + return m_ignore_current_token; +} + +} // namespace spirit +} // namespace boost + +#undef BOOST_SPIRIT_IT_NS + +#endif + diff --git a/samples/cpp_tokens/slex_interface.hpp b/samples/cpp_tokens/slex_interface.hpp new file mode 100644 index 000000000..6e34a6b21 --- /dev/null +++ b/samples/cpp_tokens/slex_interface.hpp @@ -0,0 +1,81 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the abstract lexer interface + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(SLEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED) +#define SLEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpp_token_sample { + +/////////////////////////////////////////////////////////////////////////////// +// +// new_lexer_gen: generates a new instance of the required C++ lexer +// +/////////////////////////////////////////////////////////////////////////////// +template struct slex_input_interface; + +template < + typename IteratorT, + typename PositionT = boost::wave::util::file_position_type +> +struct new_lexer_gen +{ +// The NewLexer function allows the opaque generation of a new lexer object. +// It is coupled to the token type to allow to decouple the lexer/token +// configurations at compile time. + static slex_input_interface > * + new_lexer(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// The lex_input_interface decouples the lex_iterator_shim from the actual +// lexer. This is done to allow compile time reduction. +// Thanks to JCAB for having this idea. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct slex_input_interface +{ + typedef typename TokenT::position_type position_type; + + virtual TokenT get() = 0; + virtual void set_position(position_type const &pos) = 0; + + virtual ~slex_input_interface() {} + +// The new_lexer function allows the opaque generation of a new lexer object. +// It is coupled to the token type to allow to distinguish different +// lexer/token configurations at compile time. + template + static slex_input_interface * + new_lexer(IteratorT const &first, IteratorT const &last, + position_type const &pos, boost::wave::language_support language) + { + return new_lexer_gen::new_lexer (first, last, + pos, language); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpp_token_sample +} // namespace wave +} // namespace boost + +#endif // !defined(SLEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED) diff --git a/samples/cpp_tokens/slex_iterator.hpp b/samples/cpp_tokens/slex_iterator.hpp new file mode 100644 index 000000000..f1e446d7f --- /dev/null +++ b/samples/cpp_tokens/slex_iterator.hpp @@ -0,0 +1,137 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the lexer iterator + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(SLEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED) +#define SLEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "slex_interface.hpp" + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpp_token_sample { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_iterator_functor_shim +// +/////////////////////////////////////////////////////////////////////////////// + +template +class slex_iterator_functor_shim +{ +public: + template + slex_iterator_functor_shim(IteratorT const &first, IteratorT const &last, + typename TokenT::position_type const &pos, + boost::wave::language_support language) + : functor_ptr(slex_input_interface + ::new_lexer(first, last, pos, language)) + {} + +// interface to the boost::spirit::multi_pass_policies::functor_input policy + typedef TokenT result_type; + + /*static*/ result_type const eof; + + result_type operator()() + { + BOOST_ASSERT(0 != functor_ptr.get()); + return functor_ptr->get(); + } + void set_position(typename TokenT::position_type const &pos) + { + BOOST_ASSERT(0 != functor_ptr.get()); + functor_ptr->set_position(pos); + } + +private: + boost::shared_ptr > functor_ptr; +}; + +/////////////////////////////////////////////////////////////////////////////// +// eof token +//template +//typename slex_iterator_functor_shim::result_type const +// slex_iterator_functor_shim::eof = +// typename slex_iterator_functor_shim::result_type(); + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// +// slex_iterator +// +// A generic C++ lexer interface class, which allows to plug in different +// lexer implementations (template parameter LexT). The following +// requirement apply: +// +// - the lexer type should have a function implemented, which returnes +// the next lexed token from the input stream: +// typename LexT::token_type get(); +// - at the end of the input stream this function should return the +// eof token equivalent +// - the lexer should implement a constructor taking two iterators +// pointing to the beginning and the end of the input stream and +// a third parameter containing the name of the parsed input file, +// the 4th parameter contains the information about the mode the +// preprocessor is used in (C99/C++ mode etc.) +// +/////////////////////////////////////////////////////////////////////////////// + +template +class slex_iterator +: public boost::spirit::multi_pass< + impl::slex_iterator_functor_shim, + boost::wave::util::functor_input + > +{ + typedef impl::slex_iterator_functor_shim input_policy_type; + typedef + boost::spirit::multi_pass + base_t; + typedef slex_iterator self_type; + +public: + typedef TokenT token_type; + + slex_iterator() + {} + + template + slex_iterator(IteratorT const &first, IteratorT const &last, + typename TokenT::position_type const &pos, + boost::wave::language_support language) + : base_t(input_policy_type(first, last, pos, language)) + {} +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpp_token_sample +} // namespace wave +} // namespace boost + +#endif // !defined(SLEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED) diff --git a/samples/cpp_tokens/slex_token.hpp b/samples/cpp_tokens/slex_token.hpp new file mode 100644 index 000000000..84ca6a349 --- /dev/null +++ b/samples/cpp_tokens/slex_token.hpp @@ -0,0 +1,115 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + A generic C++ lexer token definition + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(SLEX_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED) +#define SLEX_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED + +#include + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpp_token_sample { + +/////////////////////////////////////////////////////////////////////////////// +// forward declaration of the token type +template +class slex_token; + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_token +// +/////////////////////////////////////////////////////////////////////////////// + +template +class slex_token +{ +public: + typedef BOOST_WAVE_STRINGTYPE string_type; + typedef PositionT position_type; + + slex_token() + : id(T_EOI) + {} + + slex_token(token_id id_, string_type const &value_, PositionT const &pos_) + : id(id_), value(value_), pos(pos_) + {} + +// accessors + operator token_id() const { return id; } + string_type const &get_value() const { return value; } + position_type const &get_position() const { return pos; } + void set_token_id (token_id id_) { id = id_; } + void set_value (string_type const &newval) { value = newval; } + void set_position (position_type const &pos_) { pos = pos_; } + +// debug support +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 +// access functions for the tree_to_xml functionality + static int get_token_id(lex_token const &t) + { return ID_FROM_TOKEN(token_id(t)); } + static string_type get_token_value(lex_token const &t) + { return t.get_value(); } +#endif + +// print support + void print (std::ostream &stream) const + { + using namespace std; + using namespace boost::wave; + stream << setw(16) << left << boost::wave::get_token_name(id) << " (" + << "(#" << token_id(ID_FROM_TOKEN(*this)) + << ") at " << get_position().get_file() << " (" + << setw(3) << right << get_position().get_line() << "/" + << setw(2) << right << get_position().get_column() + << "): >"; + + for (size_t i = 0; i < value.size(); ++i) { + switch (value[i]) { + case '\r': stream << "\\r"; break; + case '\n': stream << "\\n"; break; + case '\t': stream << "\\t"; break; + default: + stream << value[i]; + break; + } + } + stream << "<"; + } + +private: + boost::wave::token_id id; // the token id + string_type value; // the text, which was parsed into this token + PositionT pos; // the original file position +}; + +template +inline std::ostream & +operator<< (std::ostream &stream, slex_token const &object) +{ + object.print(stream); + return stream; +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpp_token_sample +} // namespace wave +} // namespace boost + +#endif // !defined(SLEX_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED) diff --git a/samples/list_includes/build/Jamfile b/samples/list_includes/build/Jamfile new file mode 100644 index 000000000..e245ca4a1 --- /dev/null +++ b/samples/list_includes/build/Jamfile @@ -0,0 +1,25 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Sample Build Jamfile (list_includes) +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +subproject libs/wave/samples/list_includes/build ; + +exe list_includes + : ../list_includes.cpp + ../../../build/boost_wave + ../../../../../libs/program_options/build/boost_program_options + ../../../../../libs/filesystem/build/boost_filesystem + : + $(BOOST_ROOT) + <*>off # workaround for compiler bug + : + static + single + ; + diff --git a/samples/list_includes/build/Jamfile.v2 b/samples/list_includes/build/Jamfile.v2 new file mode 100644 index 000000000..9e51316b4 --- /dev/null +++ b/samples/list_includes/build/Jamfile.v2 @@ -0,0 +1,18 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Sample Build Jamfile (list_includes) +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +exe list_includes + : ../list_includes.cpp + ../../../build//boost_wave + $(BOOST_ROOT)/boost/program_options//boost_program_options + : + msvc-7.1:off # workaround for compiler bug + ; + diff --git a/samples/list_includes/list_includes.cpp b/samples/list_includes/list_includes.cpp new file mode 100644 index 000000000..2e1cce345 --- /dev/null +++ b/samples/list_includes/list_includes.cpp @@ -0,0 +1,300 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: List include dependencies of a given source file + + The 'list_includes' sample shows a simple way, how to use the Wave C++ + preprocessor library to extract a list of included files from a given + source file. + To get a hint which commandline options are supported, call it with the + --help option. + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "list_includes.hpp" // config data + +/////////////////////////////////////////////////////////////////////////////// +// include required boost libraries +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include Wave itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include the lexer stuff +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include the default context trace policies +#include + +/////////////////////////////////////////////////////////////////////////////// +// include lexer specifics, import lexer names +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0 +#include +#endif + +/////////////////////////////////////////////////////////////////////////////// +// import required names +using namespace boost::spirit; + +using std::string; +using std::vector; +using std::set; +using std::cout; +using std::cerr; +using std::endl; +using std::ifstream; +using std::ostream; +using std::istreambuf_iterator; + +namespace po = boost::program_options; + +/////////////////////////////////////////////////////////////////////////////// +namespace cmd_line_util { + + // predicate to extract all positional arguments from the command line + struct is_argument { + bool operator()(po::option const &opt) + { + return (opt.position_key == -1) ? true : false; + } + }; +/////////////////////////////////////////////////////////////////////////////// +} + +/////////////////////////////////////////////////////////////////////////////// +// print the current version + +int print_version() +{ +// get time of last compilation of this file +boost::wave::util::time_conversion_helper compilation_time(__DATE__ " " __TIME__); + +// calculate the number of days since Jan 29 2003 +// (the day the list_includes project was started) +std::tm first_day; + + std::memset (&first_day, 0, sizeof(std::tm)); + first_day.tm_mon = 0; // Jan + first_day.tm_mday = 29; // 29 + first_day.tm_year = 103; // 2003 + +long seconds = long(std::difftime(compilation_time.get_time(), + std::mktime(&first_day))); + + cout + << LIST_INCLUDES_VERSION_MAJOR << '.' + << LIST_INCLUDES_VERSION_MINOR << '.' + << LIST_INCLUDES_VERSION_SUBMINOR << '.' + << seconds/(3600*24); // get number of days from seconds + return 1; // exit app +} + +/////////////////////////////////////////////////////////////////////////////// +// policy class +struct trace_include_files +: public boost::wave::context_policies::default_preprocessing_hooks +{ + trace_include_files(set &files_) : files(files_) {} + + void + opened_include_file(string const &filename, + std::size_t include_depth, bool is_system_include) + { + set::iterator it = files.find(filename); + if (it == files.end()) { + // print indented filename + for (size_t i = 0; i < include_depth; ++i) + cout << " "; + cout << filename << endl; + + files.insert(filename); + } + } + + set &files; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +int +do_actual_work(vector const &arguments, po::variables_map const &vm) +{ +// current file position is saved for exception handling +boost::wave::util::file_position_type current_position; + + try { + // list the included files for all arguments given + vector::const_iterator lastfile = arguments.end(); + for (vector::const_iterator file_it = arguments.begin(); + file_it != lastfile; ++file_it) + { + ifstream instream((*file_it).c_str()); + string instring; + + if (!instream.is_open()) { + cerr << "Could not open input file: " << *file_it << endl; + continue; + } + instream.unsetf(std::ios::skipws); + instring = string(istreambuf_iterator(instream.rdbuf()), + istreambuf_iterator()); + + // The template boost::wave::cpplexer::lex_token<> is the token type to be + // used by the Wave library. + typedef boost::wave::cpplexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lex_iterator_type; + typedef boost::wave::context< + std::string::iterator, lex_iterator_type, + boost::wave::iteration_context_policies::load_file_to_string, + trace_include_files + > context_type; + + set files; + trace_include_files trace(files); + + // The preprocessor iterator shouldn't be constructed directly. It is + // to be generated through a wave::context<> object. This wave:context<> + // object is additionally to be used to initialize and define different + // parameters of the actual preprocessing. + // The preprocessing of the input stream is done on the fly behind the + // scenes during iteration over the context_type::iterator_type stream. + context_type ctx (instring.begin(), instring.end(), (*file_it).c_str(), trace); + + // add include directories to the include path + if (vm.count("include")) { + vector const &paths = + vm["include"].as >(); + vector::const_iterator end = paths.end(); + for (vector::const_iterator cit = paths.begin(); + cit != end; ++cit) + { + ctx.add_include_path((*cit).c_str()); + } + } + + // add system include directories to the include path + if (vm.count("sysinclude")) { + vector const &syspaths = + vm["sysinclude"].as >(); + vector::const_iterator end = syspaths.end(); + for (vector::const_iterator cit = syspaths.begin(); + cit != end; ++cit) + { + ctx.add_sysinclude_path((*cit).c_str()); + } + } + + // analyze the actual file + context_type::iterator_type first = ctx.begin(); + context_type::iterator_type last = ctx.end(); + + cout << "Printing dependency information for: " + << *file_it << endl; + + while (first != last) { + current_position = (*first).get_position(); + ++first; + } + + // prepend endl before next file + cout << endl; + } + } + catch (boost::wave::cpp_exception &e) { + // some preprocessing error + cerr + << e.file_name() << "(" << e.line_no() << "): " + << e.description() << endl; + return 2; + } + catch (std::exception &e) { + // use last recognized token to retrieve the error position + cerr + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "exception caught: " << e.what() + << endl; + return 3; + } + catch (...) { + // use last recognized token to retrieve the error position + cerr + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "unexpected exception caught." << endl; + return 4; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// here we go! +int +main (int argc, char *argv[]) +{ + try { + // analyze the command line options and arguments + vector syspathes; + po::options_description desc("Usage: list_includes [options] file ..."); + + desc.add_options() + ("help,h", "print out program usage (this message)") + ("version,v", "print the version number") + ("include,I", po::value >(), + "specify additional include directory") + ("sysinclude,S", po::value >(), + "specify additional system include directory") + ; + + po::parsed_options opts = po::parse_command_line(argc, argv, desc); + po::variables_map vm; + + po::store(opts, vm); + po::notify(vm); + + if (vm.count("help")) { + cout << desc << endl; + return 1; + } + + if (vm.count("version")) { + return print_version(); + } + + // extract the arguments from the parsed command line + vector arguments; + + std::remove_copy_if(opts.options.begin(), opts.options.end(), + inserter(arguments, arguments.end()), cmd_line_util::is_argument()); + + // if there is no input file given, then exit + if (0 == arguments.size() || 0 == arguments[0].value.size()) { + cerr << "list_includes: No input file given. " + << "Use --help to get a hint." << endl; + return 5; + } + + // iterate over all given input files + return do_actual_work(arguments[0].value , vm); + } + catch (std::exception &e) { + cout << "list_includes: exception caught: " << e.what() << endl; + return 6; + } + catch (...) { + cerr << "list_includes: unexpected exception caught." << endl; + return 7; + } +} + diff --git a/samples/list_includes/list_includes.hpp b/samples/list_includes/list_includes.hpp new file mode 100644 index 000000000..4eaa087bc --- /dev/null +++ b/samples/list_includes/list_includes.hpp @@ -0,0 +1,42 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: List include dependencies of a given source file + Configuration data + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(LIST_INCLUDES_HPP_843DB412_3AA8_4BCF_8081_AA4A5FDE0BE7_INCLUDED) +#define LIST_INCLUDES_HPP_843DB412_3AA8_4BCF_8081_AA4A5FDE0BE7_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// include often used files from the stdlib +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// include boost config +#include // global configuration information + +/////////////////////////////////////////////////////////////////////////////// +// build version +#include "list_includes_version.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// configure this app here (global configuration constants) +#include "list_includes_config.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// include required boost libraries +#include +#include + +#endif // !defined(LIST_INCLUDES_HPP_843DB412_3AA8_4BCF_8081_AA4A5FDE0BE7_INCLUDED) diff --git a/samples/list_includes/list_includes_config.hpp b/samples/list_includes/list_includes_config.hpp new file mode 100644 index 000000000..f47bbb6b2 --- /dev/null +++ b/samples/list_includes/list_includes_config.hpp @@ -0,0 +1,64 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Global application configuration of the list_includes sample + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(LIST_INCLUDES_CONFIG_HPP_0DE80E47_8D50_4DFA_9C1C_0EECAA8A934A_INCLUDED) +#define LIST_INCLUDES_CONFIG_HPP_0DE80E47_8D50_4DFA_9C1C_0EECAA8A934A_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment the following, if you need debug output, the +// BOOST_SPIRIT_DEBUG_FLAGS constants below help to fine control the amount of +// the generated debug output +//#define BOOST_SPIRIT_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// debug rules, subrules and grammars only, for possible flags see +// spirit/debug.hpp +#if defined(BOOST_SPIRIT_DEBUG) + +#define BOOST_SPIRIT_DEBUG_FLAGS ( \ + BOOST_SPIRIT_DEBUG_FLAGS_NODES | \ + BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES \ + ) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// debug flags for the pp-iterator library, possible flags (defined in +// wave_config.hpp): +// +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR 0x0001 +// #define BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION 0x0002 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR 0x0004 +// #define BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR 0x0008 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR 0x0010 +// #define BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR 0x0020 +// #define BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR 0x0040 + +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP (\ + /* insert the required flags from above */ \ + ) \ + /**/ +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Now include the cofiguration stuff for the Wave library itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// MSVC specific #pragma's +#if defined(BOOST_MSVC) +#pragma warning (disable: 4355) // 'this' used in base member initializer list +#pragma warning (disable: 4800) // forcing value to bool 'true' or 'false' +#pragma inline_depth(255) +#pragma inline_recursion(on) +#endif // defined(BOOST_MSVC) + +#endif // !defined(LIST_INCLUDES_CONFIG_HPP_0DE80E47_8D50_4DFA_9C1C_0EECAA8A934A_INCLUDED) diff --git a/samples/list_includes/list_includes_version.hpp b/samples/list_includes/list_includes_version.hpp new file mode 100644 index 000000000..2fae85f04 --- /dev/null +++ b/samples/list_includes/list_includes_version.hpp @@ -0,0 +1,20 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: List include dependencies of a given source file version number + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(LIST_INCLUDES_VERSION_HPP_FF662D6C_C3E6_4BEC_A062_5D9BD7415EBF_INCLUDED) +#define LIST_INCLUDES_VERSION_HPP_FF662D6C_C3E6_4BEC_A062_5D9BD7415EBF_INCLUDED + +#define LIST_INCLUDES_VERSION_MAJOR 0 +#define LIST_INCLUDES_VERSION_MINOR 2 +#define LIST_INCLUDES_VERSION_SUBMINOR 0 + +#endif // !defined(LIST_INCLUDES_VERSION_HPP_FF662D6C_C3E6_4BEC_A062_5D9BD7415EBF_INCLUDED) diff --git a/samples/quick_start/build/Jamfile b/samples/quick_start/build/Jamfile new file mode 100644 index 000000000..609734a03 --- /dev/null +++ b/samples/quick_start/build/Jamfile @@ -0,0 +1,24 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Sample Build Jamfile (quick_start) +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +subproject libs/wave/samples/quick_start/build ; + +exe quick_start + : ../quick_start.cpp + ../../../build/boost_wave + ../../../../../libs/filesystem/build/boost_filesystem + : + $(BOOST_ROOT) + <*>off # workaround for compiler bug + : + static + single + ; + diff --git a/samples/quick_start/build/Jamfile.v2 b/samples/quick_start/build/Jamfile.v2 new file mode 100644 index 000000000..326a692f3 --- /dev/null +++ b/samples/quick_start/build/Jamfile.v2 @@ -0,0 +1,17 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Sample Build Jamfile (quick_start) +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +exe quick_start + : ../quick_start.cpp + ../../../build//boost_wave + : + msvc-7.1:off # workaround for compiler bug + ; + diff --git a/samples/quick_start/quick_start.cpp b/samples/quick_start/quick_start.cpp new file mode 100644 index 000000000..a509f4936 --- /dev/null +++ b/samples/quick_start/quick_start.cpp @@ -0,0 +1,108 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include Wave itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include the lexer stuff +#include // token class +#include // lexer class + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int main(int argc, char *argv[]) +{ + if (2 != argc) { + std::cerr << "Usage: quick_start infile" << std::endl; + return -1; + } + +// current file position is saved for exception handling +boost::wave::util::file_position_type current_position; + + try { + // Open and read in the specified input file. + std::ifstream instream(argv[1]); + std::string instring; + + if (!instream.is_open()) { + std::cerr << "Could not open input file: " << argv[1] << std::endl; + return -2; + } + instream.unsetf(std::ios::skipws); + instring = std::string(std::istreambuf_iterator(instream.rdbuf()), + std::istreambuf_iterator()); + + // The template boost::wave::cpplexer::lex_token<> is the token type to be + // used by the Wave library. + typedef boost::wave::cpplexer::lex_token<> token_type; + + // The template boost::wave::cpplexer::lex_iterator<> is the lexer type to + // be used by the Wave library. + typedef boost::wave::cpplexer::lex_iterator lex_iterator_type; + + // This is the resulting context type to use. The first template parameter + // should match the iterator type to be used during construction of the + // corresponding context object (see below). + typedef boost::wave::context + context_type; + + // The preprocessor iterator shouldn't be constructed directly. It is + // to be generated through a wave::context<> object. This wave:context<> + // object is to be used additionally to initialize and define different + // parameters of the actual preprocessing (not done here). + // + // The preprocessing of the input stream is done on the fly behind the + // scenes during iteration over the context_type::iterator_type stream. + context_type ctx (instring.begin(), instring.end(), argv[1]); + + // analyze the input file + context_type::iterator_type first = ctx.begin(); + context_type::iterator_type last = ctx.end(); + + while (first != last) { + current_position = (*first).get_position(); + std::cout << (*first).get_value(); + ++first; + } + } + catch (boost::wave::cpp_exception &e) { + // some preprocessing error + std::cerr + << e.file_name() << "(" << e.line_no() << "): " + << e.description() << std::endl; + return 2; + } + catch (std::exception &e) { + // use last recognized token to retrieve the error position + std::cerr + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "exception caught: " << e.what() + << std::endl; + return 3; + } + catch (...) { + // use last recognized token to retrieve the error position + std::cerr + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "unexpected exception caught." << std::endl; + return 4; + } + return 0; +} diff --git a/samples/waveidl/build/Jamfile b/samples/waveidl/build/Jamfile new file mode 100644 index 000000000..03403d173 --- /dev/null +++ b/samples/waveidl/build/Jamfile @@ -0,0 +1,31 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Sample Build Jamfile (waveidl) +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +subproject libs/wave/samples/waveidl/build ; + +exe waveidl + : ../idl.cpp + ../instantiate_cpp_grammar.cpp + ../instantiate_defined_grammar.cpp + ../instantiate_predef_macros.cpp + ../instantiate_re2c_lexer.cpp + ../instantiate_re2c_lexer_string.cpp + ../idllexer/idl.re.cpp + ../../../build/boost_wave + ../../../../../libs/program_options/build/boost_program_options + ../../../../../libs/filesystem/build/boost_filesystem + : + $(BOOST_ROOT) + <*>off # workaround for compiler bug + : + static + single + ; + diff --git a/samples/waveidl/build/Jamfile.v2 b/samples/waveidl/build/Jamfile.v2 new file mode 100644 index 000000000..5486ce96f --- /dev/null +++ b/samples/waveidl/build/Jamfile.v2 @@ -0,0 +1,24 @@ +# Wave: A Standard compliant C++ preprocessor library +# +# Boost Wave Library Sample Build Jamfile (waveidl) +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +exe waveidl + : ../idl.cpp + ../instantiate_cpp_grammar.cpp + ../instantiate_defined_grammar.cpp + ../instantiate_predef_macros.cpp + ../instantiate_re2c_lexer.cpp + ../instantiate_re2c_lexer_string.cpp + ../idllexer/idl.re.cpp + ../../../build//boost_wave + $(BOOST_ROOT)/boost/program_options//boost_program_options + : + msvc-7.1:off # workaround for compiler bug + ; + diff --git a/samples/waveidl/idl.cpp b/samples/waveidl/idl.cpp new file mode 100644 index 000000000..65fb671e9 --- /dev/null +++ b/samples/waveidl/idl.cpp @@ -0,0 +1,532 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "idl.hpp" // global configuration + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include Wave itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include the lexer related stuff +#include // token type +#include "idllexer/idl_lex_iterator.hpp" // lexer type + +/////////////////////////////////////////////////////////////////////////////// +// include lexer specifics, import lexer names +// +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0 +#include "idllexer/idl_re2c_lexer.hpp" +#endif + +/////////////////////////////////////////////////////////////////////////////// +// include the grammar definitions, if these shouldn't be compiled separately +// (ATTENTION: _very_ large compilation times!) +// +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION == 0 +#include +#include +#include +#include +#include +#include +#endif + +/////////////////////////////////////////////////////////////////////////////// +// import required names +using namespace boost::spirit; + +using std::string; +using std::pair; +using std::vector; +using std::getline; +using std::ifstream; +using std::cout; +using std::cerr; +using std::endl; +using std::ostream; +using std::istreambuf_iterator; + +namespace po = boost::program_options; +namespace fs = boost::filesystem; + +/////////////////////////////////////////////////////////////////////////////// +// print the current version +int print_version() +{ + typedef boost::wave::idllexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lex_iterator_type; + typedef boost::wave::context + context_type; + + string version (context_type::get_version_string()); + cout + << version.substr(1, version.size()-2) // strip quotes + << " (" << IDL_VERSION_DATE << ")" // add date + << endl; + return 0; // exit app +} + +/////////////////////////////////////////////////////////////////////////////// +// print the copyright statement +int print_copyright() +{ + char const *copyright[] = { + "", + "Sample: IDL oriented preprocessor", + "Based on: Wave, A Standard conformant C++ preprocessor library", + "It is hosted by http://spirit.sourceforge.net/.", + "", + "Copyright (c) 2001-2005 Hartmut Kaiser, 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)", + 0 + }; + + for (int i = 0; 0 != copyright[i]; ++i) + cout << copyright[i] << endl; + + return 0; // exit app +} + +/////////////////////////////////////////////////////////////////////////////// +namespace cmd_line_util { + + // Additional command line parser which interprets '@something' as an + // option "config-file" with the value "something". + pair at_option_parser(string const&s) + { + if ('@' == s[0]) + return std::make_pair(string("config-file"), s.substr(1)); + else + return pair(); + } + + // class, which keeps include file information read from the command line + class include_paths { + public: + include_paths() : seen_separator(false) {} + + vector paths; // stores user paths + vector syspaths; // stores system paths + bool seen_separator; // command line contains a '-I-' option + + // Function which validates additional tokens from command line. + static void + validate(boost::any &v, vector const &tokens) + { + if (v.empty()) + v = boost::any(include_paths()); + + include_paths *p = boost::any_cast(&v); + + BOOST_SPIRIT_ASSERT(p); + // Assume only one path per '-I' occurrence. + string t = tokens[0]; + if (t == "-") { + // found -I- option, so switch behaviour + p->seen_separator = true; + } + else if (p->seen_separator) { + // store this path as a system path + p->syspaths.push_back(t); + } + else { + // store this path as an user path + p->paths.push_back(t); + } + } + }; + + // Read all options from a given config file, parse and add them to the + // given variables_map + void read_config_file_options(string const &filename, + po::options_description const &desc, po::variables_map &vm, + bool may_fail = false) + { + ifstream ifs(filename.c_str()); + + if (!ifs.is_open()) { + if (!may_fail) { + cerr << filename + << ": command line warning: config file not found" + << endl; + } + return; + } + + vector options; + string line; + + while (std::getline(ifs, line)) { + // skip empty lines + string::size_type pos = line.find_first_not_of(" \t"); + if (pos == string::npos) + continue; + + // skip comment lines + if ('#' != line[pos]) + options.push_back(line); + } + + if (options.size() > 0) { + po::store(po::command_line_parser(options).options(desc).run(), vm); + po::notify(vm); + } + } + + // predicate to extract all positional arguments from the command line + struct is_argument { + bool operator()(po::option const &opt) + { + return (opt.position_key == -1) ? true : false; + } + }; + +/////////////////////////////////////////////////////////////////////////////// +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Special validator overload, which allows to handle the -I- syntax for +// switching the semantics of an -I option. +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace program_options { + + void validate(boost::any &v, std::vector const &s, + cmd_line_util::include_paths *, int) + { + cmd_line_util::include_paths::validate(v, s); + } + +}} // namespace boost::program_options + +/////////////////////////////////////////////////////////////////////////////// +// do the actual preprocessing +int +do_actual_work (std::string file_name, po::variables_map const &vm) +{ +// current file position is saved for exception handling +boost::wave::util::file_position_type current_position; + + try { + // process the given file + ifstream instream(file_name.c_str()); + string instring; + + if (!instream.is_open()) { + cerr << "waveidl: could not open input file: " << file_name << endl; + return -1; + } + instream.unsetf(std::ios::skipws); + +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) + // this is known to be very slow for large files on some systems + copy (istream_iterator(instream), + istream_iterator(), + inserter(instring, instring.end())); +#else + instring = string(istreambuf_iterator(instream.rdbuf()), + istreambuf_iterator()); +#endif + + // This sample uses the lex_token type predefined in the Wave library, but + // but uses a custom lexer type. + typedef boost::wave::idllexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lex_iterator_type; + typedef boost::wave::context + context_type; + + // The C++ preprocessor iterators shouldn't be constructed directly. They + // are to be generated through a boost::wave::context<> object. This + // boost::wave::context object is additionally to be used to initialize and + // define different parameters of the actual preprocessing. + // The preprocessing of the input stream is done on the fly behind the + // scenes during iteration over the context_type::iterator_type stream. + context_type ctx (instring.begin(), instring.end(), file_name.c_str()); + + // add include directories to the system include search paths + if (vm.count("sysinclude")) { + vector const &syspaths = + vm["sysinclude"].as >(); + vector::const_iterator end = syspaths.end(); + for (vector::const_iterator cit = syspaths.begin(); + cit != end; ++cit) + { + ctx.add_sysinclude_path((*cit).c_str()); + } + } + + // add include directories to the include search paths + if (vm.count("include")) { + cmd_line_util::include_paths const &ip = + vm["include"].as(); + vector::const_iterator end = ip.paths.end(); + + for (vector::const_iterator cit = ip.paths.begin(); + cit != end; ++cit) + { + ctx.add_include_path((*cit).c_str()); + } + + // if on the command line was given -I- , this has to be propagated + if (ip.seen_separator) + ctx.set_sysinclude_delimiter(); + + // add system include directories to the include path + vector::const_iterator sysend = ip.syspaths.end(); + for (vector::const_iterator syscit = ip.syspaths.begin(); + syscit != sysend; ++syscit) + { + ctx.add_sysinclude_path((*syscit).c_str()); + } + } + + // add additional defined macros + if (vm.count("define")) { + vector const ¯os = vm["define"].as >(); + vector::const_iterator end = macros.end(); + for (vector::const_iterator cit = macros.begin(); + cit != end; ++cit) + { + ctx.add_macro_definition(*cit); + } + } + + // add additional predefined macros + if (vm.count("predefine")) { + vector const &predefmacros = + vm["predefine"].as >(); + vector::const_iterator end = predefmacros.end(); + for (vector::const_iterator cit = predefmacros.begin(); + cit != end; ++cit) + { + ctx.add_macro_definition(*cit, true); + } + } + + // undefine specified macros + if (vm.count("undefine")) { + vector const &undefmacros = + vm["undefine"].as >(); + vector::const_iterator end = undefmacros.end(); + for (vector::const_iterator cit = undefmacros.begin(); + cit != end; ++cit) + { + ctx.remove_macro_definition((*cit).c_str(), true); + } + } + + // open the output file + std::ofstream output; + + if (vm.count("output")) { + // try to open the file, where to put the preprocessed output + string out_file (vm["output"].as()); + + output.open(out_file.c_str()); + if (!output.is_open()) { + cerr << "waveidl: could not open output file: " << out_file + << endl; + return -1; + } + } + else { + // output the preprocessed result to std::cout + output.copyfmt(cout); + output.clear(cout.rdstate()); + static_cast &>(output).rdbuf(cout.rdbuf()); + } + + // analyze the input file + context_type::iterator_type first = ctx.begin(); + context_type::iterator_type last = ctx.end(); + + // loop over all generated tokens outputing the generated text + while (first != last) { + // print out the string representation of this token (skip comments) + using namespace boost::wave; + + // store the last known good token position + current_position = (*first).get_position(); + + token_id id = token_id(*first); + + if (T_CPPCOMMENT == id || T_NEWLINE == id) { + // C++ comment tokens contain the trailing newline + output << endl; + } + else if (id != T_CCOMMENT) { + // print out the current token value + output << (*first).get_value(); + } + ++first; // advance to the next token + } + } + catch (boost::wave::cpp_exception &e) { + // some preprocessing error + cerr + << e.file_name() << "(" << e.line_no() << "): " + << e.description() << endl; + return 1; + } + catch (boost::wave::cpplexer::lexing_exception &e) { + // some lexing error + cerr + << e.file_name() << "(" << e.line_no() << "): " + << e.description() << endl; + return 2; + } + catch (std::exception &e) { + // use last recognized token to retrieve the error position + cerr + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "exception caught: " << e.what() + << endl; + return 3; + } + catch (...) { + // use last recognized token to retrieve the error position + cerr + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "unexpected exception caught." << endl; + return 4; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int +main (int argc, char *argv[]) +{ + try { + // analyze the command line options and arguments + + // declare the options allowed from the command line only + po::options_description desc_cmdline ("Options allowed on the command line only"); + + desc_cmdline.add_options() + ("help,h", "print out program usage (this message)") + ("version,v", "print the version number") + ("copyright,c", "print out the copyright statement") + ("config-file", po::value >(), + "specify a config file (alternatively: @filepath)") + ; + + // declare the options allowed on command line and in config files + po::options_description desc_generic ("Options allowed additionally in a config file"); + + desc_generic.add_options() + ("output,o", "specify a file to use for output instead of stdout") + ("include,I", po::value()->composing(), + "specify an additional include directory") + ("sysinclude,S", po::value >()->composing(), + "specify an additional system include directory") + ("define,D", po::value >()->composing(), + "specify a macro to define (as macro[=[value]])") + ("predefine,P", po::value >()->composing(), + "specify a macro to predefine (as macro[=[value]])") + ("undefine,U", po::value >()->composing(), + "specify a macro to undefine") + ; + + // combine the options for the different usage schemes + po::options_description desc_overall_cmdline; + po::options_description desc_overall_cfgfile; + + desc_overall_cmdline.add(desc_cmdline).add(desc_generic); + desc_overall_cfgfile.add(desc_generic); + + // parse command line and store results + po::parsed_options opts = po::parse_command_line(argc, argv, + desc_overall_cmdline, 0, cmd_line_util::at_option_parser); + po::variables_map vm; + + po::store(opts, vm); + po::notify(vm); + + // Try to find a waveidl.cfg in the same directory as the executable was + // started from. If this exists, treat it as a wave config file + fs::path filename(argv[0], fs::native); + + filename = filename.branch_path() / "waveidl.cfg"; + cmd_line_util::read_config_file_options(filename.string(), + desc_overall_cfgfile, vm, true); + + // if there is specified at least one config file, parse it and add the + // options to the main variables_map + if (vm.count("config-file")) { + vector const &cfg_files = + vm["config-file"].as >(); + vector::const_iterator end = cfg_files.end(); + for (vector::const_iterator cit = cfg_files.begin(); + cit != end; ++cit) + { + // parse a single config file and store the results + cmd_line_util::read_config_file_options(*cit, + desc_overall_cfgfile, vm); + } + } + + // ... act as required + if (vm.count("help")) { + po::options_description desc_help ( + "Usage: waveidl [options] [@config-file(s)] file"); + + desc_help.add(desc_cmdline).add(desc_generic); + cout << desc_help << endl; + return 1; + } + + if (vm.count("version")) { + return print_version(); + } + + if (vm.count("copyright")) { + return print_copyright(); + } + + // extract the arguments from the parsed command line + vector arguments; + + std::remove_copy_if(opts.options.begin(), opts.options.end(), + inserter(arguments, arguments.end()), cmd_line_util::is_argument()); + + // if there is no input file given, then exit + if (0 == arguments.size() || 0 == arguments[0].value.size()) { + cerr << "waveidl: no input file given, " + << "use --help to get a hint." << endl; + return 5; + } + + // preprocess the given input file + return do_actual_work(arguments[0].value[0], vm); + } + catch (std::exception &e) { + cout << "waveidl: exception caught: " << e.what() << endl; + return 6; + } + catch (...) { + cerr << "waveidl: unexpected exception caught." << endl; + return 7; + } +} + diff --git a/samples/waveidl/idl.hpp b/samples/waveidl/idl.hpp new file mode 100644 index 000000000..0d8843573 --- /dev/null +++ b/samples/waveidl/idl.hpp @@ -0,0 +1,45 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(IDL_HPP_FC7EE131_5CE9_43F2_A713_8D9BBC3C8477_INCLUDED) +#define IDL_HPP_FC7EE131_5CE9_43F2_A713_8D9BBC3C8477_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// This file may be used as a precompiled header (if applicable) + +/////////////////////////////////////////////////////////////////////////////// +// include often used files from the stdlib +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// include boost config +#include // global configuration information + +/////////////////////////////////////////////////////////////////////////////// +// build version +#include "idl_version.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// configure this app here (global configuration constants) +#include "idl_config.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// include required boost libraries +#include +#include + +#endif // !defined(IDL_HPP_FC7EE131_5CE9_43F2_A713_8D9BBC3C8477_INCLUDED) diff --git a/samples/waveidl/idl_config.hpp b/samples/waveidl/idl_config.hpp new file mode 100644 index 000000000..03c020767 --- /dev/null +++ b/samples/waveidl/idl_config.hpp @@ -0,0 +1,65 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + Global application configuration of the Wave driver command + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(IDL_CONFIG_HPP_012D7524_FF3F_482F_9123_91966C72F4EA_INCLUDED) +#define IDL_CONFIG_HPP_012D7524_FF3F_482F_9123_91966C72F4EA_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment the following, if you need debug output, the +// BOOST_SPIRIT_DEBUG_FLAGS constants below help to fine control the amount of +// the generated debug output +//#define BOOST_SPIRIT_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// debug rules, subrules and grammars only, for possible flags see +// spirit/debug.hpp +#if defined(BOOST_SPIRIT_DEBUG) + +#define BOOST_SPIRIT_DEBUG_FLAGS ( \ + BOOST_SPIRIT_DEBUG_FLAGS_NODES | \ + BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES \ + ) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// debug flags for the pp-iterator library, possible flags (defined in +// wave_config.hpp): +// +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR 0x0001 +// #define BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION 0x0002 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR 0x0004 +// #define BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR 0x0008 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR 0x0010 +// #define BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR 0x0020 +// #define BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR 0x0040 + +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP (\ + /* insert the required flags from above */ \ + ) \ + /**/ +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Now include the cofiguration stuff for the Wave library itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// MSVC specific #pragma's +#if defined(BOOST_MSVC) +#pragma warning (disable: 4355) // 'this' used in base member initializer list +#pragma warning (disable: 4800) // forcing value to bool 'true' or 'false' +#pragma inline_depth(255) +#pragma inline_recursion(on) +#endif // defined(BOOST_MSVC) + +#endif // !defined(IDL_CONFIG_HPP_012D7524_FF3F_482F_9123_91966C72F4EA_INCLUDED) diff --git a/samples/waveidl/idl_version.hpp b/samples/waveidl/idl_version.hpp new file mode 100644 index 000000000..b4fbd101b --- /dev/null +++ b/samples/waveidl/idl_version.hpp @@ -0,0 +1,23 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(IDL_VERSION_HPP_780C1190_3107_440B_B303_B687A449749B_INCLUDED) +#define IDL_VERSION_HPP_780C1190_3107_440B_B303_B687A449749B_INCLUDED + +#include + +#define IDL_VERSION_MAJOR BOOST_WAVE_VERSION_MAJOR +#define IDL_VERSION_MINOR BOOST_WAVE_VERSION_MINOR +#define IDL_VERSION_SUBMINOR BOOST_WAVE_VERSION_SUBMINOR +#define IDL_VERSION_DATE 20050117L + +#endif // !defined(IDL_VERSION_HPP_780C1190_3107_440B_B303_B687A449749B_INCLUDED) diff --git a/samples/waveidl/idllexer/idl.re b/samples/waveidl/idllexer/idl.re new file mode 100644 index 000000000..02865eca1 --- /dev/null +++ b/samples/waveidl/idllexer/idl.re @@ -0,0 +1,579 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL lexer + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(BOOST_HAS_UNISTD_H) +#include +#else +#include +#endif + +#include +#include + +// reuse the token ids and re2c helper functions from the default C++ lexer +#include +#include +#include + +#include "idl.re.hpp" + +#if defined(_MSC_VER) && !defined(__COMO__) +#pragma warning (disable: 4101) // 'foo' : unreferenced local variable +#pragma warning (disable: 4102) // 'foo' : unreferenced label +#endif + +#define BSIZE 196608 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +//#define RET(i) {s->cur = cursor; return (i);} +#define RET(i) \ + { \ + s->line += count_backslash_newlines(s, cursor); \ + s->cur = cursor; \ + return (i); \ + } \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace idllexer { +namespace re2clex { + +#define RE2C_ASSERT BOOST_ASSERT + +int +get_one_char(boost::wave::cpplexer::re2clex::Scanner *s) +{ + using namespace boost::wave::cpplexer::re2clex; + if (s->fd != -1) { + uchar val; + + if (read(s->fd, &val, sizeof(val))) + return val; + } + else if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + if (s->act < s->last) + return *(s->act)++; + } + return -1; +} + +std::ptrdiff_t +rewind_stream (boost::wave::cpplexer::re2clex::Scanner *s, int cnt) +{ + if (s->fd != -1) { + return lseek(s->fd, cnt, SEEK_CUR); + } + else if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + s->act += cnt; + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + return s->act - s->first; + } + return 0; +} + +std::size_t +get_first_eol_offset(boost::wave::cpplexer::re2clex::Scanner* s) +{ + if (!AQ_EMPTY(s->eol_offsets)) + { + return s->eol_offsets->queue[s->eol_offsets->head]; + } + else + { + return (unsigned int)-1; + } +} + +void +adjust_eol_offsets(boost::wave::cpplexer::re2clex::Scanner* s, + std::size_t adjustment) +{ + boost::wave::cpplexer::re2clex::aq_queue q; + std::size_t i; + + if (!s->eol_offsets) + s->eol_offsets = boost::wave::cpplexer::re2clex::aq_create(); + + q = s->eol_offsets; + + if (AQ_EMPTY(q)) + return; + + i = q->head; + while (i != q->tail) + { + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; + ++i; + if (i == q->max_size) + i = 0; + } + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; +} + +int +count_backslash_newlines(boost::wave::cpplexer::re2clex::Scanner *s, + boost::wave::cpplexer::re2clex::uchar *cursor) +{ + using namespace boost::wave::cpplexer::re2clex; + + std::size_t diff, offset; + int skipped = 0; + + /* figure out how many backslash-newlines skipped over unknowingly. */ + diff = cursor - s->bot; + offset = get_first_eol_offset(s); + while (offset <= diff && offset != (unsigned int)-1) + { + skipped++; + boost::wave::cpplexer::re2clex::aq_pop(s->eol_offsets); + offset = get_first_eol_offset(s); + } + return skipped; +} + +bool is_backslash( + boost::wave::cpplexer::re2clex::uchar *p, + boost::wave::cpplexer::re2clex::uchar *end, int &len) +{ + if (*p == '\\') { + len = 1; + return true; + } + else if (*p == '?' && *(p+1) == '?' && (p+2 < end && *(p+2) == '/')) { + len = 3; + return true; + } + return false; +} + +boost::wave::cpplexer::re2clex::uchar * +fill(boost::wave::cpplexer::re2clex::Scanner *s, + boost::wave::cpplexer::re2clex::uchar *cursor) +{ + using namespace boost::wave::cpplexer::re2clex; + + if(!s->eof) + { + uchar* p; + std::ptrdiff_t cnt = s->tok - s->bot; + if(cnt) + { + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->lim -= cnt; + adjust_eol_offsets(s, cnt); + } + + if((s->top - s->lim) < BSIZE) + { + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + if (buf == 0) + { + if (0 != s->error_proc) + (*s->error_proc)(s, "Out of memory!"); + else + printf("Out of memory!\n"); + + /* get the scanner to stop */ + *cursor = 0; + return cursor; + } + + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + + if (s->fd != -1) { + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + else if (s->act != 0) { + cnt = s->last - s->act; + if (cnt > BSIZE) + cnt = BSIZE; + memcpy(s->lim, s->act, cnt); + s->act += cnt; + if (cnt != BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + + /* backslash-newline erasing time */ + + /* first scan for backslash-newline and erase them */ + for (p = s->lim; p < s->lim + cnt - 2; ++p) + { + int len = 0; + if (is_backslash(p, s->lim + cnt, len)) + { + if (*(p+len) == '\n') + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + else if (*(p+len) == '\r') + { + if (*(p+len+1) == '\n') + { + int offset = len + 2; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + else + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + } + } + + /* FIXME: the following code should be fixed to recognize correctly the + trigraph backslash token */ + + /* check to see if what we just read ends in a backslash */ + if (cnt >= 2) + { + uchar last = s->lim[cnt-1]; + uchar last2 = s->lim[cnt-2]; + /* check \ EOB */ + if (last == '\\') + { + int next = get_one_char(s); + /* check for \ \n or \ \r or \ \r \n straddling the border */ + if (next == '\n') + { + --cnt; /* chop the final \, we've already read the \n. */ + boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets, + cnt + (s->lim - s->bot)); + } + else if (next == '\r') + { + int next2 = get_one_char(s); + if (next2 == '\n') + { + --cnt; /* skip the backslash */ + } + else + { + /* rewind one, and skip one char */ + rewind_stream(s, -1); + --cnt; + } + boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets, + cnt + (s->lim - s->bot)); + } + else if (next != -1) /* -1 means end of file */ + { + /* next was something else, so rewind the stream */ + lseek(s->fd, -1, SEEK_CUR); + } + } + /* check \ \r EOB */ + else if (last == '\r' && last2 == '\\') + { + int next = get_one_char(s); + if (next == '\n') + { + cnt -= 2; /* skip the \ \r */ + } + else + { + /* rewind one, and skip two chars */ + rewind_stream(s, -1); + cnt -= 2; + } + boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets, + cnt + (s->lim - s->bot)); + } + /* check \ \n EOB */ + else if (last == '\n' && last2 == '\\') + { + cnt -= 2; + boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets, + cnt + (s->lim - s->bot)); + } + } + + s->lim += cnt; + if (s->eof) /* eof needs adjusting if we erased backslash-newlines */ + { + s->eof = s->lim; + *(s->eof)++ = '\0'; + } + } + return cursor; +} + +boost::wave::token_id +scan(boost::wave::cpplexer::re2clex::Scanner *s) +{ + using namespace boost::wave::cpplexer::re2clex; + + uchar *cursor = s->tok = s->cur; + +/*!re2c +any = [\t\v\f\r\n\040-\377]; +OctalDigit = [0-7]; +Digit = [0-9]; +HexDigit = [a-fA-F0-9]; +ExponentPart = [Ee] [+-]? Digit+; +FractionalConstant = (Digit* "." Digit+) | (Digit+ "."); +FloatingSuffix = [fF][lL]?|[lL][fF]?; +IntegerSuffix = [uU][lL]?|[lL][uU]?; +FixedPointSuffix = [dD]; +Backslash = [\\]|"??/"; +EscapeSequence = Backslash ([abfnrtv?'"] | Backslash | "x" HexDigit+ | OctalDigit OctalDigit? OctalDigit?); +HexQuad = HexDigit HexDigit HexDigit HexDigit; +UniversalChar = Backslash ("u" HexQuad | "U" HexQuad HexQuad); +Newline = "\r\n" | "\n" | "\r"; +PPSpace = ([ \t]|("/*"(any\[*]|Newline|("*"+(any\[*/]|Newline)))*"*"+"/"))*; +Pound = "#" | "??=" | "%:"; +*/ + +/*!re2c + "/*" { goto ccomment; } + "//" { goto cppcomment; } + + "TRUE" { RET(T_TRUE); } + "FALSE" { RET(T_FALSE); } + + "{" { RET(T_LEFTBRACE); } + "}" { RET(T_RIGHTBRACE); } + "[" { RET(T_LEFTBRACKET); } + "]" { RET(T_RIGHTBRACKET); } + "#" { RET(T_POUND); } + "##" { RET(T_POUND_POUND); } + "(" { RET(T_LEFTPAREN); } + ")" { RET(T_RIGHTPAREN); } + ";" { RET(T_SEMICOLON); } + ":" { RET(T_COLON); } + "?" { RET(T_QUESTION_MARK); } + "." { RET(T_DOT); } + "+" { RET(T_PLUS); } + "-" { RET(T_MINUS); } + "*" { RET(T_STAR); } + "/" { RET(T_DIVIDE); } + "%" { RET(T_PERCENT); } + "^" { RET(T_XOR); } + "&" { RET(T_AND); } + "|" { RET(T_OR); } + "~" { RET(T_COMPL); } + "!" { RET(T_NOT); } + "=" { RET(T_ASSIGN); } + "<" { RET(T_LESS); } + ">" { RET(T_GREATER); } + "<<" { RET(T_SHIFTLEFT); } + ">>" { RET(T_SHIFTRIGHT); } + "==" { RET(T_EQUAL); } + "!=" { RET(T_NOTEQUAL); } + "<=" { RET(T_LESSEQUAL); } + ">=" { RET(T_GREATEREQUAL); } + "&&" { RET(T_ANDAND); } + "||" { RET(T_OROR); } + "++" { RET(T_PLUSPLUS); } + "--" { RET(T_MINUSMINUS); } + "," { RET(T_COMMA); } + + ([a-zA-Z_] | UniversalChar) ([a-zA-Z_0-9] | UniversalChar)* + { RET(T_IDENTIFIER); } + + (("0" [xX] HexDigit+) | ("0" OctalDigit*) | ([1-9] Digit*)) IntegerSuffix? + { RET(T_INTLIT); } + + ((FractionalConstant ExponentPart?) | (Digit+ ExponentPart)) FloatingSuffix? + { RET(T_FLOATLIT); } + + (FractionalConstant | Digit+) FixedPointSuffix + { RET(T_FIXEDPOINTLIT); } + + "L"? (['] (EscapeSequence|any\[\n\r\\']|UniversalChar)+ [']) + { RET(T_CHARLIT); } + + "L"? (["] (EscapeSequence|any\[\n\r\\"]|UniversalChar)* ["]) + { RET(T_STRINGLIT); } + + + Pound PPSpace "include" PPSpace "<" (any\[\n\r>])+ ">" + { RET(T_PP_HHEADER); } + + Pound PPSpace "include" PPSpace "\"" (any\[\n\r"])+ "\"" + { RET(T_PP_QHEADER); } + + Pound PPSpace "include" PPSpace + { RET(T_PP_INCLUDE); } + + Pound PPSpace "if" { RET(T_PP_IF); } + Pound PPSpace "ifdef" { RET(T_PP_IFDEF); } + Pound PPSpace "ifndef" { RET(T_PP_IFNDEF); } + Pound PPSpace "else" { RET(T_PP_ELSE); } + Pound PPSpace "elif" { RET(T_PP_ELIF); } + Pound PPSpace "endif" { RET(T_PP_ENDIF); } + Pound PPSpace "define" { RET(T_PP_DEFINE); } + Pound PPSpace "undef" { RET(T_PP_UNDEF); } + Pound PPSpace "line" { RET(T_PP_LINE); } + Pound PPSpace "error" { RET(T_PP_ERROR); } + Pound PPSpace "pragma" { RET(T_PP_PRAGMA); } + + Pound PPSpace "warning" { RET(T_PP_WARNING); } + + [ \t\v\f]+ + { RET(T_SPACE); } + + Newline + { + s->line++; + RET(T_NEWLINE); + } + + "\000" + { + if(cursor != s->eof) + { + if (0 != s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file\n"); + } + RET(T_EOF); + } + + any + { + /* if (0 != s->error_proc) + (*s->error_proc)(s, "Unexpected character: '%c'", *s->tok); + else + printf("unexpected character: '%c'\n", *s->tok); + */ + RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); + } +*/ + +ccomment: +/*!re2c + "*/" { RET(T_CCOMMENT); } + Newline + { + /*if(cursor == s->eof) RET(T_EOF);*/ + /*s->tok = cursor; */ + s->line += count_backslash_newlines(s, cursor) +1; + goto ccomment; + } + + any { goto ccomment; } + + "\000" + { + yyaccept = 0; /* avoid warning about unreferenced variable */ + if(cursor == s->eof) + { + if (s->error_proc) + (*s->error_proc)(s, "Unterminated comment"); + else + printf("Error: Unterminated comment\n"); + } + else + { + if (s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file"); + } + /* adjust cursor such next call returns T_EOF */ + --YYCURSOR; + /* the comment is unterminated, but nevertheless its a comment */ + RET(T_CCOMMENT); + } + +*/ + +cppcomment: +/*!re2c + Newline + { + /*if(cursor == s->eof) RET(T_EOF); */ + /*s->tok = cursor; */ + s->line++; + RET(T_CPPCOMMENT); + } + + any { goto cppcomment; } + + "\000" + { + yyaccept = 0; /* avoid warning about unreferenced variable */ + if(cursor != s->eof) + { + if (s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file"); + } + /* adjust cursor such next call returns T_EOF */ + --YYCURSOR; + /* the comment is unterminated, but nevertheless its a comment */ + RET(T_CPPCOMMENT); + } +*/ + +} /* end of scan */ + +#undef RE2C_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace idllexer +} // namespace wave +} // namespace boost diff --git a/samples/waveidl/idllexer/idl.re.cpp b/samples/waveidl/idllexer/idl.re.cpp new file mode 100644 index 000000000..7ea5054da --- /dev/null +++ b/samples/waveidl/idllexer/idl.re.cpp @@ -0,0 +1,4071 @@ +/* Generated by re2c 0.5 on Fri Feb 11 10:36:50 2005 */ +#line 1 "c:\\Cvs\\wave\\libs\\wave\\samples\\waveidl\\idllexer\\idl.re" +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL lexer + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(BOOST_HAS_UNISTD_H) +#include +#else +#include +#endif + +#include +#include + +// reuse the token ids and re2c helper functions from the default C++ lexer +#include +#include +#include + +#include "idl.re.hpp" + +#if defined(_MSC_VER) && !defined(__COMO__) +#pragma warning (disable: 4101) // 'foo' : unreferenced local variable +#pragma warning (disable: 4102) // 'foo' : unreferenced label +#endif + +#define BSIZE 196608 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +//#define RET(i) {s->cur = cursor; return (i);} +#define RET(i) \ + { \ + s->line += count_backslash_newlines(s, cursor); \ + s->cur = cursor; \ + return (i); \ + } \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace idllexer { +namespace re2clex { + +#define RE2C_ASSERT BOOST_ASSERT + +int +get_one_char(boost::wave::cpplexer::re2clex::Scanner *s) +{ + using namespace boost::wave::cpplexer::re2clex; + if (s->fd != -1) { + uchar val; + + if (read(s->fd, &val, sizeof(val))) + return val; + } + else if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + if (s->act < s->last) + return *(s->act)++; + } + return -1; +} + +std::ptrdiff_t +rewind_stream (boost::wave::cpplexer::re2clex::Scanner *s, int cnt) +{ + if (s->fd != -1) { + return lseek(s->fd, cnt, SEEK_CUR); + } + else if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + s->act += cnt; + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + return s->act - s->first; + } + return 0; +} + +std::size_t +get_first_eol_offset(boost::wave::cpplexer::re2clex::Scanner* s) +{ + if (!AQ_EMPTY(s->eol_offsets)) + { + return s->eol_offsets->queue[s->eol_offsets->head]; + } + else + { + return (unsigned int)-1; + } +} + +void +adjust_eol_offsets(boost::wave::cpplexer::re2clex::Scanner* s, + std::size_t adjustment) +{ + boost::wave::cpplexer::re2clex::aq_queue q; + std::size_t i; + + if (!s->eol_offsets) + s->eol_offsets = boost::wave::cpplexer::re2clex::aq_create(); + + q = s->eol_offsets; + + if (AQ_EMPTY(q)) + return; + + i = q->head; + while (i != q->tail) + { + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; + ++i; + if (i == q->max_size) + i = 0; + } + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; +} + +int +count_backslash_newlines(boost::wave::cpplexer::re2clex::Scanner *s, + boost::wave::cpplexer::re2clex::uchar *cursor) +{ + using namespace boost::wave::cpplexer::re2clex; + + std::size_t diff, offset; + int skipped = 0; + + /* figure out how many backslash-newlines skipped over unknowingly. */ + diff = cursor - s->bot; + offset = get_first_eol_offset(s); + while (offset <= diff && offset != (unsigned int)-1) + { + skipped++; + boost::wave::cpplexer::re2clex::aq_pop(s->eol_offsets); + offset = get_first_eol_offset(s); + } + return skipped; +} + +bool is_backslash( + boost::wave::cpplexer::re2clex::uchar *p, + boost::wave::cpplexer::re2clex::uchar *end, int &len) +{ + if (*p == '\\') { + len = 1; + return true; + } + else if (*p == '?' && *(p+1) == '?' && (p+2 < end && *(p+2) == '/')) { + len = 3; + return true; + } + return false; +} + +boost::wave::cpplexer::re2clex::uchar * +fill(boost::wave::cpplexer::re2clex::Scanner *s, + boost::wave::cpplexer::re2clex::uchar *cursor) +{ + using namespace boost::wave::cpplexer::re2clex; + + if(!s->eof) + { + uchar* p; + std::ptrdiff_t cnt = s->tok - s->bot; + if(cnt) + { + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->lim -= cnt; + adjust_eol_offsets(s, cnt); + } + + if((s->top - s->lim) < BSIZE) + { + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + if (buf == 0) + { + if (0 != s->error_proc) + (*s->error_proc)(s, "Out of memory!"); + else + printf("Out of memory!\n"); + + /* get the scanner to stop */ + *cursor = 0; + return cursor; + } + + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + + if (s->fd != -1) { + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + else if (s->act != 0) { + cnt = s->last - s->act; + if (cnt > BSIZE) + cnt = BSIZE; + memcpy(s->lim, s->act, cnt); + s->act += cnt; + if (cnt != BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + + /* backslash-newline erasing time */ + + /* first scan for backslash-newline and erase them */ + for (p = s->lim; p < s->lim + cnt - 2; ++p) + { + int len = 0; + if (is_backslash(p, s->lim + cnt, len)) + { + if (*(p+len) == '\n') + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + else if (*(p+len) == '\r') + { + if (*(p+len+1) == '\n') + { + int offset = len + 2; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + else + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + } + } + + /* FIXME: the following code should be fixed to recognize correctly the + trigraph backslash token */ + + /* check to see if what we just read ends in a backslash */ + if (cnt >= 2) + { + uchar last = s->lim[cnt-1]; + uchar last2 = s->lim[cnt-2]; + /* check \ EOB */ + if (last == '\\') + { + int next = get_one_char(s); + /* check for \ \n or \ \r or \ \r \n straddling the border */ + if (next == '\n') + { + --cnt; /* chop the final \, we've already read the \n. */ + boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets, + cnt + (s->lim - s->bot)); + } + else if (next == '\r') + { + int next2 = get_one_char(s); + if (next2 == '\n') + { + --cnt; /* skip the backslash */ + } + else + { + /* rewind one, and skip one char */ + rewind_stream(s, -1); + --cnt; + } + boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets, + cnt + (s->lim - s->bot)); + } + else if (next != -1) /* -1 means end of file */ + { + /* next was something else, so rewind the stream */ + lseek(s->fd, -1, SEEK_CUR); + } + } + /* check \ \r EOB */ + else if (last == '\r' && last2 == '\\') + { + int next = get_one_char(s); + if (next == '\n') + { + cnt -= 2; /* skip the \ \r */ + } + else + { + /* rewind one, and skip two chars */ + rewind_stream(s, -1); + cnt -= 2; + } + boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets, + cnt + (s->lim - s->bot)); + } + /* check \ \n EOB */ + else if (last == '\n' && last2 == '\\') + { + cnt -= 2; + boost::wave::cpplexer::re2clex::aq_enqueue(s->eol_offsets, + cnt + (s->lim - s->bot)); + } + } + + s->lim += cnt; + if (s->eof) /* eof needs adjusting if we erased backslash-newlines */ + { + s->eof = s->lim; + *(s->eof)++ = '\0'; + } + } + return cursor; +} + +boost::wave::token_id +scan(boost::wave::cpplexer::re2clex::Scanner *s) +{ + using namespace boost::wave::cpplexer::re2clex; + + uchar *cursor = s->tok = s->cur; + +#line 384 + + +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; +yy1: ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 12) YYFILL(12); + yych = *YYCURSOR; + switch(yych){ + case '\000': goto yy70; + case '\001': + case '\002': + case '\003': + case '\004': + case '\005': + case '\006': + case '\a': + case '\b': case '\016': + case '\017': + case '\020': + case '\021': + case '\022': + case '\023': + case '\024': + case '\025': + case '\026': + case '\027': + case '\030': + case '\031': + case '\032': + case '\033': + case '\034': + case '\035': + case '\036': + case '\037': goto yy2; + case '\t': case '\v': + case '\f': case ' ': goto yy65; + case '\n': goto yy67; + case '\r': goto yy69; + case '!': goto yy46; + case '"': goto yy64; + case '#': goto yy16; + case '%': goto yy36; + case '&': goto yy40; + case '\'': goto yy63; + case '(': goto yy18; + case ')': goto yy20; + case '*': goto yy34; + case '+': goto yy30; + case ',': goto yy54; + case '-': goto yy32; + case '.': goto yy28; + case '/': goto yy3; + case '0': goto yy60; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy62; + case ':': goto yy24; + case ';': goto yy22; + case '<': goto yy50; + case '=': goto yy48; + case '>': goto yy52; + case '?': goto yy26; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': case 'G': + case 'H': + case 'I': + case 'J': + case 'K': case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': case '_': case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': goto yy56; + case 'F': goto yy7; + case 'L': goto yy57; + case 'T': goto yy5; + case '[': goto yy12; + case '\\': goto yy58; + case ']': goto yy14; + case '^': goto yy38; + case '{': goto yy8; + case '|': goto yy42; + case '}': goto yy10; + case '~': goto yy44; + default: goto yy72; + } +yy2: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 12: goto yy353; + case 11: goto yy349; + case 1: goto yy17; + case 2: goto yy27; + case 3: goto yy37; + case 0: goto yy6; + case 5: goto yy61; + case 8: goto yy170; + case 7: goto yy131; + case 6: goto yy81; + case 10: goto yy302; + case 9: goto yy294; + case 4: goto yy59; + } +yy3: yych = *++YYCURSOR; + if(yych == '*') goto yy356; + if(yych == '/') goto yy354; + goto yy4; +yy4: +#line 408 + { RET(T_DIVIDE); } +yy5: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'R') goto yy350; + goto yy202; +yy6: +#line 431 + { RET(T_IDENTIFIER); } +yy7: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'A') goto yy345; + goto yy202; +yy8: yych = *++YYCURSOR; + goto yy9; +yy9: +#line 393 + { RET(T_LEFTBRACE); } +yy10: yych = *++YYCURSOR; + goto yy11; +yy11: +#line 394 + { RET(T_RIGHTBRACE); } +yy12: yych = *++YYCURSOR; + goto yy13; +yy13: +#line 395 + { RET(T_LEFTBRACKET); } +yy14: yych = *++YYCURSOR; + goto yy15; +yy15: +#line 396 + { RET(T_RIGHTBRACKET); } +yy16: yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'e'){ + if(yych <= '"'){ + if(yych <= '\t'){ + if(yych >= '\t') goto yy239; + goto yy17; + } else { + if(yych == ' ') goto yy239; + goto yy17; + } + } else { + if(yych <= '.'){ + if(yych <= '#') goto yy343; + goto yy17; + } else { + if(yych <= '/') goto yy239; + if(yych >= 'd') goto yy239; + goto yy17; + } + } + } else { + if(yych <= 'o'){ + if(yych <= 'i'){ + if(yych >= 'i') goto yy239; + goto yy17; + } else { + if(yych == 'l') goto yy239; + goto yy17; + } + } else { + if(yych <= 'u'){ + if(yych <= 'p') goto yy239; + if(yych >= 'u') goto yy239; + goto yy17; + } else { + if(yych == 'w') goto yy239; + goto yy17; + } + } + } +yy17: +#line 397 + { RET(T_POUND); } +yy18: yych = *++YYCURSOR; + goto yy19; +yy19: +#line 399 + { RET(T_LEFTPAREN); } +yy20: yych = *++YYCURSOR; + goto yy21; +yy21: +#line 400 + { RET(T_RIGHTPAREN); } +yy22: yych = *++YYCURSOR; + goto yy23; +yy23: +#line 401 + { RET(T_SEMICOLON); } +yy24: yych = *++YYCURSOR; + goto yy25; +yy25: +#line 402 + { RET(T_COLON); } +yy26: yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '?') goto yy341; + goto yy27; +yy27: +#line 403 + { RET(T_QUESTION_MARK); } +yy28: yych = *++YYCURSOR; + if(yych <= '/') goto yy29; + if(yych <= '9') goto yy168; + goto yy29; +yy29: +#line 404 + { RET(T_DOT); } +yy30: yych = *++YYCURSOR; + if(yych == '+') goto yy339; + goto yy31; +yy31: +#line 405 + { RET(T_PLUS); } +yy32: yych = *++YYCURSOR; + if(yych == '-') goto yy337; + goto yy33; +yy33: +#line 406 + { RET(T_MINUS); } +yy34: yych = *++YYCURSOR; + goto yy35; +yy35: +#line 407 + { RET(T_STAR); } +yy36: yyaccept = 3; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy238; + goto yy37; +yy37: +#line 409 + { RET(T_PERCENT); } +yy38: yych = *++YYCURSOR; + goto yy39; +yy39: +#line 410 + { RET(T_XOR); } +yy40: yych = *++YYCURSOR; + if(yych == '&') goto yy236; + goto yy41; +yy41: +#line 411 + { RET(T_AND); } +yy42: yych = *++YYCURSOR; + if(yych == '|') goto yy234; + goto yy43; +yy43: +#line 412 + { RET(T_OR); } +yy44: yych = *++YYCURSOR; + goto yy45; +yy45: +#line 413 + { RET(T_COMPL); } +yy46: yych = *++YYCURSOR; + if(yych == '=') goto yy232; + goto yy47; +yy47: +#line 414 + { RET(T_NOT); } +yy48: yych = *++YYCURSOR; + if(yych == '=') goto yy230; + goto yy49; +yy49: +#line 415 + { RET(T_ASSIGN); } +yy50: yych = *++YYCURSOR; + if(yych <= ';') goto yy51; + if(yych <= '<') goto yy228; + if(yych <= '=') goto yy226; + goto yy51; +yy51: +#line 416 + { RET(T_LESS); } +yy52: yych = *++YYCURSOR; + if(yych <= '<') goto yy53; + if(yych <= '=') goto yy222; + if(yych <= '>') goto yy224; + goto yy53; +yy53: +#line 417 + { RET(T_GREATER); } +yy54: yych = *++YYCURSOR; + goto yy55; +yy55: +#line 428 + { RET(T_COMMA); } +yy56: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + goto yy202; +yy57: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '?'){ + if(yych <= '\''){ + if(yych == '"') goto yy76; + if(yych <= '&') goto yy6; + goto yy221; + } else { + if(yych <= '/') goto yy6; + if(yych <= '9') goto yy201; + if(yych <= '>') goto yy6; + goto yy204; + } + } else { + if(yych <= '\\'){ + if(yych <= '@') goto yy6; + if(yych <= 'Z') goto yy201; + if(yych <= '[') goto yy6; + goto yy203; + } else { + if(yych <= '_'){ + if(yych <= '^') goto yy6; + goto yy201; + } else { + if(yych <= '`') goto yy6; + if(yych <= 'z') goto yy201; + goto yy6; + } + } + } +yy58: yyaccept = 4; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'U') goto yy193; + if(yych == 'u') goto yy192; + goto yy59; +yy59: +#line 494 + { + /* if (0 != s->error_proc) + (*s->error_proc)(s, "Unexpected character: '%c'", *s->tok); + else + printf("unexpected character: '%c'\n", *s->tok); + */ + RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); + } +yy60: yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'U'){ + if(yych <= 'C'){ + if(yych <= '/'){ + if(yych == '.') goto yy168; + goto yy61; + } else { + if(yych <= '7') goto yy185; + if(yych <= '9') goto yy187; + goto yy61; + } + } else { + if(yych <= 'K'){ + if(yych <= 'D') goto yy164; + if(yych <= 'E') goto yy171; + goto yy61; + } else { + if(yych <= 'L') goto yy173; + if(yych >= 'U') goto yy172; + goto yy61; + } + } + } else { + if(yych <= 'k'){ + if(yych <= 'c'){ + if(yych == 'X') goto yy189; + goto yy61; + } else { + if(yych <= 'd') goto yy164; + if(yych <= 'e') goto yy171; + goto yy61; + } + } else { + if(yych <= 'u'){ + if(yych <= 'l') goto yy173; + if(yych >= 'u') goto yy172; + goto yy61; + } else { + if(yych == 'x') goto yy189; + goto yy61; + } + } + } +yy61: +#line 434 + { RET(T_INTLIT); } +yy62: yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'L'){ + if(yych <= '9'){ + if(yych == '.') goto yy168; + if(yych <= '/') goto yy61; + goto yy166; + } else { + if(yych <= 'D'){ + if(yych <= 'C') goto yy61; + goto yy164; + } else { + if(yych <= 'E') goto yy171; + if(yych <= 'K') goto yy61; + goto yy173; + } + } + } else { + if(yych <= 'e'){ + if(yych <= 'U'){ + if(yych <= 'T') goto yy61; + goto yy172; + } else { + if(yych <= 'c') goto yy61; + if(yych <= 'd') goto yy164; + goto yy171; + } + } else { + if(yych <= 'l'){ + if(yych <= 'k') goto yy61; + goto yy173; + } else { + if(yych == 'u') goto yy172; + goto yy61; + } + } + } +yy63: yyaccept = 4; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '\f'){ + if(yych == '\t') goto yy121; + if(yych <= '\n') goto yy59; + goto yy121; + } else { + if(yych <= '\037') goto yy59; + if(yych == '\'') goto yy59; + goto yy121; + } +yy64: yyaccept = 4; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '\n'){ + if(yych == '\t') goto yy77; + goto yy59; + } else { + if(yych <= '\f') goto yy77; + if(yych <= '\037') goto yy59; + goto yy77; + } +yy65: yych = *++YYCURSOR; + goto yy75; +yy66: +#line 473 + { RET(T_SPACE); } +yy67: yych = *++YYCURSOR; + goto yy68; +yy68: +#line 476 + { + s->line++; + RET(T_NEWLINE); + } +yy69: yych = *++YYCURSOR; + if(yych == '\n') goto yy73; + goto yy68; +yy70: yych = *++YYCURSOR; + goto yy71; +yy71: +#line 482 + { + if(cursor != s->eof) + { + if (0 != s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file\n"); + } + RET(T_EOF); + } +yy72: yych = *++YYCURSOR; + goto yy59; +yy73: yych = *++YYCURSOR; + goto yy68; +yy74: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy75; +yy75: if(yych <= '\n'){ + if(yych == '\t') goto yy74; + goto yy66; + } else { + if(yych <= '\f') goto yy74; + if(yych == ' ') goto yy74; + goto yy66; + } +yy76: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy77; +yy77: if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy78; + } else { + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy78: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy91; + } else { + if(yych != '\\') goto yy76; + goto yy79; + } + } +yy79: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '`'){ + if(yych <= '7'){ + if(yych <= '&'){ + if(yych == '"') goto yy76; + goto yy2; + } else { + if(yych <= '\'') goto yy76; + if(yych <= '/') goto yy2; + goto yy86; + } + } else { + if(yych <= 'T'){ + if(yych == '?') goto yy84; + goto yy2; + } else { + if(yych <= 'U') goto yy83; + if(yych == '\\') goto yy76; + goto yy2; + } + } + } else { + if(yych <= 'r'){ + if(yych <= 'f'){ + if(yych <= 'b') goto yy76; + if(yych <= 'e') goto yy2; + goto yy76; + } else { + if(yych == 'n') goto yy76; + if(yych <= 'q') goto yy2; + goto yy76; + } + } else { + if(yych <= 'u'){ + if(yych <= 's') goto yy2; + if(yych <= 't') goto yy76; + goto yy82; + } else { + if(yych <= 'v') goto yy76; + if(yych == 'x') goto yy85; + goto yy2; + } + } + } +yy80: yych = *++YYCURSOR; + goto yy81; +yy81: +#line 446 + { RET(T_STRINGLIT); } +yy82: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy117; + goto yy2; + } else { + if(yych <= 'F') goto yy117; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy117; + goto yy2; + } +yy83: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy110; + goto yy2; + } else { + if(yych <= 'F') goto yy110; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy110; + goto yy2; + } +yy84: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy90; + } else { + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy85: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy88; + goto yy2; + } else { + if(yych <= 'F') goto yy88; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy88; + goto yy2; + } +yy86: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '"'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + if(yych <= '!') goto yy76; + goto yy80; + } + } else { + if(yych <= '>'){ + if(yych <= '/') goto yy76; + if(yych >= '8') goto yy76; + goto yy87; + } else { + if(yych <= '?') goto yy78; + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy87: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy78; + } else { + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy88: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy89; +yy89: if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy88; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy88; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych <= 'f') goto yy88; + goto yy76; + } + } + } +yy90: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy91; + } else { + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy91: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy92; +yy92: if(yych <= '"'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + if(yych <= '!') goto yy76; + goto yy80; + } + } else { + if(yych <= '>'){ + if(yych != '/') goto yy76; + goto yy93; + } else { + if(yych <= '?') goto yy91; + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy93: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy94; +yy94: if(yych <= '>'){ + if(yych <= '\037'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy2; + goto yy76; + } else { + if(yych <= '\n') goto yy2; + if(yych <= '\f') goto yy76; + goto yy2; + } + } else { + if(yych <= '"'){ + if(yych <= '!') goto yy76; + goto yy97; + } else { + if(yych <= '/') goto yy76; + if(yych <= '7') goto yy86; + goto yy76; + } + } + } else { + if(yych <= '\\'){ + if(yych <= 'T'){ + if(yych <= '?') goto yy98; + goto yy76; + } else { + if(yych <= 'U') goto yy96; + if(yych <= '[') goto yy76; + goto yy93; + } + } else { + if(yych <= 'u'){ + if(yych <= 't') goto yy76; + goto yy95; + } else { + if(yych == 'x') goto yy88; + goto yy76; + } + } + } +yy95: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy107; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy107; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych <= 'f') goto yy107; + goto yy76; + } + } + } +yy96: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy100; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy100; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych <= 'f') goto yy100; + goto yy76; + } + } + } +yy97: yyaccept = 6; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy81; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy81; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy78; + } else { + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy98: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy99; + } else { + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy99: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '"'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + if(yych <= '!') goto yy76; + goto yy80; + } + } else { + if(yych <= '>'){ + if(yych == '/') goto yy93; + goto yy76; + } else { + if(yych <= '?') goto yy91; + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy100: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy101; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy101; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych >= 'g') goto yy76; + goto yy101; + } + } + } +yy101: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy102; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy102; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych >= 'g') goto yy76; + goto yy102; + } + } + } +yy102: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy103; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy103; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych >= 'g') goto yy76; + goto yy103; + } + } + } +yy103: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy104; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy104; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych >= 'g') goto yy76; + goto yy104; + } + } + } +yy104: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy105; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy105; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych >= 'g') goto yy76; + goto yy105; + } + } + } +yy105: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy106; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy106; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych >= 'g') goto yy76; + goto yy106; + } + } + } +yy106: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy78; + } else { + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy107: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy108; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy108; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych >= 'g') goto yy76; + goto yy108; + } + } + } +yy108: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy76; + if(yych <= '\n') goto yy2; + goto yy76; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy76; + } else { + if(yych <= '"') goto yy80; + if(yych <= '/') goto yy76; + goto yy109; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy78; + if(yych <= '@') goto yy76; + goto yy109; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy76; + goto yy79; + } else { + if(yych <= '`') goto yy76; + if(yych >= 'g') goto yy76; + goto yy109; + } + } + } +yy109: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy76; + goto yy2; + } else { + if(yych <= '\f') goto yy76; + if(yych <= '\037') goto yy2; + goto yy76; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy80; + if(yych <= '>') goto yy76; + goto yy78; + } else { + if(yych == '\\') goto yy79; + goto yy76; + } + } +yy110: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy111; + } else { + if(yych <= 'F') goto yy111; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy111; + } +yy111: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy112; + } else { + if(yych <= 'F') goto yy112; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy112; + } +yy112: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy113; + } else { + if(yych <= 'F') goto yy113; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy113; + } +yy113: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy114; + } else { + if(yych <= 'F') goto yy114; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy114; + } +yy114: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy115; + } else { + if(yych <= 'F') goto yy115; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy115; + } +yy115: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy116; + } else { + if(yych <= 'F') goto yy116; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy116; + } +yy116: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy76; + goto yy2; + } else { + if(yych <= 'F') goto yy76; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy76; + goto yy2; + } +yy117: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy118; + } else { + if(yych <= 'F') goto yy118; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy118; + } +yy118: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy119; + } else { + if(yych <= 'F') goto yy119; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy119; + } +yy119: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy76; + goto yy2; + } else { + if(yych <= 'F') goto yy76; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy76; + goto yy2; + } +yy120: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy121; +yy121: if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy122; + } else { + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy122: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy135; + } else { + if(yych != '\\') goto yy120; + goto yy123; + } + } +yy123: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '`'){ + if(yych <= '7'){ + if(yych <= '&'){ + if(yych == '"') goto yy120; + goto yy2; + } else { + if(yych <= '\'') goto yy120; + if(yych <= '/') goto yy2; + goto yy128; + } + } else { + if(yych <= 'T'){ + if(yych == '?') goto yy126; + goto yy2; + } else { + if(yych <= 'U') goto yy125; + if(yych == '\\') goto yy120; + goto yy2; + } + } + } else { + if(yych <= 'r'){ + if(yych <= 'f'){ + if(yych <= 'b') goto yy120; + if(yych <= 'e') goto yy2; + goto yy120; + } else { + if(yych == 'n') goto yy120; + if(yych <= 'q') goto yy2; + goto yy120; + } + } else { + if(yych <= 'u'){ + if(yych <= 's') goto yy2; + if(yych <= 't') goto yy120; + goto yy124; + } else { + if(yych <= 'v') goto yy120; + if(yych == 'x') goto yy127; + goto yy2; + } + } + } +yy124: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy161; + goto yy2; + } else { + if(yych <= 'F') goto yy161; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy161; + goto yy2; + } +yy125: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy154; + goto yy2; + } else { + if(yych <= 'F') goto yy154; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy154; + goto yy2; + } +yy126: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy134; + } else { + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy127: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy132; + goto yy2; + } else { + if(yych <= 'F') goto yy132; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy132; + goto yy2; + } +yy128: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '\''){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + if(yych <= '&') goto yy120; + goto yy130; + } + } else { + if(yych <= '>'){ + if(yych <= '/') goto yy120; + if(yych >= '8') goto yy120; + goto yy129; + } else { + if(yych <= '?') goto yy122; + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy129: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy122; + } else { + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy130: yych = *++YYCURSOR; + goto yy131; +yy131: +#line 443 + { RET(T_CHARLIT); } +yy132: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy133; +yy133: if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy132; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy132; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych <= 'f') goto yy132; + goto yy120; + } + } + } +yy134: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy135; + } else { + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy135: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy136; +yy136: if(yych <= '\''){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + if(yych <= '&') goto yy120; + goto yy130; + } + } else { + if(yych <= '>'){ + if(yych != '/') goto yy120; + goto yy137; + } else { + if(yych <= '?') goto yy135; + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy137: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy138; +yy138: if(yych <= '>'){ + if(yych <= '\037'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy2; + goto yy120; + } else { + if(yych <= '\n') goto yy2; + if(yych <= '\f') goto yy120; + goto yy2; + } + } else { + if(yych <= '\''){ + if(yych <= '&') goto yy120; + goto yy141; + } else { + if(yych <= '/') goto yy120; + if(yych <= '7') goto yy128; + goto yy120; + } + } + } else { + if(yych <= '\\'){ + if(yych <= 'T'){ + if(yych <= '?') goto yy142; + goto yy120; + } else { + if(yych <= 'U') goto yy140; + if(yych <= '[') goto yy120; + goto yy137; + } + } else { + if(yych <= 'u'){ + if(yych <= 't') goto yy120; + goto yy139; + } else { + if(yych == 'x') goto yy132; + goto yy120; + } + } + } +yy139: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy151; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy151; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych <= 'f') goto yy151; + goto yy120; + } + } + } +yy140: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy144; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy144; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych <= 'f') goto yy144; + goto yy120; + } + } + } +yy141: yyaccept = 7; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy131; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy131; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy122; + } else { + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy142: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy143; + } else { + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy143: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '\''){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + if(yych <= '&') goto yy120; + goto yy130; + } + } else { + if(yych <= '>'){ + if(yych == '/') goto yy137; + goto yy120; + } else { + if(yych <= '?') goto yy135; + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy144: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy145; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy145; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych >= 'g') goto yy120; + goto yy145; + } + } + } +yy145: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy146; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy146; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych >= 'g') goto yy120; + goto yy146; + } + } + } +yy146: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy147; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy147; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych >= 'g') goto yy120; + goto yy147; + } + } + } +yy147: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy148; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy148; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych >= 'g') goto yy120; + goto yy148; + } + } + } +yy148: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy149; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy149; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych >= 'g') goto yy120; + goto yy149; + } + } + } +yy149: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy150; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy150; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych >= 'g') goto yy120; + goto yy150; + } + } + } +yy150: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy122; + } else { + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy151: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy152; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy152; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych >= 'g') goto yy120; + goto yy152; + } + } + } +yy152: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy120; + if(yych <= '\n') goto yy2; + goto yy120; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy120; + } else { + if(yych <= '\'') goto yy130; + if(yych <= '/') goto yy120; + goto yy153; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy122; + if(yych <= '@') goto yy120; + goto yy153; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy120; + goto yy123; + } else { + if(yych <= '`') goto yy120; + if(yych >= 'g') goto yy120; + goto yy153; + } + } + } +yy153: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy120; + goto yy2; + } else { + if(yych <= '\f') goto yy120; + if(yych <= '\037') goto yy2; + goto yy120; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy130; + if(yych <= '>') goto yy120; + goto yy122; + } else { + if(yych == '\\') goto yy123; + goto yy120; + } + } +yy154: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy155; + } else { + if(yych <= 'F') goto yy155; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy155; + } +yy155: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy156; + } else { + if(yych <= 'F') goto yy156; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy156; + } +yy156: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy157; + } else { + if(yych <= 'F') goto yy157; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy157; + } +yy157: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy158; + } else { + if(yych <= 'F') goto yy158; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy158; + } +yy158: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy159; + } else { + if(yych <= 'F') goto yy159; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy159; + } +yy159: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy160; + } else { + if(yych <= 'F') goto yy160; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy160; + } +yy160: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy120; + goto yy2; + } else { + if(yych <= 'F') goto yy120; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy120; + goto yy2; + } +yy161: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy162; + } else { + if(yych <= 'F') goto yy162; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy162; + } +yy162: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy163; + } else { + if(yych <= 'F') goto yy163; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy163; + } +yy163: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy120; + goto yy2; + } else { + if(yych <= 'F') goto yy120; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy120; + goto yy2; + } +yy164: yych = *++YYCURSOR; + goto yy165; +yy165: +#line 440 + { RET(T_FIXEDPOINTLIT); } +yy166: yyaccept = 5; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy167; +yy167: if(yych <= 'L'){ + if(yych <= '9'){ + if(yych == '.') goto yy168; + if(yych <= '/') goto yy61; + goto yy166; + } else { + if(yych <= 'D'){ + if(yych <= 'C') goto yy61; + goto yy164; + } else { + if(yych <= 'E') goto yy171; + if(yych <= 'K') goto yy61; + goto yy173; + } + } + } else { + if(yych <= 'e'){ + if(yych <= 'U'){ + if(yych <= 'T') goto yy61; + goto yy172; + } else { + if(yych <= 'c') goto yy61; + if(yych <= 'd') goto yy164; + goto yy171; + } + } else { + if(yych <= 'l'){ + if(yych <= 'k') goto yy61; + goto yy173; + } else { + if(yych == 'u') goto yy172; + goto yy61; + } + } + } +yy168: yyaccept = 8; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy169; +yy169: if(yych <= 'K'){ + if(yych <= 'C'){ + if(yych <= '/') goto yy170; + if(yych <= '9') goto yy168; + goto yy170; + } else { + if(yych <= 'D') goto yy164; + if(yych <= 'E') goto yy181; + if(yych <= 'F') goto yy178; + goto yy170; + } + } else { + if(yych <= 'e'){ + if(yych <= 'L') goto yy179; + if(yych <= 'c') goto yy170; + if(yych <= 'd') goto yy164; + goto yy181; + } else { + if(yych <= 'f') goto yy178; + if(yych == 'l') goto yy179; + goto yy170; + } + } +yy170: +#line 437 + { RET(T_FLOATLIT); } +yy171: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych == '+') goto yy175; + goto yy2; + } else { + if(yych <= '-') goto yy175; + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy176; + goto yy2; + } +yy172: yych = *++YYCURSOR; + if(yych == 'L') goto yy174; + if(yych == 'l') goto yy174; + goto yy61; +yy173: yych = *++YYCURSOR; + if(yych == 'U') goto yy174; + if(yych != 'u') goto yy61; + goto yy174; +yy174: yych = *++YYCURSOR; + goto yy61; +yy175: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy176; +yy176: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy177; +yy177: if(yych <= 'K'){ + if(yych <= '9'){ + if(yych <= '/') goto yy170; + goto yy176; + } else { + if(yych != 'F') goto yy170; + goto yy178; + } + } else { + if(yych <= 'f'){ + if(yych <= 'L') goto yy179; + if(yych <= 'e') goto yy170; + goto yy178; + } else { + if(yych == 'l') goto yy179; + goto yy170; + } + } +yy178: yych = *++YYCURSOR; + if(yych == 'L') goto yy180; + if(yych == 'l') goto yy180; + goto yy170; +yy179: yych = *++YYCURSOR; + if(yych == 'F') goto yy180; + if(yych != 'f') goto yy170; + goto yy180; +yy180: yych = *++YYCURSOR; + goto yy170; +yy181: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; + goto yy182; + } else { + if(yych <= '-') goto yy182; + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy183; + goto yy2; + } +yy182: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy183; +yy183: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy184; +yy184: if(yych <= 'K'){ + if(yych <= '9'){ + if(yych <= '/') goto yy170; + goto yy183; + } else { + if(yych == 'F') goto yy178; + goto yy170; + } + } else { + if(yych <= 'f'){ + if(yych <= 'L') goto yy179; + if(yych <= 'e') goto yy170; + goto yy178; + } else { + if(yych == 'l') goto yy179; + goto yy170; + } + } +yy185: yyaccept = 5; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy186; +yy186: if(yych <= 'L'){ + if(yych <= '9'){ + if(yych <= '.'){ + if(yych <= '-') goto yy61; + goto yy168; + } else { + if(yych <= '/') goto yy61; + if(yych <= '7') goto yy185; + goto yy187; + } + } else { + if(yych <= 'D'){ + if(yych <= 'C') goto yy61; + goto yy164; + } else { + if(yych <= 'E') goto yy171; + if(yych <= 'K') goto yy61; + goto yy173; + } + } + } else { + if(yych <= 'e'){ + if(yych <= 'U'){ + if(yych <= 'T') goto yy61; + goto yy172; + } else { + if(yych <= 'c') goto yy61; + if(yych <= 'd') goto yy164; + goto yy171; + } + } else { + if(yych <= 'l'){ + if(yych <= 'k') goto yy61; + goto yy173; + } else { + if(yych == 'u') goto yy172; + goto yy61; + } + } + } +yy187: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy188; +yy188: if(yych <= 'C'){ + if(yych <= '.'){ + if(yych <= '-') goto yy2; + goto yy168; + } else { + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy187; + goto yy2; + } + } else { + if(yych <= 'c'){ + if(yych <= 'D') goto yy164; + if(yych <= 'E') goto yy171; + goto yy2; + } else { + if(yych <= 'd') goto yy164; + if(yych <= 'e') goto yy171; + goto yy2; + } + } +yy189: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy190; + } else { + if(yych <= 'F') goto yy190; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy190; + } +yy190: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy191; +yy191: if(yych <= 'T'){ + if(yych <= '@'){ + if(yych <= '/') goto yy61; + if(yych <= '9') goto yy190; + goto yy61; + } else { + if(yych <= 'F') goto yy190; + if(yych == 'L') goto yy173; + goto yy61; + } + } else { + if(yych <= 'k'){ + if(yych <= 'U') goto yy172; + if(yych <= '`') goto yy61; + if(yych <= 'f') goto yy190; + goto yy61; + } else { + if(yych <= 'l') goto yy173; + if(yych == 'u') goto yy172; + goto yy61; + } + } +yy192: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy218; + goto yy2; + } else { + if(yych <= 'F') goto yy218; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy218; + goto yy2; + } +yy193: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy194; + } else { + if(yych <= 'F') goto yy194; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy194; + } +yy194: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy195; + } else { + if(yych <= 'F') goto yy195; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy195; + } +yy195: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy196; + } else { + if(yych <= 'F') goto yy196; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy196; + } +yy196: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy197; + } else { + if(yych <= 'F') goto yy197; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy197; + } +yy197: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy198; + } else { + if(yych <= 'F') goto yy198; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy198; + } +yy198: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy199; + } else { + if(yych <= 'F') goto yy199; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy199; + } +yy199: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy200; + } else { + if(yych <= 'F') goto yy200; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy200; + } +yy200: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy201; + } else { + if(yych <= 'F') goto yy201; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy201; + } +yy201: yyaccept = 0; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy202; +yy202: if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy6; + if(yych <= '9') goto yy201; + goto yy6; + } else { + if(yych <= '?') goto yy204; + if(yych <= '@') goto yy6; + goto yy201; + } + } else { + if(yych <= '^'){ + if(yych != '\\') goto yy6; + goto yy203; + } else { + if(yych == '`') goto yy6; + if(yych <= 'z') goto yy201; + goto yy6; + } + } +yy203: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == 'U') goto yy207; + if(yych == 'u') goto yy206; + goto yy2; +yy204: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych != '?') goto yy2; + goto yy205; +yy205: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '/') goto yy203; + goto yy2; +yy206: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy215; + goto yy2; + } else { + if(yych <= 'F') goto yy215; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy215; + goto yy2; + } +yy207: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy208; + } else { + if(yych <= 'F') goto yy208; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy208; + } +yy208: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy209; + } else { + if(yych <= 'F') goto yy209; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy209; + } +yy209: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy210; + } else { + if(yych <= 'F') goto yy210; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy210; + } +yy210: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy211; + } else { + if(yych <= 'F') goto yy211; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy211; + } +yy211: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy212; + } else { + if(yych <= 'F') goto yy212; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy212; + } +yy212: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy213; + } else { + if(yych <= 'F') goto yy213; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy213; + } +yy213: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy214; + } else { + if(yych <= 'F') goto yy214; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy214; + } +yy214: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy201; + goto yy2; + } else { + if(yych <= 'F') goto yy201; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy201; + goto yy2; + } +yy215: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy216; + } else { + if(yych <= 'F') goto yy216; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy216; + } +yy216: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy217; + } else { + if(yych <= 'F') goto yy217; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy217; + } +yy217: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy201; + goto yy2; + } else { + if(yych <= 'F') goto yy201; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy201; + goto yy2; + } +yy218: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy219; + } else { + if(yych <= 'F') goto yy219; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy219; + } +yy219: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy220; + } else { + if(yych <= 'F') goto yy220; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy220; + } +yy220: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy201; + goto yy2; + } else { + if(yych <= 'F') goto yy201; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy201; + goto yy2; + } +yy221: yych = *++YYCURSOR; + if(yych == '\'') goto yy2; + goto yy121; +yy222: yych = *++YYCURSOR; + goto yy223; +yy223: +#line 423 + { RET(T_GREATEREQUAL); } +yy224: yych = *++YYCURSOR; + goto yy225; +yy225: +#line 419 + { RET(T_SHIFTRIGHT); } +yy226: yych = *++YYCURSOR; + goto yy227; +yy227: +#line 422 + { RET(T_LESSEQUAL); } +yy228: yych = *++YYCURSOR; + goto yy229; +yy229: +#line 418 + { RET(T_SHIFTLEFT); } +yy230: yych = *++YYCURSOR; + goto yy231; +yy231: +#line 420 + { RET(T_EQUAL); } +yy232: yych = *++YYCURSOR; + goto yy233; +yy233: +#line 421 + { RET(T_NOTEQUAL); } +yy234: yych = *++YYCURSOR; + goto yy235; +yy235: +#line 425 + { RET(T_OROR); } +yy236: yych = *++YYCURSOR; + goto yy237; +yy237: +#line 424 + { RET(T_ANDAND); } +yy238: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy239; +yy239: if(yych <= 'h'){ + if(yych <= '.'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy2; + goto yy238; + } else { + if(yych == ' ') goto yy238; + goto yy2; + } + } else { + if(yych <= 'c'){ + if(yych >= '0') goto yy2; + goto yy240; + } else { + if(yych <= 'd') goto yy243; + if(yych <= 'e') goto yy242; + goto yy2; + } + } + } else { + if(yych <= 'p'){ + if(yych <= 'k'){ + if(yych <= 'i') goto yy241; + goto yy2; + } else { + if(yych <= 'l') goto yy245; + if(yych <= 'o') goto yy2; + goto yy246; + } + } else { + if(yych <= 'u'){ + if(yych <= 't') goto yy2; + goto yy244; + } else { + if(yych == 'w') goto yy247; + goto yy2; + } + } + } +yy240: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '*') goto yy330; + goto yy2; +yy241: yych = *++YYCURSOR; + if(yych == 'f') goto yy293; + if(yych == 'n') goto yy295; + goto yy2; +yy242: yych = *++YYCURSOR; + if(yych <= 'm'){ + if(yych == 'l') goto yy278; + goto yy2; + } else { + if(yych <= 'n') goto yy277; + if(yych == 'r') goto yy276; + goto yy2; + } +yy243: yych = *++YYCURSOR; + if(yych == 'e') goto yy270; + goto yy2; +yy244: yych = *++YYCURSOR; + if(yych == 'n') goto yy265; + goto yy2; +yy245: yych = *++YYCURSOR; + if(yych == 'i') goto yy261; + goto yy2; +yy246: yych = *++YYCURSOR; + if(yych == 'r') goto yy255; + goto yy2; +yy247: yych = *++YYCURSOR; + if(yych != 'a') goto yy2; + goto yy248; +yy248: yych = *++YYCURSOR; + if(yych != 'r') goto yy2; + goto yy249; +yy249: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy250; +yy250: yych = *++YYCURSOR; + if(yych != 'i') goto yy2; + goto yy251; +yy251: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy252; +yy252: yych = *++YYCURSOR; + if(yych != 'g') goto yy2; + goto yy253; +yy253: yych = *++YYCURSOR; + goto yy254; +yy254: +#line 470 + { RET(T_PP_WARNING); } +yy255: yych = *++YYCURSOR; + if(yych != 'a') goto yy2; + goto yy256; +yy256: yych = *++YYCURSOR; + if(yych != 'g') goto yy2; + goto yy257; +yy257: yych = *++YYCURSOR; + if(yych != 'm') goto yy2; + goto yy258; +yy258: yych = *++YYCURSOR; + if(yych != 'a') goto yy2; + goto yy259; +yy259: yych = *++YYCURSOR; + goto yy260; +yy260: +#line 468 + { RET(T_PP_PRAGMA); } +yy261: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy262; +yy262: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy263; +yy263: yych = *++YYCURSOR; + goto yy264; +yy264: +#line 466 + { RET(T_PP_LINE); } +yy265: yych = *++YYCURSOR; + if(yych != 'd') goto yy2; + goto yy266; +yy266: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy267; +yy267: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy268; +yy268: yych = *++YYCURSOR; + goto yy269; +yy269: +#line 465 + { RET(T_PP_UNDEF); } +yy270: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy271; +yy271: yych = *++YYCURSOR; + if(yych != 'i') goto yy2; + goto yy272; +yy272: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy273; +yy273: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy274; +yy274: yych = *++YYCURSOR; + goto yy275; +yy275: +#line 464 + { RET(T_PP_DEFINE); } +yy276: yych = *++YYCURSOR; + if(yych == 'r') goto yy289; + goto yy2; +yy277: yych = *++YYCURSOR; + if(yych == 'd') goto yy285; + goto yy2; +yy278: yych = *++YYCURSOR; + if(yych == 'i') goto yy280; + if(yych != 's') goto yy2; + goto yy279; +yy279: yych = *++YYCURSOR; + if(yych == 'e') goto yy283; + goto yy2; +yy280: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy281; +yy281: yych = *++YYCURSOR; + goto yy282; +yy282: +#line 462 + { RET(T_PP_ELIF); } +yy283: yych = *++YYCURSOR; + goto yy284; +yy284: +#line 461 + { RET(T_PP_ELSE); } +yy285: yych = *++YYCURSOR; + if(yych != 'i') goto yy2; + goto yy286; +yy286: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy287; +yy287: yych = *++YYCURSOR; + goto yy288; +yy288: +#line 463 + { RET(T_PP_ENDIF); } +yy289: yych = *++YYCURSOR; + if(yych != 'o') goto yy2; + goto yy290; +yy290: yych = *++YYCURSOR; + if(yych != 'r') goto yy2; + goto yy291; +yy291: yych = *++YYCURSOR; + goto yy292; +yy292: +#line 467 + { RET(T_PP_ERROR); } +yy293: yyaccept = 9; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'd') goto yy321; + if(yych == 'n') goto yy322; + goto yy294; +yy294: +#line 458 + { RET(T_PP_IF); } +yy295: yych = *++YYCURSOR; + if(yych != 'c') goto yy2; + goto yy296; +yy296: yych = *++YYCURSOR; + if(yych != 'l') goto yy2; + goto yy297; +yy297: yych = *++YYCURSOR; + if(yych != 'u') goto yy2; + goto yy298; +yy298: yych = *++YYCURSOR; + if(yych != 'd') goto yy2; + goto yy299; +yy299: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy300; +yy300: yyaccept = 10; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy301; +yy301: if(yych <= '!'){ + if(yych <= '\t'){ + if(yych >= '\t') goto yy300; + goto yy302; + } else { + if(yych == ' ') goto yy300; + goto yy302; + } + } else { + if(yych <= '/'){ + if(yych <= '"') goto yy304; + if(yych >= '/') goto yy303; + goto yy302; + } else { + if(yych == '<') goto yy305; + goto yy302; + } + } +yy302: +#line 456 + { RET(T_PP_INCLUDE); } +yy303: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '*') goto yy314; + goto yy2; +yy304: yych = *++YYCURSOR; + if(yych == '"') goto yy2; + goto yy311; +yy305: yych = *++YYCURSOR; + if(yych == '>') goto yy2; + goto yy307; +yy306: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy307; +yy307: if(yych <= '\f'){ + if(yych == '\t') goto yy306; + if(yych <= '\n') goto yy2; + goto yy306; + } else { + if(yych <= '\037') goto yy2; + if(yych != '>') goto yy306; + goto yy308; + } +yy308: yych = *++YYCURSOR; + goto yy309; +yy309: +#line 450 + { RET(T_PP_HHEADER); } +yy310: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy311; +yy311: if(yych <= '\f'){ + if(yych == '\t') goto yy310; + if(yych <= '\n') goto yy2; + goto yy310; + } else { + if(yych <= '\037') goto yy2; + if(yych != '"') goto yy310; + goto yy312; + } +yy312: yych = *++YYCURSOR; + goto yy313; +yy313: +#line 453 + { RET(T_PP_QHEADER); } +yy314: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy315; +yy315: if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy314; + goto yy316; + } else { + if(yych <= '\037') goto yy2; + if(yych == '*') goto yy318; + goto yy314; + } +yy316: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy317; +yy317: if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy314; + goto yy316; + } else { + if(yych <= '\037') goto yy2; + if(yych != '*') goto yy314; + goto yy318; + } +yy318: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy319; +yy319: if(yych <= '\037'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy314; + if(yych >= '\016') goto yy2; + goto yy320; + } else { + if(yych <= '*'){ + if(yych <= ')') goto yy314; + goto yy318; + } else { + if(yych == '/') goto yy300; + goto yy314; + } + } +yy320: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy314; + goto yy316; + } else { + if(yych <= '\037') goto yy2; + if(yych == '*') goto yy318; + goto yy314; + } +yy321: yych = *++YYCURSOR; + if(yych == 'e') goto yy327; + goto yy2; +yy322: yych = *++YYCURSOR; + if(yych != 'd') goto yy2; + goto yy323; +yy323: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy324; +yy324: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy325; +yy325: yych = *++YYCURSOR; + goto yy326; +yy326: +#line 460 + { RET(T_PP_IFNDEF); } +yy327: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy328; +yy328: yych = *++YYCURSOR; + goto yy329; +yy329: +#line 459 + { RET(T_PP_IFDEF); } +yy330: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy331; +yy331: if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy330; + goto yy332; + } else { + if(yych <= '\037') goto yy2; + if(yych == '*') goto yy334; + goto yy330; + } +yy332: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy333; +yy333: if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy330; + goto yy332; + } else { + if(yych <= '\037') goto yy2; + if(yych != '*') goto yy330; + goto yy334; + } +yy334: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy335; +yy335: if(yych <= '\037'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy330; + if(yych >= '\016') goto yy2; + goto yy336; + } else { + if(yych <= '*'){ + if(yych <= ')') goto yy330; + goto yy334; + } else { + if(yych == '/') goto yy238; + goto yy330; + } + } +yy336: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy330; + goto yy332; + } else { + if(yych <= '\037') goto yy2; + if(yych == '*') goto yy334; + goto yy330; + } +yy337: yych = *++YYCURSOR; + goto yy338; +yy338: +#line 427 + { RET(T_MINUSMINUS); } +yy339: yych = *++YYCURSOR; + goto yy340; +yy340: +#line 426 + { RET(T_PLUSPLUS); } +yy341: yych = *++YYCURSOR; + if(yych == '/') goto yy342; + if(yych == '=') goto yy238; + goto yy2; +yy342: yych = *++YYCURSOR; + if(yych == 'U') goto yy193; + if(yych == 'u') goto yy192; + goto yy2; +yy343: yych = *++YYCURSOR; + goto yy344; +yy344: +#line 398 + { RET(T_POUND_POUND); } +yy345: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'L') goto yy202; + goto yy346; +yy346: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'S') goto yy202; + goto yy347; +yy347: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'E') goto yy202; + goto yy348; +yy348: yyaccept = 11; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy349; + if(yych <= '9') goto yy201; + goto yy349; + } else { + if(yych <= '?') goto yy204; + if(yych >= 'A') goto yy201; + goto yy349; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy203; + goto yy349; + } else { + if(yych == '`') goto yy349; + if(yych <= 'z') goto yy201; + goto yy349; + } + } +yy349: +#line 391 + { RET(T_FALSE); } +yy350: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'U') goto yy202; + goto yy351; +yy351: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'E') goto yy202; + goto yy352; +yy352: yyaccept = 12; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy353; + if(yych <= '9') goto yy201; + goto yy353; + } else { + if(yych <= '?') goto yy204; + if(yych >= 'A') goto yy201; + goto yy353; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy203; + goto yy353; + } else { + if(yych == '`') goto yy353; + if(yych <= 'z') goto yy201; + goto yy353; + } + } +yy353: +#line 390 + { RET(T_TRUE); } +yy354: yych = *++YYCURSOR; + goto yy355; +yy355: +#line 388 + { goto cppcomment; } +yy356: yych = *++YYCURSOR; + goto yy357; +yy357: +#line 387 + { goto ccomment; } +} +#line 502 + + +ccomment: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy358; +yy359: ++YYCURSOR; +yy358: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '\f'){ + if(yych <= '\b'){ + if(yych <= '\000') goto yy367; + goto yy360; + } else { + if(yych == '\n') goto yy363; + goto yy366; + } + } else { + if(yych <= '\037'){ + if(yych <= '\r') goto yy365; + goto yy360; + } else { + if(yych == '*') goto yy361; + goto yy366; + } + } +yy360:yy361: yych = *++YYCURSOR; + if(yych == '/') goto yy370; + goto yy362; +yy362: +#line 515 + { goto ccomment; } +yy363: yych = *++YYCURSOR; + goto yy364; +yy364: +#line 508 + { + /*if(cursor == s->eof) RET(T_EOF);*/ + /*s->tok = cursor; */ + s->line += count_backslash_newlines(s, cursor) +1; + goto ccomment; + } +yy365: yych = *++YYCURSOR; + if(yych == '\n') goto yy369; + goto yy364; +yy366: yych = *++YYCURSOR; + goto yy362; +yy367: yych = *++YYCURSOR; + goto yy368; +yy368: +#line 518 + { + yyaccept = 0; /* avoid warning about unreferenced variable */ + if(cursor == s->eof) + { + if (s->error_proc) + (*s->error_proc)(s, "Unterminated comment"); + else + printf("Error: Unterminated comment\n"); + } + else + { + if (s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file"); + } + /* adjust cursor such next call returns T_EOF */ + --YYCURSOR; + /* the comment is unterminated, but nevertheless its a comment */ + RET(T_CCOMMENT); + } +yy369: yych = *++YYCURSOR; + goto yy364; +yy370: yych = *++YYCURSOR; + goto yy371; +yy371: +#line 506 + { RET(T_CCOMMENT); } +} +#line 540 + + +cppcomment: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy372; +yy373: ++YYCURSOR; +yy372: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '\n'){ + if(yych <= '\000') goto yy380; + if(yych <= '\b') goto yy374; + if(yych <= '\t') goto yy378; + goto yy375; + } else { + if(yych <= '\f') goto yy378; + if(yych <= '\r') goto yy377; + if(yych >= ' ') goto yy378; + goto yy374; + } +yy374:yy375: yych = *++YYCURSOR; + goto yy376; +yy376: +#line 545 + { + /*if(cursor == s->eof) RET(T_EOF); */ + /*s->tok = cursor; */ + s->line++; + RET(T_CPPCOMMENT); + } +yy377: yych = *++YYCURSOR; + if(yych == '\n') goto yy382; + goto yy376; +yy378: yych = *++YYCURSOR; + goto yy379; +yy379: +#line 552 + { goto cppcomment; } +yy380: yych = *++YYCURSOR; + goto yy381; +yy381: +#line 555 + { + yyaccept = 0; /* avoid warning about unreferenced variable */ + if(cursor != s->eof) + { + if (s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file"); + } + /* adjust cursor such next call returns T_EOF */ + --YYCURSOR; + /* the comment is unterminated, but nevertheless its a comment */ + RET(T_CPPCOMMENT); + } +yy382: yych = *++YYCURSOR; + goto yy376; +} +#line 569 + + +} /* end of scan */ + +#undef RE2C_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace idllexer +} // namespace wave +} // namespace boost diff --git a/samples/waveidl/idllexer/idl.re.hpp b/samples/waveidl/idllexer/idl.re.hpp new file mode 100644 index 000000000..a90f7244e --- /dev/null +++ b/samples/waveidl/idllexer/idl.re.hpp @@ -0,0 +1,35 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: Re2C based IDL lexer + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(IDL_RE_HPP_BD62775D_1659_4684_872C_03C02543C9A5_INCLUDED) +#define IDL_RE_HPP_BD62775D_1659_4684_872C_03C02543C9A5_INCLUDED + +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace idllexer { +namespace re2clex { + +/////////////////////////////////////////////////////////////////////////////// +// The scanner function to call whenever a new token is requested +boost::wave::token_id scan( + boost::wave::cpplexer::re2clex::Scanner *s); + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace idllexer +} // namespace wave +} // namespace boost + +#endif // !defined(IDL_RE_HPP_BD62775D_1659_4684_872C_03C02543C9A5_INCLUDED) diff --git a/samples/waveidl/idllexer/idl_lex_interface.hpp b/samples/waveidl/idllexer/idl_lex_interface.hpp new file mode 100644 index 000000000..596d7a915 --- /dev/null +++ b/samples/waveidl/idllexer/idl_lex_interface.hpp @@ -0,0 +1,83 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Definition of the abstract lexer interface + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED) +#define CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace idllexer { + +/////////////////////////////////////////////////////////////////////////////// +// +// new_lexer_gen: generates a new instance of the required C++ lexer +// +/////////////////////////////////////////////////////////////////////////////// +template struct lex_input_interface; + +template < + typename IteratorT, + typename PositionT = boost::wave::util::file_position_type +> +struct new_lexer_gen +{ +// The NewLexer function allows the opaque generation of a new lexer object. +// It is coupled to the token type to allow to decouple the lexer/token +// configurations at compile time. + static lex_input_interface< + boost::wave::cpplexer::lex_token + > * + new_lexer(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// The lex_input_interface decouples the lex_iterator_shim from the actual +// lexer. This is done to allow compile time reduction. +// Thanks to JCAB for having this idea. +// +/////////////////////////////////////////////////////////////////////////////// + +template +struct lex_input_interface +{ + typedef typename TokenT::position_type position_type; + + virtual TokenT get() = 0; + virtual void set_position(position_type const &pos) = 0; + + virtual ~lex_input_interface() {} + +// The new_lexer function allows the opaque generation of a new lexer object. +// It is coupled to the token type to allow to distinguish different +// lexer/token configurations at compile time. + template + static lex_input_interface * + new_lexer(IteratorT const &first, IteratorT const &last, + position_type const &pos, boost::wave::language_support language) + { + return new_lexer_gen::new_lexer (first, last, + pos, language); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#endif // !defined(CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED) diff --git a/samples/waveidl/idllexer/idl_lex_iterator.hpp b/samples/waveidl/idllexer/idl_lex_iterator.hpp new file mode 100644 index 000000000..9354c9b0b --- /dev/null +++ b/samples/waveidl/idllexer/idl_lex_iterator.hpp @@ -0,0 +1,136 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: Re2C based IDL lexer + Definition of the lexer iterator + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(IDL_LEX_ITERATOR_HPP_7926F865_E02F_4950_9EB5_5F453C9FF953_INCLUDED) +#define IDL_LEX_ITERATOR_HPP_7926F865_E02F_4950_9EB5_5F453C9FF953_INCLUDED + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "idl_lex_interface.hpp" + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace idllexer { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_iterator_functor_shim +// +/////////////////////////////////////////////////////////////////////////////// + +template +class lex_iterator_functor_shim +{ + typedef lex_input_interface lex_input_interface_t; + +public: + template + lex_iterator_functor_shim(IteratorT const &first, IteratorT const &last, + typename TokenT::position_type const &pos, + boost::wave::language_support language) + : functor_ptr(lex_input_interface_t::new_lexer(first, last, pos, language)) + {} + +// interface to the boost::spirit::multi_pass_policies::functor_input policy + typedef TokenT result_type; + + static result_type const eof; + + result_type operator()() + { + BOOST_ASSERT(0 != functor_ptr.get()); + return functor_ptr->get(); + } + void set_position(typename TokenT::position_type const &pos) + { + BOOST_ASSERT(0 != functor_ptr.get()); + functor_ptr->set_position(pos); + } + +private: + boost::shared_ptr functor_ptr; +}; + +/////////////////////////////////////////////////////////////////////////////// +// eof token +template +typename lex_iterator_functor_shim::result_type const + lex_iterator_functor_shim::eof; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_iterator +// +// A generic C++ lexer interface class, which allows to plug in different +// lexer implementations (template parameter LexT). The following +// requirement apply: +// +// - the lexer type should have a function implemented, which returnes +// the next lexed token from the input stream: +// typename LexT::token_type get(); +// - at the end of the input stream this function should return the +// eof token equivalent +// - the lexer should implement a constructor taking two iterators +// pointing to the beginning and the end of the input stream and +// a third parameter containing the name of the parsed input file +// +/////////////////////////////////////////////////////////////////////////////// + +template +class lex_iterator +: public boost::spirit::multi_pass< + impl::lex_iterator_functor_shim, + boost::wave::util::functor_input + > +{ + typedef impl::lex_iterator_functor_shim input_policy_type; + typedef + boost::spirit::multi_pass + base_t; + typedef lex_iterator self_type; + +public: + typedef TokenT token_type; + + lex_iterator() + {} + + template + lex_iterator(IteratorT const &first, IteratorT const &last, + typename TokenT::position_type const &pos, + boost::wave::language_support language) + : base_t(input_policy_type(first, last, pos, language)) + {} +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace idllexer +} // namespace wave +} // namespace boost + +#endif // !defined(IDL_LEX_ITERATOR_HPP_7926F865_E02F_4950_9EB5_5F453C9FF953_INCLUDED) diff --git a/samples/waveidl/idllexer/idl_re2c_lexer.hpp b/samples/waveidl/idllexer/idl_re2c_lexer.hpp new file mode 100644 index 000000000..3849b7999 --- /dev/null +++ b/samples/waveidl/idllexer/idl_re2c_lexer.hpp @@ -0,0 +1,263 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Re2C based IDL lexer + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(IDL_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED) +#define IDL_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED + +#include +#include +#include +#if defined(BOOST_SPIRIT_DEBUG) +#include +#endif // defined(BOOST_SPIRIT_DEBUG) + +#include +#include +#include + +#include +#include +#include +#include +#include + +// reuse the default token type and re2c lexer helpers +#include +#include +#include + +#include "idl.re.hpp" + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace idllexer { +namespace re2clex { + +/////////////////////////////////////////////////////////////////////////////// +// +// encapsulation of the re2c based idl lexer +// +/////////////////////////////////////////////////////////////////////////////// + +template < + typename IteratorT, + typename PositionT = boost::wave::util::file_position_type +> +class lexer +{ + typedef boost::wave::cpplexer::re2clex::Scanner scanner_t; + +public: + + typedef char char_t; + typedef boost::wave::cpplexer::re2clex::Scanner base_t; + typedef boost::wave::cpplexer::lex_token token_type; + typedef typename token_type::string_type string_type; + + lexer(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language); + ~lexer(); + + boost::wave::cpplexer::lex_token get(); + void set_position(PositionT const &pos) + { + filename = pos.get_file(); + scanner.line = pos.get_line(); + scanner.file_name = filename.c_str(); + } + +// error reporting from the re2c generated lexer + static int report_error(scanner_t *s, char *, ...); + +private: + static char const *tok_names[]; + + scanner_t scanner; + string_type filename; + bool at_eof; +}; + +/////////////////////////////////////////////////////////////////////////////// +// initialize cpp lexer +template +inline +lexer::lexer(IteratorT const &first, + IteratorT const &last, PositionT const &pos, + boost::wave::language_support language) +: filename(pos.get_file()), at_eof(false) +{ + using namespace boost::wave::cpplexer::re2clex; + + memset(&scanner, '\0', sizeof(scanner_t)); + scanner.fd = -1; + scanner.eol_offsets = aq_create(); + scanner.first = scanner.act = (uchar *)&(*first); + scanner.last = scanner.first + std::distance(first, last); + scanner.line = 1; // start with line_no 1 + scanner.error_proc = report_error; + scanner.file_name = filename.c_str(); + +// not used by the lexer + scanner.enable_ms_extensions = 0; + scanner.act_in_c99_mode = 0; + scanner.act_in_cpp0x_mode = 0; + + boost::ignore_unused_variable_warning(language); +} + +template +inline +lexer::~lexer() +{ + boost::wave::cpplexer::re2clex::aq_terminate(scanner.eol_offsets); + free(scanner.bot); +} + +/////////////////////////////////////////////////////////////////////////////// +// get the next token from the input stream +template +inline boost::wave::cpplexer::lex_token +lexer::get() +{ + using namespace boost::wave; // to import token ids to this scope + + if (at_eof) + return boost::wave::cpplexer::lex_token(); // return T_EOI + + token_id id = token_id(scan(&scanner)); + string_type value((char const *)scanner.tok, scanner.cur-scanner.tok); + + if (T_IDENTIFIER == id) { + // test identifier characters for validity (throws if invalid chars found) + boost::wave::cpplexer::impl::validate_identifier_name(value, + scanner.line, -1, filename); + } + else if (T_STRINGLIT == id || T_CHARLIT == id) { + // test literal characters for validity (throws if invalid chars found) + boost::wave::cpplexer::impl::validate_literal(value, scanner.line, -1, + filename); + } + else if (T_EOF == id) { + // T_EOF is returned as a valid token, the next call will return T_EOI, + // i.e. the actual end of input + at_eof = true; + } + return boost::wave::cpplexer::lex_token(id, value, + PositionT(filename, scanner.line, -1)); +} + +template +inline int +lexer::report_error(scanner_t *s, char *msg, ...) +{ + BOOST_ASSERT(0 != s); + BOOST_ASSERT(0 != msg); + + using namespace std; // some system have vsprintf in namespace std + + char buffer[200]; // should be large enough + va_list params; + va_start(params, msg); + vsprintf(buffer, msg, params); + va_end(params); + + BOOST_WAVE_LEXER_THROW(boost::wave::cpplexer::lexing_exception, + generic_lexing_error, buffer, s->line, -1, s->file_name); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_functor +// +/////////////////////////////////////////////////////////////////////////////// + +template < + typename IteratorT, + typename PositionT = boost::wave::util::file_position_type +> +class lex_functor +: public lex_input_interface::token_type> +{ +public: + + typedef typename lexer::token_type token_type; + + lex_functor(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language) + : lexer(first, last, pos, language) + {} + virtual ~lex_functor() {} + +// get the next token from the input stream + token_type get() { return lexer.get(); } + void set_position(PositionT const &pos) + { lexer.set_position(pos); } + +private: + lexer lexer; +}; + +} // namespace re2clex + +/////////////////////////////////////////////////////////////////////////////// +// +// The new_lexer_gen<>::new_lexer function (declared in cpp_slex_token.hpp) +// should be defined inline, if the lex_functor shouldn't be instantiated +// separately from the lex_iterator. +// +// Separate (explicit) instantiation helps to reduce compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 +#define BOOST_WAVE_RE2C_NEW_LEXER_INLINE +#else +#define BOOST_WAVE_RE2C_NEW_LEXER_INLINE inline +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// The 'new_lexer' function allows the opaque generation of a new lexer object. +// It is coupled to the iterator type to allow to decouple the lexer/iterator +// configurations at compile time. +// +// This function is declared inside the cpp_slex_token.hpp file, which is +// referenced by the source file calling the lexer and the source file, which +// instantiates the lex_functor. But is is defined here, so it will be +// instantiated only while compiling the source file, which instantiates the +// lex_functor. While the cpp_re2c_token.hpp file may be included everywhere, +// this file (cpp_re2c_lexer.hpp) should be included only once. This allows +// to decouple the lexer interface from the lexer implementation and reduces +// compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +template +BOOST_WAVE_RE2C_NEW_LEXER_INLINE +lex_input_interface > * +new_lexer_gen::new_lexer(IteratorT const &first, + IteratorT const &last, PositionT const &pos, + wave::language_support language) +{ + return new re2clex::lex_functor(first, last, pos, + language); +} + +#undef BOOST_WAVE_RE2C_NEW_LEXER_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace idllexer +} // namespace wave +} // namespace boost + +#endif // !defined(IDL_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED) diff --git a/samples/waveidl/instantiate_cpp_grammar.cpp b/samples/waveidl/instantiate_cpp_grammar.cpp new file mode 100644 index 000000000..3e338a359 --- /dev/null +++ b/samples/waveidl/instantiate_cpp_grammar.cpp @@ -0,0 +1,42 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + Explicit instantiation of the cpp_grammar template + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "idl.hpp" + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include "idllexer/idl_lex_iterator.hpp" + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the cpp_grammar_gen template with the correct +// token type. This instantiates the corresponding pt_parse function, which +// in turn instantiates the cpp_grammar object +// (see wave/grammars/cpp_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::idllexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lexer_type; +template struct boost::wave::grammars::cpp_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/samples/waveidl/instantiate_defined_grammar.cpp b/samples/waveidl/instantiate_defined_grammar.cpp new file mode 100644 index 000000000..b30170f3c --- /dev/null +++ b/samples/waveidl/instantiate_defined_grammar.cpp @@ -0,0 +1,42 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + Explicit instantiation of the defined_grammar template + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "idl.hpp" + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include "idllexer/idl_lex_iterator.hpp" + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the defined_grammar_gen template +// with the correct token type. This instantiates the corresponding parse +// function, which in turn instantiates the defined_grammar +// object (see wave/grammars/cpp_defined_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::idllexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lexer_type; +template struct boost::wave::grammars::defined_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/samples/waveidl/instantiate_predef_macros.cpp b/samples/waveidl/instantiate_predef_macros.cpp new file mode 100644 index 000000000..345a752e1 --- /dev/null +++ b/samples/waveidl/instantiate_predef_macros.cpp @@ -0,0 +1,42 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + Explicit instantiation of the predefined_macros_grammar template + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "idl.hpp" + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include "idllexer/idl_lex_iterator.hpp" + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the predefined_macros_grammar_gen template +// with the correct token type. This instantiates the corresponding pt_parse +// function, which in turn instantiates the cpp_predefined_macros_grammar +// object (see wave/grammars/cpp_predef_macros_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::idllexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lexer_type; +template struct boost::wave::grammars::predefined_macros_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/samples/waveidl/instantiate_re2c_lexer.cpp b/samples/waveidl/instantiate_re2c_lexer.cpp new file mode 100644 index 000000000..343fba41e --- /dev/null +++ b/samples/waveidl/instantiate_re2c_lexer.cpp @@ -0,0 +1,50 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + Explicit instantiation of the lex_functor generation function + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "idl.hpp" + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include +#include + +#include "idllexer/idl_lex_iterator.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include "idllexer/idl_re2c_lexer.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// +// This instantiates the correct 'new_lexer' function, which generates the +// C++ lexer used in this sample. You will have to instantiate the +// new_lexer_gen<> template with the same iterator type, as you have used for +// instantiating the boost::wave::context<> object. +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the first +// parameter supplied while instantiating the boost::wave::context<> template +// (see the file cpp.cpp). +// +/////////////////////////////////////////////////////////////////////////////// + +template struct boost::wave::idllexer::new_lexer_gen< + BOOST_WAVE_STRINGTYPE::iterator>; + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/samples/waveidl/instantiate_re2c_lexer_string.cpp b/samples/waveidl/instantiate_re2c_lexer_string.cpp new file mode 100644 index 000000000..4d70315fa --- /dev/null +++ b/samples/waveidl/instantiate_re2c_lexer_string.cpp @@ -0,0 +1,50 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Sample: IDL oriented preprocessor + Explicit instantiation of the lex_functor generation function + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "idl.hpp" + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include +#include + +#include "idllexer/idl_lex_iterator.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include "idllexer/idl_re2c_lexer.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// +// If you've used another iterator type as std::string::iterator, you have to +// instantiate the new_lexer_gen<> template for this iterator type too. +// The reason is, that the library internally uses the new_lexer_gen<> +// template with a std::string::iterator. (You just have to undefine the +// following line.) +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the first +// parameter supplied while instantiating the boost::wave::context<> template +// (see the file cpp.cpp). +// +/////////////////////////////////////////////////////////////////////////////// + +template struct boost::wave::idllexer::new_lexer_gen; + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/src/cpplexer/re2clex/aq.cpp b/src/cpplexer/re2clex/aq.cpp new file mode 100644 index 000000000..58c36bab2 --- /dev/null +++ b/src/cpplexer/re2clex/aq.cpp @@ -0,0 +1,217 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001 Daniel C. Nuffer. + Copyright (c) 2001-2005 Hartmut Kaiser. + 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) +=============================================================================*/ + +#include +#include + +#include + +#include // configuration data +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +int aq_grow(aq_queue q) +{ + std::size_t new_size = q->max_size << 1; + aq_stdelement* new_queue = (aq_stdelement*)realloc(q->queue, + new_size * sizeof(aq_stdelement)); + + BOOST_ASSERT(q); + BOOST_ASSERT(q->max_size < 100000); + BOOST_ASSERT(q->size <= q->max_size); + +#define ASSERT_SIZE BOOST_ASSERT( \ + ((q->tail + q->max_size + 1) - q->head) % q->max_size == \ + q->size % q->max_size) + + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + if (!new_queue) + { + BOOST_ASSERT(0); + return 0; + } + + q->queue = new_queue; + if (q->tail <= q->head) /* tail has wrapped around */ + { + /* move the tail from the beginning to the end */ + memcpy(q->queue + q->max_size, q->queue, + (q->tail + 1) * sizeof(aq_stdelement)); + q->tail += q->max_size; + } + q->max_size = new_size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_enqueue(aq_queue q, aq_stdelement e) +{ + BOOST_ASSERT(q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_FULL(q)) + if (!aq_grow(q)) + return 0; + + ++q->tail; + if (q->tail == q->max_size) + q->tail = 0; + + q->queue[q->tail] = e; + ++q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_enqueue_front(aq_queue q, aq_stdelement e) +{ + BOOST_ASSERT(q); + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_FULL(q)) + if (!aq_grow(q)) + return 0; + + if (q->head == 0) + q->head = q->max_size - 1; + else + --q->head; + + q->queue[q->head] = e; + ++q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_serve(aq_queue q, aq_stdelement *e) +{ + + BOOST_ASSERT(q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_EMPTY(q)) + return 0; + + *e = q->queue[q->head]; + return aq_pop(q); +} + +int aq_pop(aq_queue q) +{ + + BOOST_ASSERT(q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_EMPTY(q)) + return 0; + + ++q->head; + if (q->head == q->max_size) + q->head = 0; + --q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +aq_queue aq_create(void) +{ + aq_queue q; + + q = (aq_queue)malloc(sizeof(aq_queuetype)); + if (!q) + { + return 0; + } + + q->max_size = 8; /* initial size */ + q->queue = (aq_stdelement*)malloc( + sizeof(aq_stdelement) * q->max_size); + if (!q->queue) + { + free(q); + return 0; + } + + q->head = 0; + q->tail = q->max_size - 1; + q->size = 0; + + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return q; +} + +void aq_terminate(aq_queue q) +{ + + BOOST_ASSERT(q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + free(q->queue); + free(q); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost diff --git a/src/cpplexer/re2clex/cpp.re b/src/cpplexer/re2clex/cpp.re new file mode 100644 index 000000000..1dee45f7d --- /dev/null +++ b/src/cpplexer/re2clex/cpp.re @@ -0,0 +1,717 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Copyright (c) 2001 Daniel C. Nuffer + Copyright (c) 2001-2005 Hartmut Kaiser. + 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) + + TODO: + It also may be necessary to add $ to identifiers, for asm. + handle errors better. + have some easier way to parse strings instead of files (done) +=============================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(BOOST_HAS_UNISTD_H) +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +#if defined(BOOST_MSVC) +#pragma warning (disable: 4101) // 'foo' : unreferenced local variable +#pragma warning (disable: 4102) // 'foo' : unreferenced label +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define BSIZE 196608 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +//#define RET(i) {s->cur = cursor; return (i);} +#define RET(i) \ + { \ + s->line += count_backslash_newlines(s, cursor); \ + s->cur = cursor; \ + return (i); \ + } \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +#define RE2C_ASSERT BOOST_ASSERT + +int get_one_char(Scanner *s) +{ + if (s->fd != -1) { + uchar val; + + if (read(s->fd, &val, sizeof(val))) + return val; + } + else if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + if (s->act < s->last) + return *(s->act)++; + } + return -1; +} + +std::ptrdiff_t rewind_stream (Scanner *s, int cnt) +{ + if (s->fd != -1) { + return lseek(s->fd, cnt, SEEK_CUR); + } + else if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + s->act += cnt; + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + return s->act - s->first; + } + return 0; +} + +std::size_t get_first_eol_offset(Scanner* s) +{ + if (!AQ_EMPTY(s->eol_offsets)) + { + return s->eol_offsets->queue[s->eol_offsets->head]; + } + else + { + return (unsigned int)-1; + } +} + +void adjust_eol_offsets(Scanner* s, std::size_t adjustment) +{ + aq_queue q; + std::size_t i; + + if (!s->eol_offsets) + s->eol_offsets = aq_create(); + + q = s->eol_offsets; + + if (AQ_EMPTY(q)) + return; + + i = q->head; + while (i != q->tail) + { + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; + ++i; + if (i == q->max_size) + i = 0; + } + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; +} + +int count_backslash_newlines(Scanner *s, uchar *cursor) +{ + std::size_t diff, offset; + int skipped = 0; + + /* figure out how many backslash-newlines skipped over unknowingly. */ + diff = cursor - s->bot; + offset = get_first_eol_offset(s); + while (offset <= diff && offset != (unsigned int)-1) + { + skipped++; + aq_pop(s->eol_offsets); + offset = get_first_eol_offset(s); + } + return skipped; +} + +bool is_backslash(uchar *p, uchar *end, int &len) +{ + if (*p == '\\') { + len = 1; + return true; + } + else if (*p == '?' && *(p+1) == '?' && (p+2 < end && *(p+2) == '/')) { + len = 3; + return true; + } + return false; +} + +uchar *fill(Scanner *s, uchar *cursor) +{ + if(!s->eof) + { + uchar* p; + std::ptrdiff_t cnt = s->tok - s->bot; + if(cnt) + { + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->lim -= cnt; + adjust_eol_offsets(s, cnt); + } + + if((s->top - s->lim) < BSIZE) + { + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + if (buf == 0) + { + if (0 != s->error_proc) + (*s->error_proc)(s, "Out of memory!"); + else + printf("Out of memory!\n"); + + /* get the scanner to stop */ + *cursor = 0; + return cursor; + } + + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + + if (s->fd != -1) { + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + else if (s->act != 0) { + cnt = s->last - s->act; + if (cnt > BSIZE) + cnt = BSIZE; + memcpy(s->lim, s->act, cnt); + s->act += cnt; + if (cnt != BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + + /* backslash-newline erasing time */ + + /* first scan for backslash-newline and erase them */ + for (p = s->lim; p < s->lim + cnt - 2; ++p) + { + int len = 0; + if (is_backslash(p, s->lim + cnt, len)) + { + if (*(p+len) == '\n') + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + else if (*(p+len) == '\r') + { + if (*(p+len+1) == '\n') + { + int offset = len + 2; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + else + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + } + } + + /* FIXME: the following code should be fixed to recognize correctly the + trigraph backslash token */ + + /* check to see if what we just read ends in a backslash */ + if (cnt >= 2) + { + uchar last = s->lim[cnt-1]; + uchar last2 = s->lim[cnt-2]; + /* check \ EOB */ + if (last == '\\') + { + int next = get_one_char(s); + /* check for \ \n or \ \r or \ \r \n straddling the border */ + if (next == '\n') + { + --cnt; /* chop the final \, we've already read the \n. */ + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + else if (next == '\r') + { + int next2 = get_one_char(s); + if (next2 == '\n') + { + --cnt; /* skip the backslash */ + } + else + { + /* rewind one, and skip one char */ + rewind_stream(s, -1); + --cnt; + } + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + else if (next != -1) /* -1 means end of file */ + { + /* next was something else, so rewind the stream */ + rewind_stream(s, -1); + } + } + /* check \ \r EOB */ + else if (last == '\r' && last2 == '\\') + { + int next = get_one_char(s); + if (next == '\n') + { + cnt -= 2; /* skip the \ \r */ + } + else + { + /* rewind one, and skip two chars */ + rewind_stream(s, -1); + cnt -= 2; + } + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + /* check \ \n EOB */ + else if (last == '\n' && last2 == '\\') + { + cnt -= 2; + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + } + + s->lim += cnt; + if (s->eof) /* eof needs adjusting if we erased backslash-newlines */ + { + s->eof = s->lim; + *(s->eof)++ = '\0'; + } + } + return cursor; +} + +boost::wave::token_id scan(Scanner *s) +{ + uchar *cursor = s->tok = s->cur; + +/*!re2c +any = [\t\v\f\r\n\040-\377]; +OctalDigit = [0-7]; +Digit = [0-9]; +HexDigit = [a-fA-F0-9]; +ExponentPart = [Ee] [+-]? Digit+; +FractionalConstant = (Digit* "." Digit+) | (Digit+ "."); +FloatingSuffix = [fF][lL]?|[lL][fF]?; +IntegerSuffix = [uU][lL]?|[lL][uU]?; +Backslash = [\\]|"??/"; +EscapeSequence = Backslash ([abfnrtv?'"] | Backslash | "x" HexDigit+ | OctalDigit OctalDigit? OctalDigit?); +HexQuad = HexDigit HexDigit HexDigit HexDigit; +UniversalChar = Backslash ("u" HexQuad | "U" HexQuad HexQuad); +Newline = "\r\n" | "\n" | "\r"; +PPSpace = ([ \t]|("/*"(any\[*]|Newline|("*"+(any\[*/]|Newline)))*"*"+"/"))*; +Pound = "#" | "??=" | "%:"; +*/ + +/*!re2c + "/*" { goto ccomment; } + "//" { goto cppcomment; } + + "asm" { RET(T_ASM); } + "auto" { RET(T_AUTO); } + "bool" { RET(T_BOOL); } + "break" { RET(T_BREAK); } + "case" { RET(T_CASE); } + "catch" { RET(T_CATCH); } + "char" { RET(T_CHAR); } + "class" { RET(T_CLASS); } + "const" { RET(T_CONST); } + "const_cast" { RET(T_CONSTCAST); } + "continue" { RET(T_CONTINUE); } + "default" { RET(T_DEFAULT); } + "delete" { RET(T_DELETE); } + "do" { RET(T_DO); } + "double" { RET(T_DOUBLE); } + "dynamic_cast" { RET(T_DYNAMICCAST); } + "else" { RET(T_ELSE); } + "enum" { RET(T_ENUM); } + "explicit" { RET(T_EXPLICIT); } + "export" { RET(T_EXPORT); } + "extern" { RET(T_EXTERN); } + "false" { RET(T_FALSE); } + "float" { RET(T_FLOAT); } + "for" { RET(T_FOR); } + "friend" { RET(T_FRIEND); } + "goto" { RET(T_GOTO); } + "if" { RET(T_IF); } + "inline" { RET(T_INLINE); } + "int" { RET(T_INT); } + "long" { RET(T_LONG); } + "mutable" { RET(T_MUTABLE); } + "namespace" { RET(T_NAMESPACE); } + "new" { RET(T_NEW); } + "operator" { RET(T_OPERATOR); } + "private" { RET(T_PRIVATE); } + "protected" { RET(T_PROTECTED); } + "public" { RET(T_PUBLIC); } + "register" { RET(T_REGISTER); } + "reinterpret_cast" { RET(T_REINTERPRETCAST); } + "return" { RET(T_RETURN); } + "short" { RET(T_SHORT); } + "signed" { RET(T_SIGNED); } + "sizeof" { RET(T_SIZEOF); } + "static" { RET(T_STATIC); } + "static_cast" { RET(T_STATICCAST); } + "struct" { RET(T_STRUCT); } + "switch" { RET(T_SWITCH); } + "template" { RET(T_TEMPLATE); } + "this" { RET(T_THIS); } + "throw" { RET(T_THROW); } + "true" { RET(T_TRUE); } + "try" { RET(T_TRY); } + "typedef" { RET(T_TYPEDEF); } + "typeid" { RET(T_TYPEID); } + "typename" { RET(T_TYPENAME); } + "union" { RET(T_UNION); } + "unsigned" { RET(T_UNSIGNED); } + "using" { RET(T_USING); } + "virtual" { RET(T_VIRTUAL); } + "void" { RET(T_VOID); } + "volatile" { RET(T_VOLATILE); } + "wchar_t" { RET(T_WCHART); } + "while" { RET(T_WHILE); } + + "__int8" { RET(s->enable_ms_extensions ? T_MSEXT_INT8 : T_IDENTIFIER); } + "__int16" { RET(s->enable_ms_extensions ? T_MSEXT_INT16 : T_IDENTIFIER); } + "__int32" { RET(s->enable_ms_extensions ? T_MSEXT_INT32 : T_IDENTIFIER); } + "__int64" { RET(s->enable_ms_extensions ? T_MSEXT_INT64 : T_IDENTIFIER); } + "_"? "_based" { RET(s->enable_ms_extensions ? T_MSEXT_BASED : T_IDENTIFIER); } + "_"? "_declspec" { RET(s->enable_ms_extensions ? T_MSEXT_DECLSPEC : T_IDENTIFIER); } + "_"? "_cdecl" { RET(s->enable_ms_extensions ? T_MSEXT_CDECL : T_IDENTIFIER); } + "_"? "_fastcall" { RET(s->enable_ms_extensions ? T_MSEXT_FASTCALL : T_IDENTIFIER); } + "_"? "_stdcall" { RET(s->enable_ms_extensions ? T_MSEXT_STDCALL : T_IDENTIFIER); } + "__try" { RET(s->enable_ms_extensions ? T_MSEXT_TRY : T_IDENTIFIER); } + "__except" { RET(s->enable_ms_extensions ? T_MSEXT_EXCEPT : T_IDENTIFIER); } + "__finally" { RET(s->enable_ms_extensions ? T_MSEXT_FINALLY : T_IDENTIFIER); } + "__leave" { RET(s->enable_ms_extensions ? T_MSEXT_LEAVE : T_IDENTIFIER); } + "_"? "_inline" { RET(s->enable_ms_extensions ? T_MSEXT_INLINE : T_IDENTIFIER); } + "_"? "_asm" { RET(s->enable_ms_extensions ? T_MSEXT_ASM : T_IDENTIFIER); } + + "{" { RET(T_LEFTBRACE); } + "??<" { RET(T_LEFTBRACE_TRIGRAPH); } + "<%" { RET(T_LEFTBRACE_ALT); } + "}" { RET(T_RIGHTBRACE); } + "??>" { RET(T_RIGHTBRACE_TRIGRAPH); } + "%>" { RET(T_RIGHTBRACE_ALT); } + "[" { RET(T_LEFTBRACKET); } + "??(" { RET(T_LEFTBRACKET_TRIGRAPH); } + "<:" { RET(T_LEFTBRACKET_ALT); } + "]" { RET(T_RIGHTBRACKET); } + "??)" { RET(T_RIGHTBRACKET_TRIGRAPH); } + ":>" { RET(T_RIGHTBRACKET_ALT); } + "#" { RET(T_POUND); } + "%:" { RET(T_POUND_ALT); } + "??=" { RET(T_POUND_TRIGRAPH); } + "##" { RET(T_POUND_POUND); } + "#??=" { RET(T_POUND_POUND_TRIGRAPH); } + "??=#" { RET(T_POUND_POUND_TRIGRAPH); } + "??=??=" { RET(T_POUND_POUND_TRIGRAPH); } + "%:%:" { RET(T_POUND_POUND_ALT); } + "(" { RET(T_LEFTPAREN); } + ")" { RET(T_RIGHTPAREN); } + ";" { RET(T_SEMICOLON); } + ":" { RET(T_COLON); } + "..." { RET(T_ELLIPSIS); } + "?" { RET(T_QUESTION_MARK); } + "::" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + RET(T_COLON); + } + else { + RET(T_COLON_COLON); + } + } + "." { RET(T_DOT); } + ".*" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + RET(T_DOT); + } + else { + RET(T_DOTSTAR); + } + } + "+" { RET(T_PLUS); } + "-" { RET(T_MINUS); } + "*" { RET(T_STAR); } + "/" { RET(T_DIVIDE); } + "%" { RET(T_PERCENT); } + "^" { RET(T_XOR); } + "??'" { RET(T_XOR_TRIGRAPH); } + "xor" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_XOR_ALT); } + "&" { RET(T_AND); } + "bitand" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_AND_ALT); } + "|" { RET(T_OR); } + "bitor" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_OR_ALT); } + "??!" { RET(T_OR_TRIGRAPH); } + "~" { RET(T_COMPL); } + "??-" { RET(T_COMPL_TRIGRAPH); } + "compl" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_COMPL_ALT); } + "!" { RET(T_NOT); } + "not" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_NOT_ALT); } + "=" { RET(T_ASSIGN); } + "<" { RET(T_LESS); } + ">" { RET(T_GREATER); } + "+=" { RET(T_PLUSASSIGN); } + "-=" { RET(T_MINUSASSIGN); } + "*=" { RET(T_STARASSIGN); } + "/=" { RET(T_DIVIDEASSIGN); } + "%=" { RET(T_PERCENTASSIGN); } + "^=" { RET(T_XORASSIGN); } + "xor_eq" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_XORASSIGN_ALT); } + "??'=" { RET(T_XORASSIGN); } + "&=" { RET(T_ANDASSIGN); } + "and_eq" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ANDASSIGN_ALT); } + "|=" { RET(T_ORASSIGN); } + "or_eq" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ORASSIGN_ALT); } + "??!=" { RET(T_ORASSIGN); } + "<<" { RET(T_SHIFTLEFT); } + ">>" { RET(T_SHIFTRIGHT); } + ">>=" { RET(T_SHIFTRIGHTASSIGN); } + "<<=" { RET(T_SHIFTLEFTASSIGN); } + "==" { RET(T_EQUAL); } + "!=" { RET(T_NOTEQUAL); } + "not_eq" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_NOTEQUAL_ALT); } + "<=" { RET(T_LESSEQUAL); } + ">=" { RET(T_GREATEREQUAL); } + "&&" { RET(T_ANDAND); } + "and" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ANDAND_ALT); } + "||" { RET(T_OROR); } + "??!|" { RET(T_OROR); } + "|??!" { RET(T_OROR); } + "or" { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_OROR_ALT); } + "??!??!" { RET(T_OROR); } + "++" { RET(T_PLUSPLUS); } + "--" { RET(T_MINUSMINUS); } + "," { RET(T_COMMA); } + "->*" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + RET(T_ARROW); + } + else { + RET(T_ARROWSTAR); + } + } + "->" { RET(T_ARROW); } + + ([a-zA-Z_] | UniversalChar) ([a-zA-Z_0-9] | UniversalChar)* + { RET(T_IDENTIFIER); } + + (("0" [xX] HexDigit+) | ("0" OctalDigit*) | ([1-9] Digit*)) IntegerSuffix? + { RET(T_INTLIT); } + + ((FractionalConstant ExponentPart?) | (Digit+ ExponentPart)) FloatingSuffix? + { RET(T_FLOATLIT); } + + "L"? (['] (EscapeSequence|any\[\n\r\\']|UniversalChar)+ [']) + { RET(T_CHARLIT); } + + "L"? (["] (EscapeSequence|any\[\n\r\\"]|UniversalChar)* ["]) + { RET(T_STRINGLIT); } + + + Pound PPSpace ( "include" | "include_next") PPSpace "<" (any\[\n\r>])+ ">" + { RET(T_PP_HHEADER); } + + Pound PPSpace ( "include" | "include_next") PPSpace "\"" (any\[\n\r"])+ "\"" + { RET(T_PP_QHEADER); } + + Pound PPSpace ( "include" | "include_next") PPSpace + { RET(T_PP_INCLUDE); } + + Pound PPSpace "if" { RET(T_PP_IF); } + Pound PPSpace "ifdef" { RET(T_PP_IFDEF); } + Pound PPSpace "ifndef" { RET(T_PP_IFNDEF); } + Pound PPSpace "else" { RET(T_PP_ELSE); } + Pound PPSpace "elif" { RET(T_PP_ELIF); } + Pound PPSpace "endif" { RET(T_PP_ENDIF); } + Pound PPSpace "define" { RET(T_PP_DEFINE); } + Pound PPSpace "undef" { RET(T_PP_UNDEF); } + Pound PPSpace "line" { RET(T_PP_LINE); } + Pound PPSpace "error" { RET(T_PP_ERROR); } + Pound PPSpace "pragma" { RET(T_PP_PRAGMA); } + + Pound PPSpace "warning" { RET(T_PP_WARNING); } + + Pound PPSpace "region" { RET(T_MSEXT_PP_REGION); } + Pound PPSpace "endregion" { RET(T_MSEXT_PP_ENDREGION); } + + [ \t\v\f]+ + { RET(T_SPACE); } + + Newline + { + s->line++; + RET(T_NEWLINE); + } + + "\000" + { + if(cursor != s->eof) + { + if (0 != s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file\n"); + } + RET(T_EOF); + } + + any + { + /* if (0 != s->error_proc) + (*s->error_proc)(s, "Unexpected character: '%c'", *s->tok); + else + printf("unexpected character: '%c'\n", *s->tok); + */ + RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); + } +*/ + +ccomment: +/*!re2c + "*/" { RET(T_CCOMMENT); } + + Newline + { + /*if(cursor == s->eof) RET(T_EOF);*/ + /*s->tok = cursor; */ + s->line += count_backslash_newlines(s, cursor) +1; + goto ccomment; + } + + any { goto ccomment; } + + "\000" + { + yyaccept = 0; /* avoid warning about unreferenced variable */ + if(cursor == s->eof) + { + if (s->error_proc) + (*s->error_proc)(s, "Unterminated comment"); + else + printf("Error: Unterminated comment\n"); + } + else + { + if (s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file"); + } + /* adjust cursor such next call returns T_EOF */ + --YYCURSOR; + /* the comment is unterminated, but nevertheless its a comment */ + RET(T_CCOMMENT); + } + +*/ + +cppcomment: +/*!re2c + Newline + { + /*if(cursor == s->eof) RET(T_EOF); */ + /*s->tok = cursor; */ + s->line++; + RET(T_CPPCOMMENT); + } + + any { goto cppcomment; } + + "\000" + { + yyaccept = 0; /* avoid warning about unreferenced variable */ + if(cursor != s->eof) + { + if (s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file"); + } + /* adjust cursor such next call returns T_EOF */ + --YYCURSOR; + /* the comment is unterminated, but nevertheless its a comment */ + RET(T_CPPCOMMENT); + } +*/ + +} /* end of scan */ + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#undef RET +#undef BSIZE +#undef YYCTYPE +#undef YYCURSOR +#undef YYLIMIT +#undef YYMARKER +#undef YYFILL + diff --git a/src/cpplexer/re2clex/cpp.re.cpp b/src/cpplexer/re2clex/cpp.re.cpp new file mode 100644 index 000000000..cfb6b0672 --- /dev/null +++ b/src/cpplexer/re2clex/cpp.re.cpp @@ -0,0 +1,8079 @@ +/* Generated by re2c 0.5 on Fri Feb 11 10:08:35 2005 */ +#line 1 "c:\\Cvs\\wave\\libs\\wave\\src\\cpplexer\\re2clex\\cpp.re" +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + Copyright (c) 2001 Daniel C. Nuffer + Copyright (c) 2001-2005 Hartmut Kaiser. + 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) + + TODO: + It also may be necessary to add $ to identifiers, for asm. + handle errors better. + have some easier way to parse strings instead of files (done) +=============================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(BOOST_HAS_UNISTD_H) +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +#if defined(BOOST_MSVC) +#pragma warning (disable: 4101) // 'foo' : unreferenced local variable +#pragma warning (disable: 4102) // 'foo' : unreferenced label +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define BSIZE 196608 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +//#define RET(i) {s->cur = cursor; return (i);} +#define RET(i) \ + { \ + s->line += count_backslash_newlines(s, cursor); \ + s->cur = cursor; \ + return (i); \ + } \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +#define RE2C_ASSERT BOOST_ASSERT + +int get_one_char(Scanner *s) +{ + if (s->fd != -1) { + uchar val; + + if (read(s->fd, &val, sizeof(val))) + return val; + } + else if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + if (s->act < s->last) + return *(s->act)++; + } + return -1; +} + +std::ptrdiff_t rewind_stream (Scanner *s, int cnt) +{ + if (s->fd != -1) { + return lseek(s->fd, cnt, SEEK_CUR); + } + else if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + s->act += cnt; + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + return s->act - s->first; + } + return 0; +} + +std::size_t get_first_eol_offset(Scanner* s) +{ + if (!AQ_EMPTY(s->eol_offsets)) + { + return s->eol_offsets->queue[s->eol_offsets->head]; + } + else + { + return (unsigned int)-1; + } +} + +void adjust_eol_offsets(Scanner* s, std::size_t adjustment) +{ + aq_queue q; + std::size_t i; + + if (!s->eol_offsets) + s->eol_offsets = aq_create(); + + q = s->eol_offsets; + + if (AQ_EMPTY(q)) + return; + + i = q->head; + while (i != q->tail) + { + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; + ++i; + if (i == q->max_size) + i = 0; + } + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; +} + +int count_backslash_newlines(Scanner *s, uchar *cursor) +{ + std::size_t diff, offset; + int skipped = 0; + + /* figure out how many backslash-newlines skipped over unknowingly. */ + diff = cursor - s->bot; + offset = get_first_eol_offset(s); + while (offset <= diff && offset != (unsigned int)-1) + { + skipped++; + aq_pop(s->eol_offsets); + offset = get_first_eol_offset(s); + } + return skipped; +} + +bool is_backslash(uchar *p, uchar *end, int &len) +{ + if (*p == '\\') { + len = 1; + return true; + } + else if (*p == '?' && *(p+1) == '?' && (p+2 < end && *(p+2) == '/')) { + len = 3; + return true; + } + return false; +} + +uchar *fill(Scanner *s, uchar *cursor) +{ + if(!s->eof) + { + uchar* p; + std::ptrdiff_t cnt = s->tok - s->bot; + if(cnt) + { + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->lim -= cnt; + adjust_eol_offsets(s, cnt); + } + + if((s->top - s->lim) < BSIZE) + { + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + if (buf == 0) + { + if (0 != s->error_proc) + (*s->error_proc)(s, "Out of memory!"); + else + printf("Out of memory!\n"); + + /* get the scanner to stop */ + *cursor = 0; + return cursor; + } + + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + + if (s->fd != -1) { + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + else if (s->act != 0) { + cnt = s->last - s->act; + if (cnt > BSIZE) + cnt = BSIZE; + memcpy(s->lim, s->act, cnt); + s->act += cnt; + if (cnt != BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + + /* backslash-newline erasing time */ + + /* first scan for backslash-newline and erase them */ + for (p = s->lim; p < s->lim + cnt - 2; ++p) + { + int len = 0; + if (is_backslash(p, s->lim + cnt, len)) + { + if (*(p+len) == '\n') + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + else if (*(p+len) == '\r') + { + if (*(p+len+1) == '\n') + { + int offset = len + 2; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + else + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + } + } + + /* FIXME: the following code should be fixed to recognize correctly the + trigraph backslash token */ + + /* check to see if what we just read ends in a backslash */ + if (cnt >= 2) + { + uchar last = s->lim[cnt-1]; + uchar last2 = s->lim[cnt-2]; + /* check \ EOB */ + if (last == '\\') + { + int next = get_one_char(s); + /* check for \ \n or \ \r or \ \r \n straddling the border */ + if (next == '\n') + { + --cnt; /* chop the final \, we've already read the \n. */ + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + else if (next == '\r') + { + int next2 = get_one_char(s); + if (next2 == '\n') + { + --cnt; /* skip the backslash */ + } + else + { + /* rewind one, and skip one char */ + rewind_stream(s, -1); + --cnt; + } + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + else if (next != -1) /* -1 means end of file */ + { + /* next was something else, so rewind the stream */ + rewind_stream(s, -1); + } + } + /* check \ \r EOB */ + else if (last == '\r' && last2 == '\\') + { + int next = get_one_char(s); + if (next == '\n') + { + cnt -= 2; /* skip the \ \r */ + } + else + { + /* rewind one, and skip two chars */ + rewind_stream(s, -1); + cnt -= 2; + } + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + /* check \ \n EOB */ + else if (last == '\n' && last2 == '\\') + { + cnt -= 2; + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + } + + s->lim += cnt; + if (s->eof) /* eof needs adjusting if we erased backslash-newlines */ + { + s->eof = s->lim; + *(s->eof)++ = '\0'; + } + } + return cursor; +} + +boost::wave::token_id scan(Scanner *s) +{ + uchar *cursor = s->tok = s->cur; + +#line 362 + + +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; +yy1: ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 17) YYFILL(17); + yych = *YYCURSOR; + switch(yych){ + case '\000': goto yy89; + case '\001': + case '\002': + case '\003': + case '\004': + case '\005': + case '\006': + case '\a': + case '\b': case '\016': + case '\017': + case '\020': + case '\021': + case '\022': + case '\023': + case '\024': + case '\025': + case '\026': + case '\027': + case '\030': + case '\031': + case '\032': + case '\033': + case '\034': + case '\035': + case '\036': + case '\037': goto yy2; + case '\t': case '\v': + case '\f': case ' ': goto yy84; + case '\n': goto yy86; + case '\r': goto yy88; + case '!': goto yy67; + case '"': goto yy83; + case '#': goto yy42; + case '%': goto yy34; + case '&': goto yy61; + case '\'': goto yy82; + case '(': goto yy44; + case ')': goto yy46; + case '*': goto yy56; + case '+': goto yy52; + case ',': goto yy73; + case '-': goto yy54; + case '.': goto yy50; + case '/': goto yy3; + case '0': goto yy79; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy81; + case ':': goto yy40; + case ';': goto yy48; + case '<': goto yy30; + case '=': goto yy69; + case '>': goto yy71; + case '?': goto yy28; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': case 'h': case 'j': + case 'k': case 'q': case 'y': + case 'z': goto yy75; + case 'L': goto yy76; + case '[': goto yy36; + case '\\': goto yy77; + case ']': goto yy38; + case '^': goto yy58; + case '_': goto yy25; + case 'a': goto yy5; + case 'b': goto yy7; + case 'c': goto yy8; + case 'd': goto yy9; + case 'e': goto yy10; + case 'f': goto yy11; + case 'g': goto yy12; + case 'i': goto yy13; + case 'l': goto yy14; + case 'm': goto yy15; + case 'n': goto yy16; + case 'o': goto yy17; + case 'p': goto yy18; + case 'r': goto yy19; + case 's': goto yy20; + case 't': goto yy21; + case 'u': goto yy22; + case 'v': goto yy23; + case 'w': goto yy24; + case 'x': goto yy60; + case '{': goto yy26; + case '|': goto yy63; + case '}': goto yy32; + case '~': goto yy65; + default: goto yy91; + } +yy2: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 101: goto yy927; + case 100: goto yy925; + case 97: goto yy911; + case 96: goto yy908; + case 95: goto yy901; + case 94: goto yy899; + case 93: goto yy894; + case 92: goto yy891; + case 90: goto yy881; + case 91: goto yy887; + case 89: goto yy879; + case 87: goto yy863; + case 86: goto yy858; + case 83: goto yy835; + case 85: goto yy852; + case 84: goto yy847; + case 82: goto yy832; + case 81: goto yy829; + case 80: goto yy826; + case 79: goto yy821; + case 78: goto yy816; + case 77: goto yy807; + case 76: goto yy803; + case 75: goto yy799; + case 74: goto yy797; + case 73: goto yy788; + case 70: goto yy776; + case 72: goto yy784; + case 71: goto yy780; + case 69: goto yy774; + case 68: goto yy770; + case 67: goto yy763; + case 66: goto yy755; + case 63: goto yy744; + case 60: goto yy730; + case 59: goto yy725; + case 58: goto yy716; + case 57: goto yy709; + case 56: goto yy703; + case 55: goto yy689; + case 54: goto yy681; + case 53: goto yy677; + case 52: goto yy673; + case 50: goto yy661; + case 51: goto yy667; + case 49: goto yy657; + case 48: goto yy651; + case 47: goto yy642; + case 46: goto yy635; + case 45: goto yy633; + case 44: goto yy628; + case 43: goto yy626; + case 42: goto yy623; + case 41: goto yy620; + case 40: goto yy618; + case 39: goto yy605; + case 38: goto yy602; + case 37: goto yy594; + case 36: goto yy588; + case 35: goto yy582; + case 34: goto yy580; + case 33: goto yy570; + case 32: goto yy564; + case 28: goto yy552; + case 31: goto yy558; + case 30: goto yy556; + case 29: goto yy554; + case 22: goto yy516; + case 20: goto yy506; + case 21: goto yy511; + case 19: goto yy498; + case 17: goto yy484; + case 26: goto yy538; + case 25: goto yy535; + case 27: goto yy545; + case 24: goto yy529; + case 18: goto yy490; + case 23: goto yy519; + case 2: goto yy43; + case 14: goto yy418; + case 15: goto yy446; + case 1: goto yy29; + case 3: goto yy51; + case 10: goto yy263; + case 99: goto yy919; + case 4: goto yy64; + case 98: goto yy916; + case 16: goto yy450; + case 88: goto yy872; + case 64: goto yy749; + case 11: goto yy267; + case 103: goto yy933; + case 62: goto yy737; + case 65: goto yy753; + case 102: goto yy929; + case 61: goto yy733; + case 0: goto yy6; + case 6: goto yy80; + case 9: goto yy188; + case 8: goto yy150; + case 7: goto yy100; + case 13: goto yy323; + case 12: goto yy308; + case 5: goto yy78; + } +yy3: yych = *++YYCURSOR; + if(yych <= '.'){ + if(yych == '*') goto yy938; + goto yy4; + } else { + if(yych <= '/') goto yy936; + if(yych == '=') goto yy934; + goto yy4; + } +yy4: +#line 498 + { RET(T_DIVIDE); } +yy5: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'r'){ + if(yych == 'n') goto yy920; + goto yy219; + } else { + if(yych <= 's') goto yy921; + if(yych == 'u') goto yy922; + goto yy219; + } +yy6: +#line 561 + { RET(T_IDENTIFIER); } +yy7: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'n'){ + if(yych == 'i') goto yy902; + goto yy219; + } else { + if(yych <= 'o') goto yy903; + if(yych == 'r') goto yy904; + goto yy219; + } +yy8: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + switch(yych){ + case 'a': goto yy864; + case 'h': goto yy865; + case 'l': goto yy866; + case 'o': goto yy867; + default: goto yy219; + } +yy9: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'n'){ + if(yych == 'e') goto yy833; + goto yy219; + } else { + if(yych <= 'o') goto yy834; + if(yych == 'y') goto yy836; + goto yy219; + } +yy10: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'm'){ + if(yych == 'l') goto yy808; + goto yy219; + } else { + if(yych <= 'n') goto yy809; + if(yych == 'x') goto yy810; + goto yy219; + } +yy11: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + switch(yych){ + case 'a': goto yy789; + case 'l': goto yy790; + case 'o': goto yy791; + case 'r': goto yy792; + default: goto yy219; + } +yy12: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'o') goto yy785; + goto yy219; +yy13: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'f') goto yy775; + if(yych == 'n') goto yy777; + goto yy219; +yy14: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'o') goto yy771; + goto yy219; +yy15: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'u') goto yy764; + goto yy219; +yy16: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'd'){ + if(yych == 'a') goto yy745; + goto yy219; + } else { + if(yych <= 'e') goto yy746; + if(yych == 'o') goto yy747; + goto yy219; + } +yy17: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'p') goto yy731; + if(yych == 'r') goto yy732; + goto yy219; +yy18: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'r') goto yy710; + if(yych == 'u') goto yy711; + goto yy219; +yy19: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'e') goto yy682; + goto yy219; +yy20: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 's'){ + if(yych <= 'g') goto yy219; + if(yych <= 'h') goto yy643; + if(yych <= 'i') goto yy644; + goto yy219; + } else { + if(yych <= 't') goto yy645; + if(yych == 'w') goto yy646; + goto yy219; + } +yy21: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'h'){ + if(yych == 'e') goto yy606; + if(yych <= 'g') goto yy219; + goto yy607; + } else { + if(yych <= 'r'){ + if(yych <= 'q') goto yy219; + goto yy608; + } else { + if(yych == 'y') goto yy609; + goto yy219; + } + } +yy22: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'n') goto yy589; + if(yych == 's') goto yy590; + goto yy219; +yy23: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'i') goto yy571; + if(yych == 'o') goto yy572; + goto yy219; +yy24: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'c') goto yy559; + if(yych == 'h') goto yy560; + goto yy219; +yy25: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + switch(yych){ + case '_': goto yy470; + case 'a': goto yy471; + case 'b': goto yy472; + case 'c': goto yy473; + case 'd': goto yy474; + case 'f': goto yy475; + case 'i': goto yy476; + case 's': goto yy477; + default: goto yy219; + } +yy26: yych = *++YYCURSOR; + goto yy27; +yy27: +#line 448 + { RET(T_LEFTBRACE); } +yy28: yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '?') goto yy436; + goto yy29; +yy29: +#line 473 + { RET(T_QUESTION_MARK); } +yy30: yych = *++YYCURSOR; + if(yych <= ':'){ + if(yych == '%') goto yy432; + if(yych >= ':') goto yy430; + goto yy31; + } else { + if(yych <= ';') goto yy31; + if(yych <= '<') goto yy428; + if(yych <= '=') goto yy426; + goto yy31; + } +yy31: +#line 514 + { RET(T_LESS); } +yy32: yych = *++YYCURSOR; + goto yy33; +yy33: +#line 451 + { RET(T_RIGHTBRACE); } +yy34: yych = *++YYCURSOR; + if(yych <= '<'){ + if(yych == ':') goto yy417; + goto yy35; + } else { + if(yych <= '=') goto yy419; + if(yych <= '>') goto yy421; + goto yy35; + } +yy35: +#line 499 + { RET(T_PERCENT); } +yy36: yych = *++YYCURSOR; + goto yy37; +yy37: +#line 454 + { RET(T_LEFTBRACKET); } +yy38: yych = *++YYCURSOR; + goto yy39; +yy39: +#line 457 + { RET(T_RIGHTBRACKET); } +yy40: yych = *++YYCURSOR; + if(yych == ':') goto yy413; + if(yych == '>') goto yy415; + goto yy41; +yy41: +#line 471 + { RET(T_COLON); } +yy42: yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'e'){ + if(yych <= '#'){ + if(yych <= '\037'){ + if(yych == '\t') goto yy290; + goto yy43; + } else { + if(yych <= ' ') goto yy290; + if(yych >= '#') goto yy301; + goto yy43; + } + } else { + if(yych <= '>'){ + if(yych == '/') goto yy290; + goto yy43; + } else { + if(yych <= '?') goto yy300; + if(yych >= 'd') goto yy290; + goto yy43; + } + } + } else { + if(yych <= 'p'){ + if(yych <= 'k'){ + if(yych == 'i') goto yy290; + goto yy43; + } else { + if(yych <= 'l') goto yy290; + if(yych >= 'p') goto yy290; + goto yy43; + } + } else { + if(yych <= 't'){ + if(yych == 'r') goto yy290; + goto yy43; + } else { + if(yych == 'v') goto yy43; + if(yych <= 'w') goto yy290; + goto yy43; + } + } + } +yy43: +#line 460 + { RET(T_POUND); } +yy44: yych = *++YYCURSOR; + goto yy45; +yy45: +#line 468 + { RET(T_LEFTPAREN); } +yy46: yych = *++YYCURSOR; + goto yy47; +yy47: +#line 469 + { RET(T_RIGHTPAREN); } +yy48: yych = *++YYCURSOR; + goto yy49; +yy49: +#line 470 + { RET(T_SEMICOLON); } +yy50: yyaccept = 3; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '-'){ + if(yych == '*') goto yy284; + goto yy51; + } else { + if(yych <= '.') goto yy286; + if(yych <= '/') goto yy51; + if(yych <= '9') goto yy186; + goto yy51; + } +yy51: +#line 484 + { RET(T_DOT); } +yy52: yych = *++YYCURSOR; + if(yych == '+') goto yy280; + if(yych == '=') goto yy282; + goto yy53; +yy53: +#line 495 + { RET(T_PLUS); } +yy54: yych = *++YYCURSOR; + if(yych <= '<'){ + if(yych == '-') goto yy274; + goto yy55; + } else { + if(yych <= '=') goto yy276; + if(yych <= '>') goto yy272; + goto yy55; + } +yy55: +#line 496 + { RET(T_MINUS); } +yy56: yych = *++YYCURSOR; + if(yych == '=') goto yy270; + goto yy57; +yy57: +#line 497 + { RET(T_STAR); } +yy58: yych = *++YYCURSOR; + if(yych == '=') goto yy268; + goto yy59; +yy59: +#line 500 + { RET(T_XOR); } +yy60: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'o') goto yy261; + goto yy219; +yy61: yych = *++YYCURSOR; + if(yych == '&') goto yy257; + if(yych == '=') goto yy259; + goto yy62; +yy62: +#line 503 + { RET(T_AND); } +yy63: yyaccept = 4; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '>'){ + if(yych == '=') goto yy252; + goto yy64; + } else { + if(yych <= '?') goto yy249; + if(yych == '|') goto yy250; + goto yy64; + } +yy64: +#line 505 + { RET(T_OR); } +yy65: yych = *++YYCURSOR; + goto yy66; +yy66: +#line 508 + { RET(T_COMPL); } +yy67: yych = *++YYCURSOR; + if(yych == '=') goto yy247; + goto yy68; +yy68: +#line 511 + { RET(T_NOT); } +yy69: yych = *++YYCURSOR; + if(yych == '=') goto yy245; + goto yy70; +yy70: +#line 513 + { RET(T_ASSIGN); } +yy71: yych = *++YYCURSOR; + if(yych <= '<') goto yy72; + if(yych <= '=') goto yy239; + if(yych <= '>') goto yy241; + goto yy72; +yy72: +#line 515 + { RET(T_GREATER); } +yy73: yych = *++YYCURSOR; + goto yy74; +yy74: +#line 547 + { RET(T_COMMA); } +yy75: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + goto yy219; +yy76: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '?'){ + if(yych <= '\''){ + if(yych == '"') goto yy95; + if(yych <= '&') goto yy6; + goto yy238; + } else { + if(yych <= '/') goto yy6; + if(yych <= '9') goto yy218; + if(yych <= '>') goto yy6; + goto yy221; + } + } else { + if(yych <= '\\'){ + if(yych <= '@') goto yy6; + if(yych <= 'Z') goto yy218; + if(yych <= '[') goto yy6; + goto yy220; + } else { + if(yych <= '_'){ + if(yych <= '^') goto yy6; + goto yy218; + } else { + if(yych <= '`') goto yy6; + if(yych <= 'z') goto yy218; + goto yy6; + } + } + } +yy77: yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'U') goto yy210; + if(yych == 'u') goto yy209; + goto yy78; +yy78: +#line 624 + { + /* if (0 != s->error_proc) + (*s->error_proc)(s, "Unexpected character: '%c'", *s->tok); + else + printf("unexpected character: '%c'\n", *s->tok); + */ + RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); + } +yy79: yyaccept = 6; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'U'){ + if(yych <= '9'){ + if(yych <= '.'){ + if(yych >= '.') goto yy186; + goto yy80; + } else { + if(yych <= '/') goto yy80; + if(yych <= '7') goto yy202; + goto yy204; + } + } else { + if(yych <= 'K'){ + if(yych == 'E') goto yy183; + goto yy80; + } else { + if(yych <= 'L') goto yy190; + if(yych >= 'U') goto yy189; + goto yy80; + } + } + } else { + if(yych <= 'k'){ + if(yych <= 'X'){ + if(yych >= 'X') goto yy206; + goto yy80; + } else { + if(yych == 'e') goto yy183; + goto yy80; + } + } else { + if(yych <= 'u'){ + if(yych <= 'l') goto yy190; + if(yych >= 'u') goto yy189; + goto yy80; + } else { + if(yych == 'x') goto yy206; + goto yy80; + } + } + } +yy80: +#line 564 + { RET(T_INTLIT); } +yy81: yyaccept = 6; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'L'){ + if(yych <= '9'){ + if(yych == '.') goto yy186; + if(yych <= '/') goto yy80; + goto yy184; + } else { + if(yych == 'E') goto yy183; + if(yych <= 'K') goto yy80; + goto yy190; + } + } else { + if(yych <= 'e'){ + if(yych == 'U') goto yy189; + if(yych <= 'd') goto yy80; + goto yy183; + } else { + if(yych <= 'l'){ + if(yych <= 'k') goto yy80; + goto yy190; + } else { + if(yych == 'u') goto yy189; + goto yy80; + } + } + } +yy82: yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '\f'){ + if(yych == '\t') goto yy140; + if(yych <= '\n') goto yy78; + goto yy140; + } else { + if(yych <= '\037') goto yy78; + if(yych == '\'') goto yy78; + goto yy140; + } +yy83: yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '\n'){ + if(yych == '\t') goto yy96; + goto yy78; + } else { + if(yych <= '\f') goto yy96; + if(yych <= '\037') goto yy78; + goto yy96; + } +yy84: yych = *++YYCURSOR; + goto yy94; +yy85: +#line 603 + { RET(T_SPACE); } +yy86: yych = *++YYCURSOR; + goto yy87; +yy87: +#line 606 + { + s->line++; + RET(T_NEWLINE); + } +yy88: yych = *++YYCURSOR; + if(yych == '\n') goto yy92; + goto yy87; +yy89: yych = *++YYCURSOR; + goto yy90; +yy90: +#line 612 + { + if(cursor != s->eof) + { + if (0 != s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file\n"); + } + RET(T_EOF); + } +yy91: yych = *++YYCURSOR; + goto yy78; +yy92: yych = *++YYCURSOR; + goto yy87; +yy93: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy94; +yy94: if(yych <= '\n'){ + if(yych == '\t') goto yy93; + goto yy85; + } else { + if(yych <= '\f') goto yy93; + if(yych == ' ') goto yy93; + goto yy85; + } +yy95: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy96; +yy96: if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy97; + } else { + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy97: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy110; + } else { + if(yych != '\\') goto yy95; + goto yy98; + } + } +yy98: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '`'){ + if(yych <= '7'){ + if(yych <= '&'){ + if(yych == '"') goto yy95; + goto yy2; + } else { + if(yych <= '\'') goto yy95; + if(yych <= '/') goto yy2; + goto yy105; + } + } else { + if(yych <= 'T'){ + if(yych == '?') goto yy103; + goto yy2; + } else { + if(yych <= 'U') goto yy102; + if(yych == '\\') goto yy95; + goto yy2; + } + } + } else { + if(yych <= 'r'){ + if(yych <= 'f'){ + if(yych <= 'b') goto yy95; + if(yych <= 'e') goto yy2; + goto yy95; + } else { + if(yych == 'n') goto yy95; + if(yych <= 'q') goto yy2; + goto yy95; + } + } else { + if(yych <= 'u'){ + if(yych <= 's') goto yy2; + if(yych <= 't') goto yy95; + goto yy101; + } else { + if(yych <= 'v') goto yy95; + if(yych == 'x') goto yy104; + goto yy2; + } + } + } +yy99: yych = *++YYCURSOR; + goto yy100; +yy100: +#line 573 + { RET(T_STRINGLIT); } +yy101: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy136; + goto yy2; + } else { + if(yych <= 'F') goto yy136; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy136; + goto yy2; + } +yy102: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy129; + goto yy2; + } else { + if(yych <= 'F') goto yy129; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy129; + goto yy2; + } +yy103: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy109; + } else { + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy104: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy107; + goto yy2; + } else { + if(yych <= 'F') goto yy107; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy107; + goto yy2; + } +yy105: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '"'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + if(yych <= '!') goto yy95; + goto yy99; + } + } else { + if(yych <= '>'){ + if(yych <= '/') goto yy95; + if(yych >= '8') goto yy95; + goto yy106; + } else { + if(yych <= '?') goto yy97; + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy106: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy97; + } else { + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy107: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy108; +yy108: if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy107; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy107; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych <= 'f') goto yy107; + goto yy95; + } + } + } +yy109: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy110; + } else { + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy110: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy111; +yy111: if(yych <= '"'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + if(yych <= '!') goto yy95; + goto yy99; + } + } else { + if(yych <= '>'){ + if(yych != '/') goto yy95; + goto yy112; + } else { + if(yych <= '?') goto yy110; + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy112: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy113; +yy113: if(yych <= '>'){ + if(yych <= '\037'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy2; + goto yy95; + } else { + if(yych <= '\n') goto yy2; + if(yych <= '\f') goto yy95; + goto yy2; + } + } else { + if(yych <= '"'){ + if(yych <= '!') goto yy95; + goto yy116; + } else { + if(yych <= '/') goto yy95; + if(yych <= '7') goto yy105; + goto yy95; + } + } + } else { + if(yych <= '\\'){ + if(yych <= 'T'){ + if(yych <= '?') goto yy117; + goto yy95; + } else { + if(yych <= 'U') goto yy115; + if(yych <= '[') goto yy95; + goto yy112; + } + } else { + if(yych <= 'u'){ + if(yych <= 't') goto yy95; + goto yy114; + } else { + if(yych == 'x') goto yy107; + goto yy95; + } + } + } +yy114: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy126; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy126; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych <= 'f') goto yy126; + goto yy95; + } + } + } +yy115: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy119; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy119; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych <= 'f') goto yy119; + goto yy95; + } + } + } +yy116: yyaccept = 7; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy100; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy100; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy97; + } else { + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy117: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy118; + } else { + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy118: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '"'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + if(yych <= '!') goto yy95; + goto yy99; + } + } else { + if(yych <= '>'){ + if(yych == '/') goto yy112; + goto yy95; + } else { + if(yych <= '?') goto yy110; + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy119: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy120; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy120; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych >= 'g') goto yy95; + goto yy120; + } + } + } +yy120: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy121; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy121; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych >= 'g') goto yy95; + goto yy121; + } + } + } +yy121: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy122; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy122; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych >= 'g') goto yy95; + goto yy122; + } + } + } +yy122: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy123; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy123; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych >= 'g') goto yy95; + goto yy123; + } + } + } +yy123: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy124; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy124; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych >= 'g') goto yy95; + goto yy124; + } + } + } +yy124: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy125; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy125; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych >= 'g') goto yy95; + goto yy125; + } + } + } +yy125: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy97; + } else { + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy126: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy127; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy127; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych >= 'g') goto yy95; + goto yy127; + } + } + } +yy127: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy95; + if(yych <= '\n') goto yy2; + goto yy95; + } else { + if(yych <= '!'){ + if(yych <= '\037') goto yy2; + goto yy95; + } else { + if(yych <= '"') goto yy99; + if(yych <= '/') goto yy95; + goto yy128; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy97; + if(yych <= '@') goto yy95; + goto yy128; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy95; + goto yy98; + } else { + if(yych <= '`') goto yy95; + if(yych >= 'g') goto yy95; + goto yy128; + } + } + } +yy128: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '!'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy95; + goto yy2; + } else { + if(yych <= '\f') goto yy95; + if(yych <= '\037') goto yy2; + goto yy95; + } + } else { + if(yych <= '?'){ + if(yych <= '"') goto yy99; + if(yych <= '>') goto yy95; + goto yy97; + } else { + if(yych == '\\') goto yy98; + goto yy95; + } + } +yy129: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy130; + } else { + if(yych <= 'F') goto yy130; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy130; + } +yy130: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy131; + } else { + if(yych <= 'F') goto yy131; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy131; + } +yy131: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy132; + } else { + if(yych <= 'F') goto yy132; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy132; + } +yy132: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy133; + } else { + if(yych <= 'F') goto yy133; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy133; + } +yy133: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy134; + } else { + if(yych <= 'F') goto yy134; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy134; + } +yy134: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy135; + } else { + if(yych <= 'F') goto yy135; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy135; + } +yy135: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy95; + goto yy2; + } else { + if(yych <= 'F') goto yy95; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy95; + goto yy2; + } +yy136: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy137; + } else { + if(yych <= 'F') goto yy137; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy137; + } +yy137: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy138; + } else { + if(yych <= 'F') goto yy138; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy138; + } +yy138: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy95; + goto yy2; + } else { + if(yych <= 'F') goto yy95; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy95; + goto yy2; + } +yy139: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy140; +yy140: if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy141; + } else { + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy141: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy154; + } else { + if(yych != '\\') goto yy139; + goto yy142; + } + } +yy142: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '`'){ + if(yych <= '7'){ + if(yych <= '&'){ + if(yych == '"') goto yy139; + goto yy2; + } else { + if(yych <= '\'') goto yy139; + if(yych <= '/') goto yy2; + goto yy147; + } + } else { + if(yych <= 'T'){ + if(yych == '?') goto yy145; + goto yy2; + } else { + if(yych <= 'U') goto yy144; + if(yych == '\\') goto yy139; + goto yy2; + } + } + } else { + if(yych <= 'r'){ + if(yych <= 'f'){ + if(yych <= 'b') goto yy139; + if(yych <= 'e') goto yy2; + goto yy139; + } else { + if(yych == 'n') goto yy139; + if(yych <= 'q') goto yy2; + goto yy139; + } + } else { + if(yych <= 'u'){ + if(yych <= 's') goto yy2; + if(yych <= 't') goto yy139; + goto yy143; + } else { + if(yych <= 'v') goto yy139; + if(yych == 'x') goto yy146; + goto yy2; + } + } + } +yy143: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy180; + goto yy2; + } else { + if(yych <= 'F') goto yy180; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy180; + goto yy2; + } +yy144: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy173; + goto yy2; + } else { + if(yych <= 'F') goto yy173; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy173; + goto yy2; + } +yy145: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy153; + } else { + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy146: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy151; + goto yy2; + } else { + if(yych <= 'F') goto yy151; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy151; + goto yy2; + } +yy147: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '\''){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + if(yych <= '&') goto yy139; + goto yy149; + } + } else { + if(yych <= '>'){ + if(yych <= '/') goto yy139; + if(yych >= '8') goto yy139; + goto yy148; + } else { + if(yych <= '?') goto yy141; + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy148: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy141; + } else { + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy149: yych = *++YYCURSOR; + goto yy150; +yy150: +#line 570 + { RET(T_CHARLIT); } +yy151: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy152; +yy152: if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy151; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy151; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych <= 'f') goto yy151; + goto yy139; + } + } + } +yy153: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy154; + } else { + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy154: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy155; +yy155: if(yych <= '\''){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + if(yych <= '&') goto yy139; + goto yy149; + } + } else { + if(yych <= '>'){ + if(yych != '/') goto yy139; + goto yy156; + } else { + if(yych <= '?') goto yy154; + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy156: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy157; +yy157: if(yych <= '>'){ + if(yych <= '\037'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy2; + goto yy139; + } else { + if(yych <= '\n') goto yy2; + if(yych <= '\f') goto yy139; + goto yy2; + } + } else { + if(yych <= '\''){ + if(yych <= '&') goto yy139; + goto yy160; + } else { + if(yych <= '/') goto yy139; + if(yych <= '7') goto yy147; + goto yy139; + } + } + } else { + if(yych <= '\\'){ + if(yych <= 'T'){ + if(yych <= '?') goto yy161; + goto yy139; + } else { + if(yych <= 'U') goto yy159; + if(yych <= '[') goto yy139; + goto yy156; + } + } else { + if(yych <= 'u'){ + if(yych <= 't') goto yy139; + goto yy158; + } else { + if(yych == 'x') goto yy151; + goto yy139; + } + } + } +yy158: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy170; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy170; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych <= 'f') goto yy170; + goto yy139; + } + } + } +yy159: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy163; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy163; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych <= 'f') goto yy163; + goto yy139; + } + } + } +yy160: yyaccept = 8; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy150; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy150; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy141; + } else { + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy161: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy162; + } else { + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy162: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '\''){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + if(yych <= '&') goto yy139; + goto yy149; + } + } else { + if(yych <= '>'){ + if(yych == '/') goto yy156; + goto yy139; + } else { + if(yych <= '?') goto yy154; + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy163: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy164; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy164; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych >= 'g') goto yy139; + goto yy164; + } + } + } +yy164: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy165; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy165; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych >= 'g') goto yy139; + goto yy165; + } + } + } +yy165: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy166; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy166; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych >= 'g') goto yy139; + goto yy166; + } + } + } +yy166: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy167; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy167; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych >= 'g') goto yy139; + goto yy167; + } + } + } +yy167: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy168; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy168; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych >= 'g') goto yy139; + goto yy168; + } + } + } +yy168: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy169; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy169; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych >= 'g') goto yy139; + goto yy169; + } + } + } +yy169: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy141; + } else { + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy170: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy171; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy171; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych >= 'g') goto yy139; + goto yy171; + } + } + } +yy171: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '9'){ + if(yych <= '\f'){ + if(yych == '\t') goto yy139; + if(yych <= '\n') goto yy2; + goto yy139; + } else { + if(yych <= '&'){ + if(yych <= '\037') goto yy2; + goto yy139; + } else { + if(yych <= '\'') goto yy149; + if(yych <= '/') goto yy139; + goto yy172; + } + } + } else { + if(yych <= 'F'){ + if(yych == '?') goto yy141; + if(yych <= '@') goto yy139; + goto yy172; + } else { + if(yych <= '\\'){ + if(yych <= '[') goto yy139; + goto yy142; + } else { + if(yych <= '`') goto yy139; + if(yych >= 'g') goto yy139; + goto yy172; + } + } + } +yy172: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych == '\t') goto yy139; + goto yy2; + } else { + if(yych <= '\f') goto yy139; + if(yych <= '\037') goto yy2; + goto yy139; + } + } else { + if(yych <= '?'){ + if(yych <= '\'') goto yy149; + if(yych <= '>') goto yy139; + goto yy141; + } else { + if(yych == '\\') goto yy142; + goto yy139; + } + } +yy173: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy174; + } else { + if(yych <= 'F') goto yy174; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy174; + } +yy174: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy175; + } else { + if(yych <= 'F') goto yy175; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy175; + } +yy175: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy176; + } else { + if(yych <= 'F') goto yy176; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy176; + } +yy176: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy177; + } else { + if(yych <= 'F') goto yy177; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy177; + } +yy177: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy178; + } else { + if(yych <= 'F') goto yy178; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy178; + } +yy178: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy179; + } else { + if(yych <= 'F') goto yy179; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy179; + } +yy179: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy139; + goto yy2; + } else { + if(yych <= 'F') goto yy139; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy139; + goto yy2; + } +yy180: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy181; + } else { + if(yych <= 'F') goto yy181; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy181; + } +yy181: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy182; + } else { + if(yych <= 'F') goto yy182; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy182; + } +yy182: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy139; + goto yy2; + } else { + if(yych <= 'F') goto yy139; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy139; + goto yy2; + } +yy183: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych == '+') goto yy199; + goto yy2; + } else { + if(yych <= '-') goto yy199; + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy200; + goto yy2; + } +yy184: yyaccept = 6; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy185; +yy185: if(yych <= 'L'){ + if(yych <= '9'){ + if(yych == '.') goto yy186; + if(yych <= '/') goto yy80; + goto yy184; + } else { + if(yych == 'E') goto yy183; + if(yych <= 'K') goto yy80; + goto yy190; + } + } else { + if(yych <= 'e'){ + if(yych == 'U') goto yy189; + if(yych <= 'd') goto yy80; + goto yy183; + } else { + if(yych <= 'l'){ + if(yych <= 'k') goto yy80; + goto yy190; + } else { + if(yych == 'u') goto yy189; + goto yy80; + } + } + } +yy186: yyaccept = 9; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy187; +yy187: if(yych <= 'K'){ + if(yych <= 'D'){ + if(yych <= '/') goto yy188; + if(yych <= '9') goto yy186; + goto yy188; + } else { + if(yych <= 'E') goto yy192; + if(yych <= 'F') goto yy193; + goto yy188; + } + } else { + if(yych <= 'e'){ + if(yych <= 'L') goto yy194; + if(yych >= 'e') goto yy192; + goto yy188; + } else { + if(yych <= 'f') goto yy193; + if(yych == 'l') goto yy194; + goto yy188; + } + } +yy188: +#line 567 + { RET(T_FLOATLIT); } +yy189: yych = *++YYCURSOR; + if(yych == 'L') goto yy191; + if(yych == 'l') goto yy191; + goto yy80; +yy190: yych = *++YYCURSOR; + if(yych == 'U') goto yy191; + if(yych != 'u') goto yy80; + goto yy191; +yy191: yych = *++YYCURSOR; + goto yy80; +yy192: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych == '+') goto yy196; + goto yy2; + } else { + if(yych <= '-') goto yy196; + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy197; + goto yy2; + } +yy193: yych = *++YYCURSOR; + if(yych == 'L') goto yy195; + if(yych == 'l') goto yy195; + goto yy188; +yy194: yych = *++YYCURSOR; + if(yych == 'F') goto yy195; + if(yych != 'f') goto yy188; + goto yy195; +yy195: yych = *++YYCURSOR; + goto yy188; +yy196: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy197; +yy197: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy198; +yy198: if(yych <= 'K'){ + if(yych <= '9'){ + if(yych <= '/') goto yy188; + goto yy197; + } else { + if(yych == 'F') goto yy193; + goto yy188; + } + } else { + if(yych <= 'f'){ + if(yych <= 'L') goto yy194; + if(yych <= 'e') goto yy188; + goto yy193; + } else { + if(yych == 'l') goto yy194; + goto yy188; + } + } +yy199: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy200; +yy200: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy201; +yy201: if(yych <= 'K'){ + if(yych <= '9'){ + if(yych <= '/') goto yy188; + goto yy200; + } else { + if(yych == 'F') goto yy193; + goto yy188; + } + } else { + if(yych <= 'f'){ + if(yych <= 'L') goto yy194; + if(yych <= 'e') goto yy188; + goto yy193; + } else { + if(yych == 'l') goto yy194; + goto yy188; + } + } +yy202: yyaccept = 6; + YYMARKER = ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy203; +yy203: if(yych <= 'L'){ + if(yych <= '7'){ + if(yych == '.') goto yy186; + if(yych <= '/') goto yy80; + goto yy202; + } else { + if(yych <= 'D'){ + if(yych >= ':') goto yy80; + goto yy204; + } else { + if(yych <= 'E') goto yy183; + if(yych <= 'K') goto yy80; + goto yy190; + } + } + } else { + if(yych <= 'e'){ + if(yych == 'U') goto yy189; + if(yych <= 'd') goto yy80; + goto yy183; + } else { + if(yych <= 'l'){ + if(yych <= 'k') goto yy80; + goto yy190; + } else { + if(yych == 'u') goto yy189; + goto yy80; + } + } + } +yy204: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + goto yy205; +yy205: if(yych <= '9'){ + if(yych == '.') goto yy186; + if(yych <= '/') goto yy2; + goto yy204; + } else { + if(yych <= 'E'){ + if(yych <= 'D') goto yy2; + goto yy183; + } else { + if(yych == 'e') goto yy183; + goto yy2; + } + } +yy206: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy207; + } else { + if(yych <= 'F') goto yy207; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy207; + } +yy207: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + goto yy208; +yy208: if(yych <= 'T'){ + if(yych <= '@'){ + if(yych <= '/') goto yy80; + if(yych <= '9') goto yy207; + goto yy80; + } else { + if(yych <= 'F') goto yy207; + if(yych == 'L') goto yy190; + goto yy80; + } + } else { + if(yych <= 'k'){ + if(yych <= 'U') goto yy189; + if(yych <= '`') goto yy80; + if(yych <= 'f') goto yy207; + goto yy80; + } else { + if(yych <= 'l') goto yy190; + if(yych == 'u') goto yy189; + goto yy80; + } + } +yy209: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy235; + goto yy2; + } else { + if(yych <= 'F') goto yy235; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy235; + goto yy2; + } +yy210: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy211; + } else { + if(yych <= 'F') goto yy211; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy211; + } +yy211: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy212; + } else { + if(yych <= 'F') goto yy212; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy212; + } +yy212: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy213; + } else { + if(yych <= 'F') goto yy213; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy213; + } +yy213: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy214; + } else { + if(yych <= 'F') goto yy214; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy214; + } +yy214: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy215; + } else { + if(yych <= 'F') goto yy215; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy215; + } +yy215: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy216; + } else { + if(yych <= 'F') goto yy216; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy216; + } +yy216: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy217; + } else { + if(yych <= 'F') goto yy217; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy217; + } +yy217: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy218; + } else { + if(yych <= 'F') goto yy218; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy218; + } +yy218: yyaccept = 0; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy219; +yy219: if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy6; + if(yych <= '9') goto yy218; + goto yy6; + } else { + if(yych <= '?') goto yy221; + if(yych <= '@') goto yy6; + goto yy218; + } + } else { + if(yych <= '^'){ + if(yych != '\\') goto yy6; + goto yy220; + } else { + if(yych == '`') goto yy6; + if(yych <= 'z') goto yy218; + goto yy6; + } + } +yy220: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == 'U') goto yy224; + if(yych == 'u') goto yy223; + goto yy2; +yy221: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych != '?') goto yy2; + goto yy222; +yy222: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '/') goto yy220; + goto yy2; +yy223: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy232; + goto yy2; + } else { + if(yych <= 'F') goto yy232; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy232; + goto yy2; + } +yy224: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy225; + } else { + if(yych <= 'F') goto yy225; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy225; + } +yy225: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy226; + } else { + if(yych <= 'F') goto yy226; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy226; + } +yy226: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy227; + } else { + if(yych <= 'F') goto yy227; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy227; + } +yy227: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy228; + } else { + if(yych <= 'F') goto yy228; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy228; + } +yy228: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy229; + } else { + if(yych <= 'F') goto yy229; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy229; + } +yy229: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy230; + } else { + if(yych <= 'F') goto yy230; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy230; + } +yy230: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy231; + } else { + if(yych <= 'F') goto yy231; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy231; + } +yy231: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy218; + goto yy2; + } else { + if(yych <= 'F') goto yy218; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy218; + goto yy2; + } +yy232: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy233; + } else { + if(yych <= 'F') goto yy233; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy233; + } +yy233: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy234; + } else { + if(yych <= 'F') goto yy234; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy234; + } +yy234: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy218; + goto yy2; + } else { + if(yych <= 'F') goto yy218; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy218; + goto yy2; + } +yy235: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy236; + } else { + if(yych <= 'F') goto yy236; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy236; + } +yy236: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; + goto yy237; + } else { + if(yych <= 'F') goto yy237; + if(yych <= '`') goto yy2; + if(yych >= 'g') goto yy2; + goto yy237; + } +yy237: yych = *++YYCURSOR; + if(yych <= '@'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy218; + goto yy2; + } else { + if(yych <= 'F') goto yy218; + if(yych <= '`') goto yy2; + if(yych <= 'f') goto yy218; + goto yy2; + } +yy238: yych = *++YYCURSOR; + if(yych == '\'') goto yy2; + goto yy140; +yy239: yych = *++YYCURSOR; + goto yy240; +yy240: +#line 537 + { RET(T_GREATEREQUAL); } +yy241: yych = *++YYCURSOR; + if(yych == '=') goto yy243; + goto yy242; +yy242: +#line 530 + { RET(T_SHIFTRIGHT); } +yy243: yych = *++YYCURSOR; + goto yy244; +yy244: +#line 531 + { RET(T_SHIFTRIGHTASSIGN); } +yy245: yych = *++YYCURSOR; + goto yy246; +yy246: +#line 533 + { RET(T_EQUAL); } +yy247: yych = *++YYCURSOR; + goto yy248; +yy248: +#line 534 + { RET(T_NOTEQUAL); } +yy249: yych = *++YYCURSOR; + if(yych == '?') goto yy254; + goto yy2; +yy250: yych = *++YYCURSOR; + goto yy251; +yy251: +#line 540 + { RET(T_OROR); } +yy252: yych = *++YYCURSOR; + goto yy253; +yy253: +#line 526 + { RET(T_ORASSIGN); } +yy254: yych = *++YYCURSOR; + if(yych != '!') goto yy2; + goto yy255; +yy255: yych = *++YYCURSOR; + goto yy256; +yy256: +#line 542 + { RET(T_OROR); } +yy257: yych = *++YYCURSOR; + goto yy258; +yy258: +#line 538 + { RET(T_ANDAND); } +yy259: yych = *++YYCURSOR; + goto yy260; +yy260: +#line 524 + { RET(T_ANDASSIGN); } +yy261: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy262; +yy262: yyaccept = 10; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy263; + if(yych <= '9') goto yy218; + goto yy263; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy263; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy263; + } else { + if(yych <= '_') goto yy264; + if(yych <= '`') goto yy263; + if(yych <= 'z') goto yy218; + goto yy263; + } + } +yy263: +#line 502 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_XOR_ALT); } +yy264: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy265; +yy265: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'q') goto yy219; + goto yy266; +yy266: yyaccept = 11; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy267; + if(yych <= '9') goto yy218; + goto yy267; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy267; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy267; + } else { + if(yych == '`') goto yy267; + if(yych <= 'z') goto yy218; + goto yy267; + } + } +yy267: +#line 522 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_XORASSIGN_ALT); } +yy268: yych = *++YYCURSOR; + goto yy269; +yy269: +#line 521 + { RET(T_XORASSIGN); } +yy270: yych = *++YYCURSOR; + goto yy271; +yy271: +#line 518 + { RET(T_STARASSIGN); } +yy272: yych = *++YYCURSOR; + if(yych == '*') goto yy278; + goto yy273; +yy273: +#line 558 + { RET(T_ARROW); } +yy274: yych = *++YYCURSOR; + goto yy275; +yy275: +#line 546 + { RET(T_MINUSMINUS); } +yy276: yych = *++YYCURSOR; + goto yy277; +yy277: +#line 517 + { RET(T_MINUSASSIGN); } +yy278: yych = *++YYCURSOR; + goto yy279; +yy279: +#line 549 + { + if (s->act_in_c99_mode) { + --YYCURSOR; + RET(T_ARROW); + } + else { + RET(T_ARROWSTAR); + } + } +yy280: yych = *++YYCURSOR; + goto yy281; +yy281: +#line 545 + { RET(T_PLUSPLUS); } +yy282: yych = *++YYCURSOR; + goto yy283; +yy283: +#line 516 + { RET(T_PLUSASSIGN); } +yy284: yych = *++YYCURSOR; + goto yy285; +yy285: +#line 486 + { + if (s->act_in_c99_mode) { + --YYCURSOR; + RET(T_DOT); + } + else { + RET(T_DOTSTAR); + } + } +yy286: yych = *++YYCURSOR; + if(yych != '.') goto yy2; + goto yy287; +yy287: yych = *++YYCURSOR; + goto yy288; +yy288: +#line 472 + { RET(T_ELLIPSIS); } +yy289: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy290; +yy290: if(yych <= 'i'){ + if(yych <= '.'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy2; + goto yy289; + } else { + if(yych == ' ') goto yy289; + goto yy2; + } + } else { + if(yych <= 'd'){ + if(yych <= '/') goto yy291; + if(yych <= 'c') goto yy2; + goto yy298; + } else { + if(yych <= 'e') goto yy292; + if(yych <= 'h') goto yy2; + goto yy299; + } + } + } else { + if(yych <= 'q'){ + if(yych <= 'l'){ + if(yych <= 'k') goto yy2; + goto yy296; + } else { + if(yych == 'p') goto yy295; + goto yy2; + } + } else { + if(yych <= 'u'){ + if(yych <= 'r') goto yy293; + if(yych <= 't') goto yy2; + goto yy297; + } else { + if(yych == 'w') goto yy294; + goto yy2; + } + } + } +yy291: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '*') goto yy406; + goto yy2; +yy292: yych = *++YYCURSOR; + if(yych <= 'm'){ + if(yych == 'l') goto yy382; + goto yy2; + } else { + if(yych <= 'n') goto yy383; + if(yych == 'r') goto yy384; + goto yy2; + } +yy293: yych = *++YYCURSOR; + if(yych == 'e') goto yy376; + goto yy2; +yy294: yych = *++YYCURSOR; + if(yych == 'a') goto yy369; + goto yy2; +yy295: yych = *++YYCURSOR; + if(yych == 'r') goto yy363; + goto yy2; +yy296: yych = *++YYCURSOR; + if(yych == 'i') goto yy359; + goto yy2; +yy297: yych = *++YYCURSOR; + if(yych == 'n') goto yy354; + goto yy2; +yy298: yych = *++YYCURSOR; + if(yych == 'e') goto yy348; + goto yy2; +yy299: yych = *++YYCURSOR; + if(yych == 'f') goto yy307; + if(yych == 'n') goto yy306; + goto yy2; +yy300: yych = *++YYCURSOR; + if(yych == '?') goto yy303; + goto yy2; +yy301: yych = *++YYCURSOR; + goto yy302; +yy302: +#line 463 + { RET(T_POUND_POUND); } +yy303: yych = *++YYCURSOR; + if(yych != '=') goto yy2; + goto yy304; +yy304: yych = *++YYCURSOR; + goto yy305; +yy305: +#line 464 + { RET(T_POUND_POUND_TRIGRAPH); } +yy306: yych = *++YYCURSOR; + if(yych == 'c') goto yy318; + goto yy2; +yy307: yyaccept = 12; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'd') goto yy310; + if(yych == 'n') goto yy309; + goto yy308; +yy308: +#line 585 + { RET(T_PP_IF); } +yy309: yych = *++YYCURSOR; + if(yych == 'd') goto yy314; + goto yy2; +yy310: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy311; +yy311: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy312; +yy312: yych = *++YYCURSOR; + goto yy313; +yy313: +#line 586 + { RET(T_PP_IFDEF); } +yy314: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy315; +yy315: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy316; +yy316: yych = *++YYCURSOR; + goto yy317; +yy317: +#line 587 + { RET(T_PP_IFNDEF); } +yy318: yych = *++YYCURSOR; + if(yych != 'l') goto yy2; + goto yy319; +yy319: yych = *++YYCURSOR; + if(yych != 'u') goto yy2; + goto yy320; +yy320: yych = *++YYCURSOR; + if(yych != 'd') goto yy2; + goto yy321; +yy321: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy322; +yy322: yyaccept = 13; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '_') goto yy324; + goto yy326; +yy323: +#line 583 + { RET(T_PP_INCLUDE); } +yy324: yych = *++YYCURSOR; + if(yych == 'n') goto yy345; + goto yy2; +yy325: yyaccept = 13; + YYMARKER = ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy326; +yy326: if(yych <= '!'){ + if(yych <= '\t'){ + if(yych <= '\b') goto yy323; + goto yy325; + } else { + if(yych == ' ') goto yy325; + goto yy323; + } + } else { + if(yych <= '/'){ + if(yych <= '"') goto yy329; + if(yych <= '.') goto yy323; + goto yy327; + } else { + if(yych == '<') goto yy328; + goto yy323; + } + } +yy327: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '*') goto yy338; + goto yy2; +yy328: yych = *++YYCURSOR; + if(yych == '>') goto yy2; + goto yy335; +yy329: yych = *++YYCURSOR; + if(yych == '"') goto yy2; + goto yy331; +yy330: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy331; +yy331: if(yych <= '\f'){ + if(yych == '\t') goto yy330; + if(yych <= '\n') goto yy2; + goto yy330; + } else { + if(yych <= '\037') goto yy2; + if(yych != '"') goto yy330; + goto yy332; + } +yy332: yych = *++YYCURSOR; + goto yy333; +yy333: +#line 580 + { RET(T_PP_QHEADER); } +yy334: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy335; +yy335: if(yych <= '\f'){ + if(yych == '\t') goto yy334; + if(yych <= '\n') goto yy2; + goto yy334; + } else { + if(yych <= '\037') goto yy2; + if(yych != '>') goto yy334; + goto yy336; + } +yy336: yych = *++YYCURSOR; + goto yy337; +yy337: +#line 577 + { RET(T_PP_HHEADER); } +yy338: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy339; +yy339: if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy338; + goto yy340; + } else { + if(yych <= '\037') goto yy2; + if(yych == '*') goto yy342; + goto yy338; + } +yy340: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy341; +yy341: if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy338; + goto yy340; + } else { + if(yych <= '\037') goto yy2; + if(yych != '*') goto yy338; + goto yy342; + } +yy342: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy343; +yy343: if(yych <= '\037'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy338; + if(yych >= '\016') goto yy2; + goto yy344; + } else { + if(yych <= '*'){ + if(yych <= ')') goto yy338; + goto yy342; + } else { + if(yych == '/') goto yy325; + goto yy338; + } + } +yy344: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy338; + goto yy340; + } else { + if(yych <= '\037') goto yy2; + if(yych == '*') goto yy342; + goto yy338; + } +yy345: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy346; +yy346: yych = *++YYCURSOR; + if(yych != 'x') goto yy2; + goto yy347; +yy347: yych = *++YYCURSOR; + if(yych == 't') goto yy325; + goto yy2; +yy348: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy349; +yy349: yych = *++YYCURSOR; + if(yych != 'i') goto yy2; + goto yy350; +yy350: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy351; +yy351: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy352; +yy352: yych = *++YYCURSOR; + goto yy353; +yy353: +#line 591 + { RET(T_PP_DEFINE); } +yy354: yych = *++YYCURSOR; + if(yych != 'd') goto yy2; + goto yy355; +yy355: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy356; +yy356: yych = *++YYCURSOR; + if(yych != 'f') goto yy2; + goto yy357; +yy357: yych = *++YYCURSOR; + goto yy358; +yy358: +#line 592 + { RET(T_PP_UNDEF); } +yy359: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy360; +yy360: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy361; +yy361: yych = *++YYCURSOR; + goto yy362; +yy362: +#line 593 + { RET(T_PP_LINE); } +yy363: yych = *++YYCURSOR; + if(yych != 'a') goto yy2; + goto yy364; +yy364: yych = *++YYCURSOR; + if(yych != 'g') goto yy2; + goto yy365; +yy365: yych = *++YYCURSOR; + if(yych != 'm') goto yy2; + goto yy366; +yy366: yych = *++YYCURSOR; + if(yych != 'a') goto yy2; + goto yy367; +yy367: yych = *++YYCURSOR; + goto yy368; +yy368: +#line 595 + { RET(T_PP_PRAGMA); } +yy369: yych = *++YYCURSOR; + if(yych != 'r') goto yy2; + goto yy370; +yy370: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy371; +yy371: yych = *++YYCURSOR; + if(yych != 'i') goto yy2; + goto yy372; +yy372: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy373; +yy373: yych = *++YYCURSOR; + if(yych != 'g') goto yy2; + goto yy374; +yy374: yych = *++YYCURSOR; + goto yy375; +yy375: +#line 597 + { RET(T_PP_WARNING); } +yy376: yych = *++YYCURSOR; + if(yych != 'g') goto yy2; + goto yy377; +yy377: yych = *++YYCURSOR; + if(yych != 'i') goto yy2; + goto yy378; +yy378: yych = *++YYCURSOR; + if(yych != 'o') goto yy2; + goto yy379; +yy379: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy380; +yy380: yych = *++YYCURSOR; + goto yy381; +yy381: +#line 599 + { RET(T_MSEXT_PP_REGION); } +yy382: yych = *++YYCURSOR; + if(yych == 'i') goto yy400; + if(yych == 's') goto yy401; + goto yy2; +yy383: yych = *++YYCURSOR; + if(yych == 'd') goto yy389; + goto yy2; +yy384: yych = *++YYCURSOR; + if(yych != 'r') goto yy2; + goto yy385; +yy385: yych = *++YYCURSOR; + if(yych != 'o') goto yy2; + goto yy386; +yy386: yych = *++YYCURSOR; + if(yych != 'r') goto yy2; + goto yy387; +yy387: yych = *++YYCURSOR; + goto yy388; +yy388: +#line 594 + { RET(T_PP_ERROR); } +yy389: yych = *++YYCURSOR; + if(yych == 'i') goto yy390; + if(yych == 'r') goto yy391; + goto yy2; +yy390: yych = *++YYCURSOR; + if(yych == 'f') goto yy398; + goto yy2; +yy391: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy392; +yy392: yych = *++YYCURSOR; + if(yych != 'g') goto yy2; + goto yy393; +yy393: yych = *++YYCURSOR; + if(yych != 'i') goto yy2; + goto yy394; +yy394: yych = *++YYCURSOR; + if(yych != 'o') goto yy2; + goto yy395; +yy395: yych = *++YYCURSOR; + if(yych != 'n') goto yy2; + goto yy396; +yy396: yych = *++YYCURSOR; + goto yy397; +yy397: +#line 600 + { RET(T_MSEXT_PP_ENDREGION); } +yy398: yych = *++YYCURSOR; + goto yy399; +yy399: +#line 590 + { RET(T_PP_ENDIF); } +yy400: yych = *++YYCURSOR; + if(yych == 'f') goto yy404; + goto yy2; +yy401: yych = *++YYCURSOR; + if(yych != 'e') goto yy2; + goto yy402; +yy402: yych = *++YYCURSOR; + goto yy403; +yy403: +#line 588 + { RET(T_PP_ELSE); } +yy404: yych = *++YYCURSOR; + goto yy405; +yy405: +#line 589 + { RET(T_PP_ELIF); } +yy406: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy407; +yy407: if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy406; + goto yy408; + } else { + if(yych <= '\037') goto yy2; + if(yych == '*') goto yy410; + goto yy406; + } +yy408: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy409; +yy409: if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy406; + goto yy408; + } else { + if(yych <= '\037') goto yy2; + if(yych != '*') goto yy406; + goto yy410; + } +yy410: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + goto yy411; +yy411: if(yych <= '\037'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy406; + if(yych >= '\016') goto yy2; + goto yy412; + } else { + if(yych <= '*'){ + if(yych <= ')') goto yy406; + goto yy410; + } else { + if(yych == '/') goto yy289; + goto yy406; + } + } +yy412: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych <= '\r'){ + if(yych <= '\b') goto yy2; + if(yych <= '\f') goto yy406; + goto yy408; + } else { + if(yych <= '\037') goto yy2; + if(yych == '*') goto yy410; + goto yy406; + } +yy413: yych = *++YYCURSOR; + goto yy414; +yy414: +#line 475 + { + if (s->act_in_c99_mode) { + --YYCURSOR; + RET(T_COLON); + } + else { + RET(T_COLON_COLON); + } + } +yy415: yych = *++YYCURSOR; + goto yy416; +yy416: +#line 459 + { RET(T_RIGHTBRACKET_ALT); } +yy417: yyaccept = 14; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'h'){ + if(yych <= '$'){ + if(yych <= '\t'){ + if(yych >= '\t') goto yy290; + goto yy418; + } else { + if(yych == ' ') goto yy290; + goto yy418; + } + } else { + if(yych <= '/'){ + if(yych <= '%') goto yy423; + if(yych >= '/') goto yy290; + goto yy418; + } else { + if(yych <= 'c') goto yy418; + if(yych <= 'e') goto yy290; + goto yy418; + } + } + } else { + if(yych <= 'q'){ + if(yych <= 'l'){ + if(yych <= 'i') goto yy290; + if(yych >= 'l') goto yy290; + goto yy418; + } else { + if(yych == 'p') goto yy290; + goto yy418; + } + } else { + if(yych <= 'u'){ + if(yych <= 'r') goto yy290; + if(yych >= 'u') goto yy290; + goto yy418; + } else { + if(yych == 'w') goto yy290; + goto yy418; + } + } + } +yy418: +#line 461 + { RET(T_POUND_ALT); } +yy419: yych = *++YYCURSOR; + goto yy420; +yy420: +#line 520 + { RET(T_PERCENTASSIGN); } +yy421: yych = *++YYCURSOR; + goto yy422; +yy422: +#line 453 + { RET(T_RIGHTBRACE_ALT); } +yy423: yych = *++YYCURSOR; + if(yych != ':') goto yy2; + goto yy424; +yy424: yych = *++YYCURSOR; + goto yy425; +yy425: +#line 467 + { RET(T_POUND_POUND_ALT); } +yy426: yych = *++YYCURSOR; + goto yy427; +yy427: +#line 536 + { RET(T_LESSEQUAL); } +yy428: yych = *++YYCURSOR; + if(yych == '=') goto yy434; + goto yy429; +yy429: +#line 529 + { RET(T_SHIFTLEFT); } +yy430: yych = *++YYCURSOR; + goto yy431; +yy431: +#line 456 + { RET(T_LEFTBRACKET_ALT); } +yy432: yych = *++YYCURSOR; + goto yy433; +yy433: +#line 450 + { RET(T_LEFTBRACE_ALT); } +yy434: yych = *++YYCURSOR; + goto yy435; +yy435: +#line 532 + { RET(T_SHIFTLEFTASSIGN); } +yy436: yych = *++YYCURSOR; + switch(yych){ + case '!': goto yy449; + case '\'': goto yy447; + case '(': goto yy441; + case ')': goto yy443; + case '-': goto yy451; + case '/': goto yy453; + case '<': goto yy437; + case '=': goto yy445; + case '>': goto yy439; + default: goto yy2; + } +yy437: yych = *++YYCURSOR; + goto yy438; +yy438: +#line 449 + { RET(T_LEFTBRACE_TRIGRAPH); } +yy439: yych = *++YYCURSOR; + goto yy440; +yy440: +#line 452 + { RET(T_RIGHTBRACE_TRIGRAPH); } +yy441: yych = *++YYCURSOR; + goto yy442; +yy442: +#line 455 + { RET(T_LEFTBRACKET_TRIGRAPH); } +yy443: yych = *++YYCURSOR; + goto yy444; +yy444: +#line 458 + { RET(T_RIGHTBRACKET_TRIGRAPH); } +yy445: yyaccept = 15; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'e'){ + if(yych <= '#'){ + if(yych <= '\037'){ + if(yych == '\t') goto yy290; + goto yy446; + } else { + if(yych <= ' ') goto yy290; + if(yych >= '#') goto yy465; + goto yy446; + } + } else { + if(yych <= '>'){ + if(yych == '/') goto yy290; + goto yy446; + } else { + if(yych <= '?') goto yy464; + if(yych >= 'd') goto yy290; + goto yy446; + } + } + } else { + if(yych <= 'p'){ + if(yych <= 'k'){ + if(yych == 'i') goto yy290; + goto yy446; + } else { + if(yych <= 'l') goto yy290; + if(yych >= 'p') goto yy290; + goto yy446; + } + } else { + if(yych <= 't'){ + if(yych == 'r') goto yy290; + goto yy446; + } else { + if(yych == 'v') goto yy446; + if(yych <= 'w') goto yy290; + goto yy446; + } + } + } +yy446: +#line 462 + { RET(T_POUND_TRIGRAPH); } +yy447: yych = *++YYCURSOR; + if(yych == '=') goto yy462; + goto yy448; +yy448: +#line 501 + { RET(T_XOR_TRIGRAPH); } +yy449: yyaccept = 16; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '>'){ + if(yych == '=') goto yy457; + goto yy450; + } else { + if(yych <= '?') goto yy454; + if(yych == '|') goto yy455; + goto yy450; + } +yy450: +#line 507 + { RET(T_OR_TRIGRAPH); } +yy451: yych = *++YYCURSOR; + goto yy452; +yy452: +#line 509 + { RET(T_COMPL_TRIGRAPH); } +yy453: yych = *++YYCURSOR; + if(yych == 'U') goto yy210; + if(yych == 'u') goto yy209; + goto yy2; +yy454: yych = *++YYCURSOR; + if(yych == '?') goto yy459; + goto yy2; +yy455: yych = *++YYCURSOR; + goto yy456; +yy456: +#line 541 + { RET(T_OROR); } +yy457: yych = *++YYCURSOR; + goto yy458; +yy458: +#line 528 + { RET(T_ORASSIGN); } +yy459: yych = *++YYCURSOR; + if(yych != '!') goto yy2; + goto yy460; +yy460: yych = *++YYCURSOR; + goto yy461; +yy461: +#line 544 + { RET(T_OROR); } +yy462: yych = *++YYCURSOR; + goto yy463; +yy463: +#line 523 + { RET(T_XORASSIGN); } +yy464: yych = *++YYCURSOR; + if(yych == '?') goto yy467; + goto yy2; +yy465: yych = *++YYCURSOR; + goto yy466; +yy466: +#line 465 + { RET(T_POUND_POUND_TRIGRAPH); } +yy467: yych = *++YYCURSOR; + if(yych != '=') goto yy2; + goto yy468; +yy468: yych = *++YYCURSOR; + goto yy469; +yy469: +#line 466 + { RET(T_POUND_POUND_TRIGRAPH); } +yy470: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + switch(yych){ + case 'a': goto yy471; + case 'b': goto yy472; + case 'c': goto yy473; + case 'd': goto yy474; + case 'e': goto yy523; + case 'f': goto yy521; + case 'i': goto yy520; + case 'l': goto yy524; + case 's': goto yy477; + case 't': goto yy522; + default: goto yy219; + } +yy471: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 's') goto yy517; + goto yy219; +yy472: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'a') goto yy512; + goto yy219; +yy473: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'd') goto yy507; + goto yy219; +yy474: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'e') goto yy499; + goto yy219; +yy475: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'a') goto yy491; + goto yy219; +yy476: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'n') goto yy485; + goto yy219; +yy477: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy478; +yy478: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'd') goto yy219; + goto yy479; +yy479: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy480; +yy480: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy481; +yy481: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy482; +yy482: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy483; +yy483: yyaccept = 17; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy484; + if(yych <= '9') goto yy218; + goto yy484; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy484; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy484; + } else { + if(yych == '`') goto yy484; + if(yych <= 'z') goto yy218; + goto yy484; + } + } +yy484: +#line 440 + { RET(s->enable_ms_extensions ? T_MSEXT_STDCALL : T_IDENTIFIER); } +yy485: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy486; +yy486: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy487; +yy487: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy488; +yy488: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy489; +yy489: yyaccept = 18; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy490; + if(yych <= '9') goto yy218; + goto yy490; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy490; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy490; + } else { + if(yych == '`') goto yy490; + if(yych <= 'z') goto yy218; + goto yy490; + } + } +yy490: +#line 445 + { RET(s->enable_ms_extensions ? T_MSEXT_INLINE : T_IDENTIFIER); } +yy491: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy492; +yy492: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy493; +yy493: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy494; +yy494: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy495; +yy495: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy496; +yy496: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy497; +yy497: yyaccept = 19; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy498; + if(yych <= '9') goto yy218; + goto yy498; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy498; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy498; + } else { + if(yych == '`') goto yy498; + if(yych <= 'z') goto yy218; + goto yy498; + } + } +yy498: +#line 439 + { RET(s->enable_ms_extensions ? T_MSEXT_FASTCALL : T_IDENTIFIER); } +yy499: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy500; +yy500: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy501; +yy501: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy502; +yy502: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'p') goto yy219; + goto yy503; +yy503: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy504; +yy504: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy505; +yy505: yyaccept = 20; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy506; + if(yych <= '9') goto yy218; + goto yy506; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy506; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy506; + } else { + if(yych == '`') goto yy506; + if(yych <= 'z') goto yy218; + goto yy506; + } + } +yy506: +#line 437 + { RET(s->enable_ms_extensions ? T_MSEXT_DECLSPEC : T_IDENTIFIER); } +yy507: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy508; +yy508: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy509; +yy509: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy510; +yy510: yyaccept = 21; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy511; + if(yych <= '9') goto yy218; + goto yy511; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy511; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy511; + } else { + if(yych == '`') goto yy511; + if(yych <= 'z') goto yy218; + goto yy511; + } + } +yy511: +#line 438 + { RET(s->enable_ms_extensions ? T_MSEXT_CDECL : T_IDENTIFIER); } +yy512: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy513; +yy513: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy514; +yy514: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'd') goto yy219; + goto yy515; +yy515: yyaccept = 22; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy516; + if(yych <= '9') goto yy218; + goto yy516; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy516; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy516; + } else { + if(yych == '`') goto yy516; + if(yych <= 'z') goto yy218; + goto yy516; + } + } +yy516: +#line 436 + { RET(s->enable_ms_extensions ? T_MSEXT_BASED : T_IDENTIFIER); } +yy517: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'm') goto yy219; + goto yy518; +yy518: yyaccept = 23; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy519; + if(yych <= '9') goto yy218; + goto yy519; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy519; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy519; + } else { + if(yych == '`') goto yy519; + if(yych <= 'z') goto yy218; + goto yy519; + } + } +yy519: +#line 446 + { RET(s->enable_ms_extensions ? T_MSEXT_ASM : T_IDENTIFIER); } +yy520: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'n') goto yy546; + goto yy219; +yy521: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'a') goto yy491; + if(yych == 'i') goto yy539; + goto yy219; +yy522: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'r') goto yy536; + goto yy219; +yy523: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'x') goto yy530; + goto yy219; +yy524: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy525; +yy525: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy526; +yy526: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'v') goto yy219; + goto yy527; +yy527: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy528; +yy528: yyaccept = 24; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy529; + if(yych <= '9') goto yy218; + goto yy529; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy529; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy529; + } else { + if(yych == '`') goto yy529; + if(yych <= 'z') goto yy218; + goto yy529; + } + } +yy529: +#line 444 + { RET(s->enable_ms_extensions ? T_MSEXT_LEAVE : T_IDENTIFIER); } +yy530: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy531; +yy531: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy532; +yy532: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'p') goto yy219; + goto yy533; +yy533: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy534; +yy534: yyaccept = 25; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy535; + if(yych <= '9') goto yy218; + goto yy535; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy535; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy535; + } else { + if(yych == '`') goto yy535; + if(yych <= 'z') goto yy218; + goto yy535; + } + } +yy535: +#line 442 + { RET(s->enable_ms_extensions ? T_MSEXT_EXCEPT : T_IDENTIFIER); } +yy536: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'y') goto yy219; + goto yy537; +yy537: yyaccept = 26; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy538; + if(yych <= '9') goto yy218; + goto yy538; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy538; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy538; + } else { + if(yych == '`') goto yy538; + if(yych <= 'z') goto yy218; + goto yy538; + } + } +yy538: +#line 441 + { RET(s->enable_ms_extensions ? T_MSEXT_TRY : T_IDENTIFIER); } +yy539: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy540; +yy540: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy541; +yy541: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy542; +yy542: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy543; +yy543: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'y') goto yy219; + goto yy544; +yy544: yyaccept = 27; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy545; + if(yych <= '9') goto yy218; + goto yy545; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy545; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy545; + } else { + if(yych == '`') goto yy545; + if(yych <= 'z') goto yy218; + goto yy545; + } + } +yy545: +#line 443 + { RET(s->enable_ms_extensions ? T_MSEXT_FINALLY : T_IDENTIFIER); } +yy546: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'l') goto yy486; + if(yych != 't') goto yy219; + goto yy547; +yy547: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + switch(yych){ + case '1': goto yy548; + case '3': goto yy549; + case '6': goto yy550; + case '8': goto yy551; + default: goto yy219; + } +yy548: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '6') goto yy557; + goto yy219; +yy549: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '2') goto yy555; + goto yy219; +yy550: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '4') goto yy553; + goto yy219; +yy551: yyaccept = 28; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy552; + if(yych <= '9') goto yy218; + goto yy552; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy552; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy552; + } else { + if(yych == '`') goto yy552; + if(yych <= 'z') goto yy218; + goto yy552; + } + } +yy552: +#line 432 + { RET(s->enable_ms_extensions ? T_MSEXT_INT8 : T_IDENTIFIER); } +yy553: yyaccept = 29; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy554; + if(yych <= '9') goto yy218; + goto yy554; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy554; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy554; + } else { + if(yych == '`') goto yy554; + if(yych <= 'z') goto yy218; + goto yy554; + } + } +yy554: +#line 435 + { RET(s->enable_ms_extensions ? T_MSEXT_INT64 : T_IDENTIFIER); } +yy555: yyaccept = 30; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy556; + if(yych <= '9') goto yy218; + goto yy556; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy556; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy556; + } else { + if(yych == '`') goto yy556; + if(yych <= 'z') goto yy218; + goto yy556; + } + } +yy556: +#line 434 + { RET(s->enable_ms_extensions ? T_MSEXT_INT32 : T_IDENTIFIER); } +yy557: yyaccept = 31; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy558; + if(yych <= '9') goto yy218; + goto yy558; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy558; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy558; + } else { + if(yych == '`') goto yy558; + if(yych <= 'z') goto yy218; + goto yy558; + } + } +yy558: +#line 433 + { RET(s->enable_ms_extensions ? T_MSEXT_INT16 : T_IDENTIFIER); } +yy559: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'h') goto yy565; + goto yy219; +yy560: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy561; +yy561: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy562; +yy562: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy563; +yy563: yyaccept = 32; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy564; + if(yych <= '9') goto yy218; + goto yy564; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy564; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy564; + } else { + if(yych == '`') goto yy564; + if(yych <= 'z') goto yy218; + goto yy564; + } + } +yy564: +#line 430 + { RET(T_WHILE); } +yy565: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy566; +yy566: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy567; +yy567: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != '_') goto yy219; + goto yy568; +yy568: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy569; +yy569: yyaccept = 33; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy570; + if(yych <= '9') goto yy218; + goto yy570; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy570; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy570; + } else { + if(yych == '`') goto yy570; + if(yych <= 'z') goto yy218; + goto yy570; + } + } +yy570: +#line 429 + { RET(T_WCHART); } +yy571: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'r') goto yy583; + goto yy219; +yy572: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'i') goto yy573; + if(yych == 'l') goto yy574; + goto yy219; +yy573: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'd') goto yy581; + goto yy219; +yy574: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy575; +yy575: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy576; +yy576: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy577; +yy577: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy578; +yy578: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy579; +yy579: yyaccept = 34; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy580; + if(yych <= '9') goto yy218; + goto yy580; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy580; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy580; + } else { + if(yych == '`') goto yy580; + if(yych <= 'z') goto yy218; + goto yy580; + } + } +yy580: +#line 428 + { RET(T_VOLATILE); } +yy581: yyaccept = 35; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy582; + if(yych <= '9') goto yy218; + goto yy582; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy582; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy582; + } else { + if(yych == '`') goto yy582; + if(yych <= 'z') goto yy218; + goto yy582; + } + } +yy582: +#line 427 + { RET(T_VOID); } +yy583: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy584; +yy584: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'u') goto yy219; + goto yy585; +yy585: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy586; +yy586: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy587; +yy587: yyaccept = 36; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy588; + if(yych <= '9') goto yy218; + goto yy588; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy588; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy588; + } else { + if(yych == '`') goto yy588; + if(yych <= 'z') goto yy218; + goto yy588; + } + } +yy588: +#line 426 + { RET(T_VIRTUAL); } +yy589: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'i') goto yy595; + if(yych == 's') goto yy596; + goto yy219; +yy590: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy591; +yy591: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy592; +yy592: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'g') goto yy219; + goto yy593; +yy593: yyaccept = 37; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy594; + if(yych <= '9') goto yy218; + goto yy594; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy594; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy594; + } else { + if(yych == '`') goto yy594; + if(yych <= 'z') goto yy218; + goto yy594; + } + } +yy594: +#line 425 + { RET(T_USING); } +yy595: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'o') goto yy603; + goto yy219; +yy596: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy597; +yy597: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'g') goto yy219; + goto yy598; +yy598: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy599; +yy599: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy600; +yy600: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'd') goto yy219; + goto yy601; +yy601: yyaccept = 38; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy602; + if(yych <= '9') goto yy218; + goto yy602; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy602; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy602; + } else { + if(yych == '`') goto yy602; + if(yych <= 'z') goto yy218; + goto yy602; + } + } +yy602: +#line 424 + { RET(T_UNSIGNED); } +yy603: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy604; +yy604: yyaccept = 39; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy605; + if(yych <= '9') goto yy218; + goto yy605; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy605; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy605; + } else { + if(yych == '`') goto yy605; + if(yych <= 'z') goto yy218; + goto yy605; + } + } +yy605: +#line 423 + { RET(T_UNION); } +yy606: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'm') goto yy636; + goto yy219; +yy607: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'i') goto yy629; + if(yych == 'r') goto yy630; + goto yy219; +yy608: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'u') goto yy624; + if(yych == 'y') goto yy625; + goto yy219; +yy609: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'p') goto yy219; + goto yy610; +yy610: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy611; +yy611: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'h'){ + if(yych != 'd') goto yy219; + goto yy612; + } else { + if(yych <= 'i') goto yy613; + if(yych == 'n') goto yy614; + goto yy219; + } +yy612: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'e') goto yy621; + goto yy219; +yy613: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'd') goto yy619; + goto yy219; +yy614: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy615; +yy615: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'm') goto yy219; + goto yy616; +yy616: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy617; +yy617: yyaccept = 40; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy618; + if(yych <= '9') goto yy218; + goto yy618; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy618; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy618; + } else { + if(yych == '`') goto yy618; + if(yych <= 'z') goto yy218; + goto yy618; + } + } +yy618: +#line 422 + { RET(T_TYPENAME); } +yy619: yyaccept = 41; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy620; + if(yych <= '9') goto yy218; + goto yy620; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy620; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy620; + } else { + if(yych == '`') goto yy620; + if(yych <= 'z') goto yy218; + goto yy620; + } + } +yy620: +#line 421 + { RET(T_TYPEID); } +yy621: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'f') goto yy219; + goto yy622; +yy622: yyaccept = 42; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy623; + if(yych <= '9') goto yy218; + goto yy623; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy623; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy623; + } else { + if(yych == '`') goto yy623; + if(yych <= 'z') goto yy218; + goto yy623; + } + } +yy623: +#line 420 + { RET(T_TYPEDEF); } +yy624: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'e') goto yy627; + goto yy219; +yy625: yyaccept = 43; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy626; + if(yych <= '9') goto yy218; + goto yy626; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy626; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy626; + } else { + if(yych == '`') goto yy626; + if(yych <= 'z') goto yy218; + goto yy626; + } + } +yy626: +#line 419 + { RET(T_TRY); } +yy627: yyaccept = 44; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy628; + if(yych <= '9') goto yy218; + goto yy628; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy628; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy628; + } else { + if(yych == '`') goto yy628; + if(yych <= 'z') goto yy218; + goto yy628; + } + } +yy628: +#line 418 + { RET(T_TRUE); } +yy629: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 's') goto yy634; + goto yy219; +yy630: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'o') goto yy219; + goto yy631; +yy631: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'w') goto yy219; + goto yy632; +yy632: yyaccept = 45; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy633; + if(yych <= '9') goto yy218; + goto yy633; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy633; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy633; + } else { + if(yych == '`') goto yy633; + if(yych <= 'z') goto yy218; + goto yy633; + } + } +yy633: +#line 417 + { RET(T_THROW); } +yy634: yyaccept = 46; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy635; + if(yych <= '9') goto yy218; + goto yy635; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy635; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy635; + } else { + if(yych == '`') goto yy635; + if(yych <= 'z') goto yy218; + goto yy635; + } + } +yy635: +#line 416 + { RET(T_THIS); } +yy636: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'p') goto yy219; + goto yy637; +yy637: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy638; +yy638: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy639; +yy639: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy640; +yy640: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy641; +yy641: yyaccept = 47; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy642; + if(yych <= '9') goto yy218; + goto yy642; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy642; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy642; + } else { + if(yych == '`') goto yy642; + if(yych <= 'z') goto yy218; + goto yy642; + } + } +yy642: +#line 415 + { RET(T_TEMPLATE); } +yy643: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'o') goto yy678; + goto yy219; +yy644: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'g') goto yy668; + if(yych == 'z') goto yy669; + goto yy219; +yy645: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'a') goto yy652; + if(yych == 'r') goto yy653; + goto yy219; +yy646: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy647; +yy647: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy648; +yy648: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy649; +yy649: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'h') goto yy219; + goto yy650; +yy650: yyaccept = 48; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy651; + if(yych <= '9') goto yy218; + goto yy651; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy651; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy651; + } else { + if(yych == '`') goto yy651; + if(yych <= 'z') goto yy218; + goto yy651; + } + } +yy651: +#line 414 + { RET(T_SWITCH); } +yy652: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 't') goto yy658; + goto yy219; +yy653: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'u') goto yy219; + goto yy654; +yy654: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy655; +yy655: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy656; +yy656: yyaccept = 49; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy657; + if(yych <= '9') goto yy218; + goto yy657; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy657; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy657; + } else { + if(yych == '`') goto yy657; + if(yych <= 'z') goto yy218; + goto yy657; + } + } +yy657: +#line 413 + { RET(T_STRUCT); } +yy658: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy659; +yy659: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy660; +yy660: yyaccept = 50; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy661; + if(yych <= '9') goto yy218; + goto yy661; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy661; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy661; + } else { + if(yych <= '_') goto yy662; + if(yych <= '`') goto yy661; + if(yych <= 'z') goto yy218; + goto yy661; + } + } +yy661: +#line 411 + { RET(T_STATIC); } +yy662: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy663; +yy663: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy664; +yy664: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy665; +yy665: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy666; +yy666: yyaccept = 51; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy667; + if(yych <= '9') goto yy218; + goto yy667; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy667; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy667; + } else { + if(yych == '`') goto yy667; + if(yych <= 'z') goto yy218; + goto yy667; + } + } +yy667: +#line 412 + { RET(T_STATICCAST); } +yy668: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'n') goto yy674; + goto yy219; +yy669: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy670; +yy670: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'o') goto yy219; + goto yy671; +yy671: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'f') goto yy219; + goto yy672; +yy672: yyaccept = 52; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy673; + if(yych <= '9') goto yy218; + goto yy673; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy673; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy673; + } else { + if(yych == '`') goto yy673; + if(yych <= 'z') goto yy218; + goto yy673; + } + } +yy673: +#line 410 + { RET(T_SIZEOF); } +yy674: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy675; +yy675: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'd') goto yy219; + goto yy676; +yy676: yyaccept = 53; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy677; + if(yych <= '9') goto yy218; + goto yy677; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy677; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy677; + } else { + if(yych == '`') goto yy677; + if(yych <= 'z') goto yy218; + goto yy677; + } + } +yy677: +#line 409 + { RET(T_SIGNED); } +yy678: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy679; +yy679: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy680; +yy680: yyaccept = 54; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy681; + if(yych <= '9') goto yy218; + goto yy681; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy681; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy681; + } else { + if(yych == '`') goto yy681; + if(yych <= 'z') goto yy218; + goto yy681; + } + } +yy681: +#line 408 + { RET(T_SHORT); } +yy682: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'h'){ + if(yych != 'g') goto yy219; + goto yy683; + } else { + if(yych <= 'i') goto yy684; + if(yych == 't') goto yy685; + goto yy219; + } +yy683: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'i') goto yy704; + goto yy219; +yy684: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'n') goto yy690; + goto yy219; +yy685: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'u') goto yy219; + goto yy686; +yy686: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy687; +yy687: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy688; +yy688: yyaccept = 55; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy689; + if(yych <= '9') goto yy218; + goto yy689; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy689; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy689; + } else { + if(yych == '`') goto yy689; + if(yych <= 'z') goto yy218; + goto yy689; + } + } +yy689: +#line 407 + { RET(T_RETURN); } +yy690: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy691; +yy691: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy692; +yy692: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy693; +yy693: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'p') goto yy219; + goto yy694; +yy694: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy695; +yy695: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy696; +yy696: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy697; +yy697: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != '_') goto yy219; + goto yy698; +yy698: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy699; +yy699: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy700; +yy700: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy701; +yy701: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy702; +yy702: yyaccept = 56; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy703; + if(yych <= '9') goto yy218; + goto yy703; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy703; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy703; + } else { + if(yych == '`') goto yy703; + if(yych <= 'z') goto yy218; + goto yy703; + } + } +yy703: +#line 406 + { RET(T_REINTERPRETCAST); } +yy704: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy705; +yy705: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy706; +yy706: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy707; +yy707: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy708; +yy708: yyaccept = 57; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy709; + if(yych <= '9') goto yy218; + goto yy709; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy709; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy709; + } else { + if(yych == '`') goto yy709; + if(yych <= 'z') goto yy218; + goto yy709; + } + } +yy709: +#line 405 + { RET(T_REGISTER); } +yy710: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'i') goto yy717; + if(yych == 'o') goto yy718; + goto yy219; +yy711: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'b') goto yy219; + goto yy712; +yy712: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy713; +yy713: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy714; +yy714: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy715; +yy715: yyaccept = 58; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy716; + if(yych <= '9') goto yy218; + goto yy716; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy716; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy716; + } else { + if(yych == '`') goto yy716; + if(yych <= 'z') goto yy218; + goto yy716; + } + } +yy716: +#line 404 + { RET(T_PUBLIC); } +yy717: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'v') goto yy726; + goto yy219; +yy718: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy719; +yy719: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy720; +yy720: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy721; +yy721: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy722; +yy722: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy723; +yy723: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'd') goto yy219; + goto yy724; +yy724: yyaccept = 59; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy725; + if(yych <= '9') goto yy218; + goto yy725; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy725; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy725; + } else { + if(yych == '`') goto yy725; + if(yych <= 'z') goto yy218; + goto yy725; + } + } +yy725: +#line 403 + { RET(T_PROTECTED); } +yy726: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy727; +yy727: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy728; +yy728: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy729; +yy729: yyaccept = 60; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy730; + if(yych <= '9') goto yy218; + goto yy730; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy730; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy730; + } else { + if(yych == '`') goto yy730; + if(yych <= 'z') goto yy218; + goto yy730; + } + } +yy730: +#line 402 + { RET(T_PRIVATE); } +yy731: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'e') goto yy738; + goto yy219; +yy732: yyaccept = 61; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy733; + if(yych <= '9') goto yy218; + goto yy733; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy733; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy733; + } else { + if(yych <= '_') goto yy734; + if(yych <= '`') goto yy733; + if(yych <= 'z') goto yy218; + goto yy733; + } + } +yy733: +#line 543 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_OROR_ALT); } +yy734: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy735; +yy735: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'q') goto yy219; + goto yy736; +yy736: yyaccept = 62; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy737; + if(yych <= '9') goto yy218; + goto yy737; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy737; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy737; + } else { + if(yych == '`') goto yy737; + if(yych <= 'z') goto yy218; + goto yy737; + } + } +yy737: +#line 527 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ORASSIGN_ALT); } +yy738: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy739; +yy739: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy740; +yy740: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy741; +yy741: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'o') goto yy219; + goto yy742; +yy742: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy743; +yy743: yyaccept = 63; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy744; + if(yych <= '9') goto yy218; + goto yy744; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy744; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy744; + } else { + if(yych == '`') goto yy744; + if(yych <= 'z') goto yy218; + goto yy744; + } + } +yy744: +#line 401 + { RET(T_OPERATOR); } +yy745: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'm') goto yy756; + goto yy219; +yy746: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'w') goto yy754; + goto yy219; +yy747: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy748; +yy748: yyaccept = 64; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy749; + if(yych <= '9') goto yy218; + goto yy749; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy749; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy749; + } else { + if(yych <= '_') goto yy750; + if(yych <= '`') goto yy749; + if(yych <= 'z') goto yy218; + goto yy749; + } + } +yy749: +#line 512 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_NOT_ALT); } +yy750: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy751; +yy751: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'q') goto yy219; + goto yy752; +yy752: yyaccept = 65; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy753; + if(yych <= '9') goto yy218; + goto yy753; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy753; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy753; + } else { + if(yych == '`') goto yy753; + if(yych <= 'z') goto yy218; + goto yy753; + } + } +yy753: +#line 535 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_NOTEQUAL_ALT); } +yy754: yyaccept = 66; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy755; + if(yych <= '9') goto yy218; + goto yy755; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy755; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy755; + } else { + if(yych == '`') goto yy755; + if(yych <= 'z') goto yy218; + goto yy755; + } + } +yy755: +#line 400 + { RET(T_NEW); } +yy756: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy757; +yy757: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy758; +yy758: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'p') goto yy219; + goto yy759; +yy759: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy760; +yy760: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy761; +yy761: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy762; +yy762: yyaccept = 67; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy763; + if(yych <= '9') goto yy218; + goto yy763; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy763; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy763; + } else { + if(yych == '`') goto yy763; + if(yych <= 'z') goto yy218; + goto yy763; + } + } +yy763: +#line 399 + { RET(T_NAMESPACE); } +yy764: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy765; +yy765: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy766; +yy766: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'b') goto yy219; + goto yy767; +yy767: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy768; +yy768: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy769; +yy769: yyaccept = 68; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy770; + if(yych <= '9') goto yy218; + goto yy770; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy770; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy770; + } else { + if(yych == '`') goto yy770; + if(yych <= 'z') goto yy218; + goto yy770; + } + } +yy770: +#line 398 + { RET(T_MUTABLE); } +yy771: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy772; +yy772: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'g') goto yy219; + goto yy773; +yy773: yyaccept = 69; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy774; + if(yych <= '9') goto yy218; + goto yy774; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy774; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy774; + } else { + if(yych == '`') goto yy774; + if(yych <= 'z') goto yy218; + goto yy774; + } + } +yy774: +#line 397 + { RET(T_LONG); } +yy775: yyaccept = 70; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy776; + if(yych <= '9') goto yy218; + goto yy776; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy776; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy776; + } else { + if(yych == '`') goto yy776; + if(yych <= 'z') goto yy218; + goto yy776; + } + } +yy776: +#line 394 + { RET(T_IF); } +yy777: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'l') goto yy778; + if(yych == 't') goto yy779; + goto yy219; +yy778: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'i') goto yy781; + goto yy219; +yy779: yyaccept = 71; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy780; + if(yych <= '9') goto yy218; + goto yy780; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy780; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy780; + } else { + if(yych == '`') goto yy780; + if(yych <= 'z') goto yy218; + goto yy780; + } + } +yy780: +#line 396 + { RET(T_INT); } +yy781: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy782; +yy782: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy783; +yy783: yyaccept = 72; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy784; + if(yych <= '9') goto yy218; + goto yy784; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy784; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy784; + } else { + if(yych == '`') goto yy784; + if(yych <= 'z') goto yy218; + goto yy784; + } + } +yy784: +#line 395 + { RET(T_INLINE); } +yy785: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy786; +yy786: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'o') goto yy219; + goto yy787; +yy787: yyaccept = 73; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy788; + if(yych <= '9') goto yy218; + goto yy788; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy788; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy788; + } else { + if(yych == '`') goto yy788; + if(yych <= 'z') goto yy218; + goto yy788; + } + } +yy788: +#line 393 + { RET(T_GOTO); } +yy789: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'l') goto yy804; + goto yy219; +yy790: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'o') goto yy800; + goto yy219; +yy791: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'r') goto yy798; + goto yy219; +yy792: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy793; +yy793: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy794; +yy794: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy795; +yy795: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'd') goto yy219; + goto yy796; +yy796: yyaccept = 74; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy797; + if(yych <= '9') goto yy218; + goto yy797; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy797; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy797; + } else { + if(yych == '`') goto yy797; + if(yych <= 'z') goto yy218; + goto yy797; + } + } +yy797: +#line 392 + { RET(T_FRIEND); } +yy798: yyaccept = 75; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy799; + if(yych <= '9') goto yy218; + goto yy799; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy799; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy799; + } else { + if(yych == '`') goto yy799; + if(yych <= 'z') goto yy218; + goto yy799; + } + } +yy799: +#line 391 + { RET(T_FOR); } +yy800: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy801; +yy801: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy802; +yy802: yyaccept = 76; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy803; + if(yych <= '9') goto yy218; + goto yy803; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy803; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy803; + } else { + if(yych == '`') goto yy803; + if(yych <= 'z') goto yy218; + goto yy803; + } + } +yy803: +#line 390 + { RET(T_FLOAT); } +yy804: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy805; +yy805: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy806; +yy806: yyaccept = 77; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy807; + if(yych <= '9') goto yy218; + goto yy807; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy807; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy807; + } else { + if(yych == '`') goto yy807; + if(yych <= 'z') goto yy218; + goto yy807; + } + } +yy807: +#line 389 + { RET(T_FALSE); } +yy808: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 's') goto yy830; + goto yy219; +yy809: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'u') goto yy827; + goto yy219; +yy810: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'p') goto yy811; + if(yych == 't') goto yy812; + goto yy219; +yy811: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'l') goto yy817; + if(yych == 'o') goto yy818; + goto yy219; +yy812: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy813; +yy813: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy814; +yy814: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy815; +yy815: yyaccept = 78; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy816; + if(yych <= '9') goto yy218; + goto yy816; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy816; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy816; + } else { + if(yych == '`') goto yy816; + if(yych <= 'z') goto yy218; + goto yy816; + } + } +yy816: +#line 388 + { RET(T_EXTERN); } +yy817: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'i') goto yy822; + goto yy219; +yy818: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy819; +yy819: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy820; +yy820: yyaccept = 79; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy821; + if(yych <= '9') goto yy218; + goto yy821; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy821; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy821; + } else { + if(yych == '`') goto yy821; + if(yych <= 'z') goto yy218; + goto yy821; + } + } +yy821: +#line 387 + { RET(T_EXPORT); } +yy822: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy823; +yy823: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy824; +yy824: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy825; +yy825: yyaccept = 80; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy826; + if(yych <= '9') goto yy218; + goto yy826; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy826; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy826; + } else { + if(yych == '`') goto yy826; + if(yych <= 'z') goto yy218; + goto yy826; + } + } +yy826: +#line 386 + { RET(T_EXPLICIT); } +yy827: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'm') goto yy219; + goto yy828; +yy828: yyaccept = 81; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy829; + if(yych <= '9') goto yy218; + goto yy829; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy829; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy829; + } else { + if(yych == '`') goto yy829; + if(yych <= 'z') goto yy218; + goto yy829; + } + } +yy829: +#line 385 + { RET(T_ENUM); } +yy830: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy831; +yy831: yyaccept = 82; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy832; + if(yych <= '9') goto yy218; + goto yy832; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy832; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy832; + } else { + if(yych == '`') goto yy832; + if(yych <= 'z') goto yy218; + goto yy832; + } + } +yy832: +#line 384 + { RET(T_ELSE); } +yy833: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'f') goto yy853; + if(yych == 'l') goto yy854; + goto yy219; +yy834: yyaccept = 83; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '['){ + if(yych <= '>'){ + if(yych <= '/') goto yy835; + if(yych <= '9') goto yy218; + goto yy835; + } else { + if(yych <= '?') goto yy221; + if(yych <= '@') goto yy835; + if(yych <= 'Z') goto yy218; + goto yy835; + } + } else { + if(yych <= '`'){ + if(yych <= '\\') goto yy220; + if(yych == '_') goto yy218; + goto yy835; + } else { + if(yych == 'u') goto yy848; + if(yych <= 'z') goto yy218; + goto yy835; + } + } +yy835: +#line 381 + { RET(T_DO); } +yy836: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy837; +yy837: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy838; +yy838: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'm') goto yy219; + goto yy839; +yy839: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy840; +yy840: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy841; +yy841: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != '_') goto yy219; + goto yy842; +yy842: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy843; +yy843: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy844; +yy844: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy845; +yy845: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy846; +yy846: yyaccept = 84; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy847; + if(yych <= '9') goto yy218; + goto yy847; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy847; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy847; + } else { + if(yych == '`') goto yy847; + if(yych <= 'z') goto yy218; + goto yy847; + } + } +yy847: +#line 383 + { RET(T_DYNAMICCAST); } +yy848: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'b') goto yy219; + goto yy849; +yy849: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy850; +yy850: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy851; +yy851: yyaccept = 85; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy852; + if(yych <= '9') goto yy218; + goto yy852; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy852; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy852; + } else { + if(yych == '`') goto yy852; + if(yych <= 'z') goto yy218; + goto yy852; + } + } +yy852: +#line 382 + { RET(T_DOUBLE); } +yy853: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'a') goto yy859; + goto yy219; +yy854: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy855; +yy855: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy856; +yy856: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy857; +yy857: yyaccept = 86; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy858; + if(yych <= '9') goto yy218; + goto yy858; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy858; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy858; + } else { + if(yych == '`') goto yy858; + if(yych <= 'z') goto yy218; + goto yy858; + } + } +yy858: +#line 380 + { RET(T_DELETE); } +yy859: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'u') goto yy219; + goto yy860; +yy860: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy861; +yy861: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy862; +yy862: yyaccept = 87; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy863; + if(yych <= '9') goto yy218; + goto yy863; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy863; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy863; + } else { + if(yych == '`') goto yy863; + if(yych <= 'z') goto yy218; + goto yy863; + } + } +yy863: +#line 379 + { RET(T_DEFAULT); } +yy864: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'r') goto yy219; + if(yych <= 's') goto yy895; + if(yych <= 't') goto yy896; + goto yy219; +yy865: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'a') goto yy892; + goto yy219; +yy866: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'a') goto yy888; + goto yy219; +yy867: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'l') goto yy219; + if(yych <= 'm') goto yy869; + if(yych >= 'o') goto yy219; + goto yy868; +yy868: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'r') goto yy219; + if(yych <= 's') goto yy873; + if(yych <= 't') goto yy874; + goto yy219; +yy869: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'p') goto yy219; + goto yy870; +yy870: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy871; +yy871: yyaccept = 88; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy872; + if(yych <= '9') goto yy218; + goto yy872; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy872; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy872; + } else { + if(yych == '`') goto yy872; + if(yych <= 'z') goto yy218; + goto yy872; + } + } +yy872: +#line 510 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_COMPL_ALT); } +yy873: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 't') goto yy880; + goto yy219; +yy874: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'i') goto yy219; + goto yy875; +yy875: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'n') goto yy219; + goto yy876; +yy876: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'u') goto yy219; + goto yy877; +yy877: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy878; +yy878: yyaccept = 89; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy879; + if(yych <= '9') goto yy218; + goto yy879; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy879; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy879; + } else { + if(yych == '`') goto yy879; + if(yych <= 'z') goto yy218; + goto yy879; + } + } +yy879: +#line 378 + { RET(T_CONTINUE); } +yy880: yyaccept = 90; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy881; + if(yych <= '9') goto yy218; + goto yy881; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy881; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy881; + } else { + if(yych <= '_') goto yy882; + if(yych <= '`') goto yy881; + if(yych <= 'z') goto yy218; + goto yy881; + } + } +yy881: +#line 376 + { RET(T_CONST); } +yy882: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy883; +yy883: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy884; +yy884: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy885; +yy885: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy886; +yy886: yyaccept = 91; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy887; + if(yych <= '9') goto yy218; + goto yy887; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy887; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy887; + } else { + if(yych == '`') goto yy887; + if(yych <= 'z') goto yy218; + goto yy887; + } + } +yy887: +#line 377 + { RET(T_CONSTCAST); } +yy888: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy889; +yy889: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 's') goto yy219; + goto yy890; +yy890: yyaccept = 92; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy891; + if(yych <= '9') goto yy218; + goto yy891; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy891; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy891; + } else { + if(yych == '`') goto yy891; + if(yych <= 'z') goto yy218; + goto yy891; + } + } +yy891: +#line 375 + { RET(T_CLASS); } +yy892: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy893; +yy893: yyaccept = 93; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy894; + if(yych <= '9') goto yy218; + goto yy894; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy894; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy894; + } else { + if(yych == '`') goto yy894; + if(yych <= 'z') goto yy218; + goto yy894; + } + } +yy894: +#line 374 + { RET(T_CHAR); } +yy895: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'e') goto yy900; + goto yy219; +yy896: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'c') goto yy219; + goto yy897; +yy897: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'h') goto yy219; + goto yy898; +yy898: yyaccept = 94; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy899; + if(yych <= '9') goto yy218; + goto yy899; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy899; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy899; + } else { + if(yych == '`') goto yy899; + if(yych <= 'z') goto yy218; + goto yy899; + } + } +yy899: +#line 373 + { RET(T_CATCH); } +yy900: yyaccept = 95; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy901; + if(yych <= '9') goto yy218; + goto yy901; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy901; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy901; + } else { + if(yych == '`') goto yy901; + if(yych <= 'z') goto yy218; + goto yy901; + } + } +yy901: +#line 372 + { RET(T_CASE); } +yy902: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 't') goto yy912; + goto yy219; +yy903: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'o') goto yy909; + goto yy219; +yy904: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy905; +yy905: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'a') goto yy219; + goto yy906; +yy906: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'k') goto yy219; + goto yy907; +yy907: yyaccept = 96; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy908; + if(yych <= '9') goto yy218; + goto yy908; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy908; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy908; + } else { + if(yych == '`') goto yy908; + if(yych <= 'z') goto yy218; + goto yy908; + } + } +yy908: +#line 371 + { RET(T_BREAK); } +yy909: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'l') goto yy219; + goto yy910; +yy910: yyaccept = 97; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy911; + if(yych <= '9') goto yy218; + goto yy911; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy911; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy911; + } else { + if(yych == '`') goto yy911; + if(yych <= 'z') goto yy218; + goto yy911; + } + } +yy911: +#line 370 + { RET(T_BOOL); } +yy912: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'a') goto yy913; + if(yych == 'o') goto yy914; + goto yy219; +yy913: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'n') goto yy917; + goto yy219; +yy914: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'r') goto yy219; + goto yy915; +yy915: yyaccept = 98; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy916; + if(yych <= '9') goto yy218; + goto yy916; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy916; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy916; + } else { + if(yych == '`') goto yy916; + if(yych <= 'z') goto yy218; + goto yy916; + } + } +yy916: +#line 506 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_OR_ALT); } +yy917: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'd') goto yy219; + goto yy918; +yy918: yyaccept = 99; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy919; + if(yych <= '9') goto yy218; + goto yy919; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy919; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy919; + } else { + if(yych == '`') goto yy919; + if(yych <= 'z') goto yy218; + goto yy919; + } + } +yy919: +#line 504 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_AND_ALT); } +yy920: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'd') goto yy928; + goto yy219; +yy921: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == 'm') goto yy926; + goto yy219; +yy922: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 't') goto yy219; + goto yy923; +yy923: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'o') goto yy219; + goto yy924; +yy924: yyaccept = 100; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy925; + if(yych <= '9') goto yy218; + goto yy925; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy925; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy925; + } else { + if(yych == '`') goto yy925; + if(yych <= 'z') goto yy218; + goto yy925; + } + } +yy925: +#line 369 + { RET(T_AUTO); } +yy926: yyaccept = 101; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy927; + if(yych <= '9') goto yy218; + goto yy927; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy927; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy927; + } else { + if(yych == '`') goto yy927; + if(yych <= 'z') goto yy218; + goto yy927; + } + } +yy927: +#line 368 + { RET(T_ASM); } +yy928: yyaccept = 102; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy929; + if(yych <= '9') goto yy218; + goto yy929; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy929; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy929; + } else { + if(yych <= '_') goto yy930; + if(yych <= '`') goto yy929; + if(yych <= 'z') goto yy218; + goto yy929; + } + } +yy929: +#line 539 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ANDAND_ALT); } +yy930: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'e') goto yy219; + goto yy931; +yy931: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != 'q') goto yy219; + goto yy932; +yy932: yyaccept = 103; + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= 'Z'){ + if(yych <= '>'){ + if(yych <= '/') goto yy933; + if(yych <= '9') goto yy218; + goto yy933; + } else { + if(yych <= '?') goto yy221; + if(yych >= 'A') goto yy218; + goto yy933; + } + } else { + if(yych <= '^'){ + if(yych == '\\') goto yy220; + goto yy933; + } else { + if(yych == '`') goto yy933; + if(yych <= 'z') goto yy218; + goto yy933; + } + } +yy933: +#line 525 + { RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ANDASSIGN_ALT); } +yy934: yych = *++YYCURSOR; + goto yy935; +yy935: +#line 519 + { RET(T_DIVIDEASSIGN); } +yy936: yych = *++YYCURSOR; + goto yy937; +yy937: +#line 366 + { goto cppcomment; } +yy938: yych = *++YYCURSOR; + goto yy939; +yy939: +#line 365 + { goto ccomment; } +} +#line 632 + + +ccomment: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy940; +yy941: ++YYCURSOR; +yy940: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '\f'){ + if(yych <= '\b'){ + if(yych <= '\000') goto yy949; + goto yy942; + } else { + if(yych == '\n') goto yy945; + goto yy948; + } + } else { + if(yych <= '\037'){ + if(yych <= '\r') goto yy947; + goto yy942; + } else { + if(yych == '*') goto yy943; + goto yy948; + } + } +yy942:yy943: yych = *++YYCURSOR; + if(yych == '/') goto yy952; + goto yy944; +yy944: +#line 646 + { goto ccomment; } +yy945: yych = *++YYCURSOR; + goto yy946; +yy946: +#line 639 + { + /*if(cursor == s->eof) RET(T_EOF);*/ + /*s->tok = cursor; */ + s->line += count_backslash_newlines(s, cursor) +1; + goto ccomment; + } +yy947: yych = *++YYCURSOR; + if(yych == '\n') goto yy951; + goto yy946; +yy948: yych = *++YYCURSOR; + goto yy944; +yy949: yych = *++YYCURSOR; + goto yy950; +yy950: +#line 649 + { + yyaccept = 0; /* avoid warning about unreferenced variable */ + if(cursor == s->eof) + { + if (s->error_proc) + (*s->error_proc)(s, "Unterminated comment"); + else + printf("Error: Unterminated comment\n"); + } + else + { + if (s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file"); + } + /* adjust cursor such next call returns T_EOF */ + --YYCURSOR; + /* the comment is unterminated, but nevertheless its a comment */ + RET(T_CCOMMENT); + } +yy951: yych = *++YYCURSOR; + goto yy946; +yy952: yych = *++YYCURSOR; + goto yy953; +yy953: +#line 636 + { RET(T_CCOMMENT); } +} +#line 671 + + +cppcomment: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy954; +yy955: ++YYCURSOR; +yy954: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '\n'){ + if(yych <= '\000') goto yy962; + if(yych <= '\b') goto yy956; + if(yych <= '\t') goto yy960; + goto yy957; + } else { + if(yych <= '\f') goto yy960; + if(yych <= '\r') goto yy959; + if(yych >= ' ') goto yy960; + goto yy956; + } +yy956:yy957: yych = *++YYCURSOR; + goto yy958; +yy958: +#line 676 + { + /*if(cursor == s->eof) RET(T_EOF); */ + /*s->tok = cursor; */ + s->line++; + RET(T_CPPCOMMENT); + } +yy959: yych = *++YYCURSOR; + if(yych == '\n') goto yy964; + goto yy958; +yy960: yych = *++YYCURSOR; + goto yy961; +yy961: +#line 683 + { goto cppcomment; } +yy962: yych = *++YYCURSOR; + goto yy963; +yy963: +#line 686 + { + yyaccept = 0; /* avoid warning about unreferenced variable */ + if(cursor != s->eof) + { + if (s->error_proc) + (*s->error_proc)(s, "'\\000' in input stream"); + else + printf("Error: 0 in file"); + } + /* adjust cursor such next call returns T_EOF */ + --YYCURSOR; + /* the comment is unterminated, but nevertheless its a comment */ + RET(T_CPPCOMMENT); + } +yy964: yych = *++YYCURSOR; + goto yy958; +} +#line 700 + + +} /* end of scan */ + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#undef RET +#undef BSIZE +#undef YYCTYPE +#undef YYCURSOR +#undef YYLIMIT +#undef YYMARKER +#undef YYFILL + diff --git a/src/instantiate_cpp_exprgrammar.cpp b/src/instantiate_cpp_exprgrammar.cpp new file mode 100644 index 000000000..2d7d49062 --- /dev/null +++ b/src/instantiate_cpp_exprgrammar.cpp @@ -0,0 +1,36 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include +#include + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the expression_grammar_gen template with the +// correct lexer iterator type. This instantiates the corresponding parse +// function, which in turn instantiates the expression_grammar object (see +// wave/grammars/cpp_expression_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpplexer::lex_token<> token_type; + +template struct boost::wave::grammars::expression_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/src/instantiate_cpp_grammar.cpp b/src/instantiate_cpp_grammar.cpp new file mode 100644 index 000000000..d7a3a15d2 --- /dev/null +++ b/src/instantiate_cpp_grammar.cpp @@ -0,0 +1,36 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the cpp_grammar_gen template with the correct +// token type. This instantiates the corresponding pt_parse function, which +// in turn instantiates the cpp_grammar object +// (see wave/grammars/cpp_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpplexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lexer_type; +template struct boost::wave::grammars::cpp_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/src/instantiate_cpp_literalgrammars.cpp b/src/instantiate_cpp_literalgrammars.cpp new file mode 100644 index 000000000..2e7fa433c --- /dev/null +++ b/src/instantiate_cpp_literalgrammars.cpp @@ -0,0 +1,37 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the intlit_grammar_gen and chlit_grammar_gen +// templates with the correct token type. This instantiates the corresponding +// parse function, which in turn instantiates the corresponding parser object. +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpplexer::lex_token<> token_type; + +template struct boost::wave::grammars::intlit_grammar_gen; +template struct boost::wave::grammars::chlit_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/src/instantiate_defined_grammar.cpp b/src/instantiate_defined_grammar.cpp new file mode 100644 index 000000000..71a4b8557 --- /dev/null +++ b/src/instantiate_defined_grammar.cpp @@ -0,0 +1,36 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the defined_grammar_gen template +// with the correct token type. This instantiates the corresponding parse +// function, which in turn instantiates the defined_grammar +// object (see wave/grammars/cpp_defined_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpplexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lexer_type; +template struct boost::wave::grammars::defined_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/src/instantiate_predef_macros.cpp b/src/instantiate_predef_macros.cpp new file mode 100644 index 000000000..dab8fbbe9 --- /dev/null +++ b/src/instantiate_predef_macros.cpp @@ -0,0 +1,36 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the predefined_macros_grammar_gen template +// with the correct token type. This instantiates the corresponding pt_parse +// function, which in turn instantiates the cpp_predefined_macros_grammar +// object (see wave/grammars/cpp_predef_macros_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpplexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lexer_type; +template struct boost::wave::grammars::predefined_macros_grammar_gen; + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/src/instantiate_re2c_lexer.cpp b/src/instantiate_re2c_lexer.cpp new file mode 100644 index 000000000..aaef94ebd --- /dev/null +++ b/src/instantiate_re2c_lexer.cpp @@ -0,0 +1,47 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + Explicit instantiation of the lex_functor generation function + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include // configuration data + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// This instantiates the correct 'new_lexer' function, which generates the +// C++ lexer used in this sample. You will have to instantiate the +// new_lexer_gen<> template with the same iterator type, as you have used for +// instantiating the boost::wave::context<> object. +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the first +// parameter supplied while instantiating the boost::wave::context<> template +// (see the file cpp.cpp). +// +/////////////////////////////////////////////////////////////////////////////// + +template struct boost::wave::cpplexer::new_lexer_gen< + BOOST_WAVE_STRINGTYPE::iterator>; + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/src/instantiate_re2c_lexer_string.cpp b/src/instantiate_re2c_lexer_string.cpp new file mode 100644 index 000000000..5c47ce6a4 --- /dev/null +++ b/src/instantiate_re2c_lexer_string.cpp @@ -0,0 +1,47 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + Explicit instantiation of the lex_functor generation function + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include // configuration data + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// If you've used another iterator type as std::string::iterator, you have to +// instantiate the new_lexer_gen<> template for this iterator type too. +// The reason is, that the library internally uses the new_lexer_gen<> +// template with a std::string::iterator. (You just have to undefine the +// following line.) +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the first +// parameter supplied while instantiating the boost::wave::context<> template +// (see the file cpp.cpp). +// +/////////////////////////////////////////////////////////////////////////////// + +template struct boost::wave::cpplexer::new_lexer_gen; + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/tool/build/Jamfile b/tool/build/Jamfile new file mode 100644 index 000000000..9ba4c9cb4 --- /dev/null +++ b/tool/build/Jamfile @@ -0,0 +1,26 @@ +# Wave: A Standard compliant C++ preprocessor +# +# Boost Wave Library Build Jamfile +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +subproject tools/wave/build ; + +exe wave + : ../cpp.cpp + ../../../libs/wave/build/boost_wave + ../../../libs/program_options/build/boost_program_options + ../../../libs/filesystem/build/boost_filesystem + : + $(BOOST_ROOT) + <*>off # workaround for compiler bug + : + release + static + single + ; + diff --git a/tool/build/Jamfile.v2 b/tool/build/Jamfile.v2 new file mode 100644 index 000000000..65a9f2ac8 --- /dev/null +++ b/tool/build/Jamfile.v2 @@ -0,0 +1,23 @@ +# Wave: A Standard compliant C++ preprocessor +# +# Boost Wave Library Build Jamfile +# +# http://spirit.sourceforge.net/ +# +# Copyright (c) 2001-2005 Hartmut Kaiser. 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) + +exe wave + : ../cpp.cpp + ../../../libs/wave/build//boost_wave + ../../../libs/program_options/build//boost_program_options + ../../../libs/filesystem/build//boost_filesystem + : + msvc-7.1:off # workaround for compiler bug + : + release + static + single + ; + diff --git a/tool/cpp.cpp b/tool/cpp.cpp new file mode 100644 index 000000000..a7c4ac586 --- /dev/null +++ b/tool/cpp.cpp @@ -0,0 +1,664 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#include "cpp.hpp" // global configuration + +/////////////////////////////////////////////////////////////////////////////// +// Include additional Boost libraries +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include Wave itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// Include the lexer related stuff +#include // token type +#include // lexer type + +/////////////////////////////////////////////////////////////////////////////// +// Include the context trace policies to use +#include "trace_macro_expansion.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// include lexer specifics, import lexer names +// +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0 +#include +#endif + +/////////////////////////////////////////////////////////////////////////////// +// include the grammar definitions, if these shouldn't be compiled separately +// (ATTENTION: _very_ large compilation times!) +// +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION == 0 +#include +#include +#include +#include +#include +#include +#endif + +/////////////////////////////////////////////////////////////////////////////// +// import required names +using namespace boost::spirit; + +using std::string; +using std::pair; +using std::vector; +using std::getline; +using std::ifstream; +using std::cout; +using std::cerr; +using std::endl; +using std::ostream; +using std::istreambuf_iterator; + +namespace po = boost::program_options; +namespace fs = boost::filesystem; + +/////////////////////////////////////////////////////////////////////////////// +// print the current version +int print_version() +{ + typedef boost::wave::cpplexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lex_iterator_type; + typedef boost::wave::context< + std::string::iterator, lex_iterator_type, + boost::wave::iteration_context_policies::load_file_to_string, + trace_macro_expansion> + context_type; + + string version (context_type::get_version_string()); + cout + << version.substr(1, version.size()-2) // strip quotes + << " (" << CPP_VERSION_DATE << ")" // add date + << endl; + return 0; // exit app +} + +/////////////////////////////////////////////////////////////////////////////// +// print the copyright statement +int print_copyright() +{ + char const *copyright[] = { + "", + "Wave: A Standard conformant C++ preprocessor", + "It is hosted by http://spirit.sourceforge.net/.", + "", + "Copyright (c) 2001-2005 Hartmut Kaiser, 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)", + 0 + }; + + for (int i = 0; 0 != copyright[i]; ++i) + cout << copyright[i] << endl; + + return 0; // exit app +} + +/////////////////////////////////////////////////////////////////////////////// +namespace cmd_line_util { + + // Additional command line parser which interprets '@something' as an + // option "config-file" with the value "something". + pair at_option_parser(string const&s) + { + if ('@' == s[0]) + return std::make_pair(string("config-file"), s.substr(1)); + else + return pair(); + } + + // class, which keeps include file information read from the command line + class include_paths { + public: + include_paths() : seen_separator(false) {} + + vector paths; // stores user paths + vector syspaths; // stores system paths + bool seen_separator; // command line contains a '-I-' option + + // Function which validates additional tokens from command line. + static void + validate(boost::any &v, vector const &tokens) + { + if (v.empty()) + v = boost::any(include_paths()); + + include_paths *p = boost::any_cast(&v); + + BOOST_SPIRIT_ASSERT(p); + // Assume only one path per '-I' occurrence. + string t = tokens[0]; + if (t == "-") { + // found -I- option, so switch behaviour + p->seen_separator = true; + } + else if (p->seen_separator) { + // store this path as a system path + p->syspaths.push_back(t); + } + else { + // store this path as an user path + p->paths.push_back(t); + } + } + }; + + // Read all options from a given config file, parse and add them to the + // given variables_map + void read_config_file_options(string const &filename, + po::options_description const &desc, po::variables_map &vm, + bool may_fail = false) + { + ifstream ifs(filename.c_str()); + + if (!ifs.is_open()) { + if (!may_fail) { + cerr << filename + << ": command line warning: config file not found" + << endl; + } + return; + } + + vector options; + string line; + + while (std::getline(ifs, line)) { + // skip empty lines + string::size_type pos = line.find_first_not_of(" \t"); + if (pos == string::npos) + continue; + + // skip comment lines + if ('#' != line[pos]) + options.push_back(line); + } + + if (options.size() > 0) { + po::store(po::command_line_parser(options).options(desc).run(), vm); + po::notify(vm); + } + } + + // predicate to extract all positional arguments from the command line + struct is_argument { + bool operator()(po::option const &opt) + { + return (opt.position_key == -1) ? true : false; + } + }; + +/////////////////////////////////////////////////////////////////////////////// +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Special validator overload, which allows to handle the -I- syntax for +// switching the semantics of an -I option. +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace program_options { + + void validate(boost::any &v, std::vector const &s, + cmd_line_util::include_paths *, int) + { + cmd_line_util::include_paths::validate(v, s); + } + +}} // namespace boost::program_options + +/////////////////////////////////////////////////////////////////////////////// +namespace { + + class auto_stop_watch : public stop_watch + { + public: + auto_stop_watch(bool print_time_, std::ostream &outstrm_) + : print_time(print_time_), outstrm(outstrm_) + { + } + + ~auto_stop_watch() + { + if (print_time) { + outstrm << "Elapsed time: " + << this->format_elapsed_time() + << std::endl; + } + } + + private: + bool print_time; + std::ostream &outstrm; + }; + +/////////////////////////////////////////////////////////////////////////////// +} // anonymous namespace + +/////////////////////////////////////////////////////////////////////////////// +// do the actual preprocessing +int +do_actual_work (std::string file_name, std::istream &instream, + po::variables_map const &vm) +{ +// current file position is saved for exception handling +boost::wave::util::file_position_type current_position; + + try { + // process the given file + string instring; + + instream.unsetf(std::ios::skipws); + +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) + // this is known to be very slow for large files on some systems + copy (istream_iterator(instream), + istream_iterator(), + inserter(instring, instring.end())); +#else + instring = string(istreambuf_iterator(instream.rdbuf()), + istreambuf_iterator()); +#endif + + // This application uses the lex_iterator and lex_token types predefined + // with the Wave library, but it is possible to use your own types. + // + // You may want to have a look at the other samples to see how this is + // possible to achieve. + typedef boost::wave::cpplexer::lex_iterator< + boost::wave::cpplexer::lex_token<> > + lex_iterator_type; + + // The C++ preprocessor iterators shouldn't be constructed directly. They + // are to be generated through a boost::wave::context<> object. This + // boost::wave::context object is additionally to be used to initialize and + // define different parameters of the actual preprocessing. + typedef boost::wave::context< + std::string::iterator, lex_iterator_type, + boost::wave::iteration_context_policies::load_file_to_string, + trace_macro_expansion> + context_type; + + // The preprocessing of the input stream is done on the fly behind the + // scenes during iteration over the context_type::iterator_type stream. + std::ofstream traceout; + trace_flags enable_trace = trace_nothing; + + if (vm.count("traceto")) { + // try to open the file, where to put the trace output + string trace_file (vm["traceto"].as()); + + if (trace_file != "-") { + traceout.open(trace_file.c_str()); + if (!traceout.is_open()) { + cerr << "wave: could not open trace file: " << trace_file + << endl; + return -1; + } + } + enable_trace = trace_macros; + } + if ((enable_trace & trace_macros) && !traceout.is_open()) + { + // by default trace to std::cerr + traceout.copyfmt(cerr); + traceout.clear(cerr.rdstate()); + static_cast &>(traceout).rdbuf(cerr.rdbuf()); + } + + // This this the central piece of the Wave library, it provides you with + // the iterators to get the preprocessed tokens and allows to configure + // the preprocessing stage in advance. + context_type ctx (instring.begin(), instring.end(), file_name.c_str(), + trace_macro_expansion(traceout, enable_trace)); + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + // enable C99 mode, if appropriate (implies variadics) + if (vm.count("c99")) { + ctx.set_language(boost::wave::support_c99); + } + else if (vm.count("variadics")) { + // enable variadics and placemarkers, if appropriate + ctx.set_language(boost::wave::enable_variadics(ctx.get_language())); + } +#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + + // add include directories to the system include search paths + if (vm.count("sysinclude")) { + vector syspaths = vm["sysinclude"].as >(); + + vector::const_iterator end = syspaths.end(); + for (vector::const_iterator cit = syspaths.begin(); + cit != end; ++cit) + { + ctx.add_sysinclude_path((*cit).c_str()); + } + } + + // add include directories to the include search paths + if (vm.count("include")) { + cmd_line_util::include_paths const &ip = + vm["include"].as(); + vector::const_iterator end = ip.paths.end(); + + for (vector::const_iterator cit = ip.paths.begin(); + cit != end; ++cit) + { + ctx.add_include_path((*cit).c_str()); + } + + // if on the command line was given -I- , this has to be propagated + if (ip.seen_separator) + ctx.set_sysinclude_delimiter(); + + // add system include directories to the include path + vector::const_iterator sysend = ip.syspaths.end(); + for (vector::const_iterator syscit = ip.syspaths.begin(); + syscit != sysend; ++syscit) + { + ctx.add_sysinclude_path((*syscit).c_str()); + } + } + + // add additional defined macros + if (vm.count("define")) { + vector const ¯os = vm["define"].as >(); + vector::const_iterator end = macros.end(); + for (vector::const_iterator cit = macros.begin(); + cit != end; ++cit) + { + ctx.add_macro_definition(*cit); + } + } + + // add additional predefined macros + if (vm.count("predefine")) { + vector const &predefmacros = + vm["predefine"].as >(); + vector::const_iterator end = predefmacros.end(); + for (vector::const_iterator cit = predefmacros.begin(); + cit != end; ++cit) + { + ctx.add_macro_definition(*cit, true); + } + } + + // undefine specified macros + if (vm.count("undefine")) { + vector const &undefmacros = + vm["undefine"].as >(); + vector::const_iterator end = undefmacros.end(); + for (vector::const_iterator cit = undefmacros.begin(); + cit != end; ++cit) + { + ctx.remove_macro_definition((*cit).c_str(), true); + } + } + + // maximal include nesting depth + if (vm.count("nesting")) { + int max_depth = vm["nesting"].as(); + if (max_depth < 1 || max_depth > 100000) { + cerr << "wave: bogus maximal include nesting depth: " + << max_depth << endl; + return -1; + } + ctx.set_max_include_nesting_depth(max_depth); + } + + // open the output file + std::ofstream output; + + if (vm.count("output")) { + // try to open the file, where to put the preprocessed output + string out_file (vm["output"].as()); + + output.open(out_file.c_str()); + if (!output.is_open()) { + cerr << "wave: could not open output file: " << out_file << endl; + return -1; + } + } + else { + // output the preprocessed result to std::cout + output.copyfmt(cout); + output.clear(cout.rdstate()); + static_cast &>(output).rdbuf(cout.rdbuf()); + } + + // analyze the input file + auto_stop_watch elapsed_time(vm.count("timer") > 0, cout); + context_type::iterator_type first = ctx.begin(); + context_type::iterator_type last = ctx.end(); + + // preprocess the required include files + if (vm.count("forceinclude")) { + // add the filenames to force as include files in _reverse_ order + // the second parameter 'is_last' of the force_include function should + // be set to true for the last (first given) file. + vector const &force = + vm["forceinclude"].as >(); + vector::const_reverse_iterator rend = force.rend(); + for (vector::const_reverse_iterator cit = force.rbegin(); + cit != rend; /**/) + { + string filename(*cit); + first.force_include(filename.c_str(), ++cit == rend); + } + } + + // >>>>>>>>>>>>> Here the actual preprocessing happens. <<<<<<<<<<<<<<<<<<< + // loop over all generated tokens outputting the generated text + while (first != last) { + // print out the string representation of this token (skip comments) + using namespace boost::wave; + + // store the last known good token position + current_position = (*first).get_position(); + + token_id id = token_id(*first); + + if (T_CPPCOMMENT == id || T_NEWLINE == id) { + // C++ comment tokens contain the trailing newline + output << endl; + } + else if (id != T_CCOMMENT) { + // print out the current token value + output << (*first).get_value(); + } + ++first; // advance to the next token + } + } + catch (boost::wave::cpp_exception &e) { + // some preprocessing error + cerr + << e.file_name() << "(" << e.line_no() << "): " + << e.description() << endl; + return 1; + } + catch (boost::wave::cpplexer::lexing_exception &e) { + // some lexing error + cerr + << e.file_name() << "(" << e.line_no() << "): " + << e.description() << endl; + return 2; + } + catch (std::exception &e) { + // use last recognized token to retrieve the error position + cerr + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "exception caught: " << e.what() + << endl; + return 3; + } + catch (...) { + // use last recognized token to retrieve the error position + cerr + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "unexpected exception caught." << endl; + return 4; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int +main (int argc, char *argv[]) +{ + try { + // analyze the command line options and arguments + + // declare the options allowed from the command line only + po::options_description desc_cmdline ("Options allowed on the command line only"); + + desc_cmdline.add_options() + ("help,h", "print out program usage (this message)") + ("version,v", "print the version number") + ("copyright,c", "print out the copyright statement") + ("config-file", po::value >(), + "specify a config file (alternatively: @filepath)") + ; + + // declare the options allowed on command line and in config files + po::options_description desc_generic ("Options allowed additionally in a config file"); + + desc_generic.add_options() + ("output,o", po::value(), + "specify a file to use for output instead of stdout") + ("include,I", po::value()->composing(), + "specify an additional include directory") + ("sysinclude,S", po::value >()->composing(), + "specify an additional system include directory") + ("forceinclude,F", po::value >()->composing(), + "force inclusion of the given file") + ("define,D", po::value >()->composing(), + "specify a macro to define (as macro[=[value]])") + ("predefine,P", po::value >()->composing(), + "specify a macro to predefine (as macro[=[value]])") + ("undefine,U", po::value >()->composing(), + "specify a macro to undefine") + ("nesting,n", po::value(), + "specify a new maximal include nesting depth") + ; + + po::options_description desc_ext ("Extended options (allowed everywhere)"); + + desc_ext.add_options() + ("traceto,t", po::value(), + "output trace info to a file [path] or to stderr [-]") + ("timer", "output overall elapsed computing time to stderr") +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + ("variadics", "enable certain C99 extensions in C++ mode") + ("c99", "enable C99 mode (implies --variadics)") +#endif + ; + + // combine the options for the different usage schemes + po::options_description desc_overall_cmdline; + po::options_description desc_overall_cfgfile; + + desc_overall_cmdline.add(desc_cmdline).add(desc_generic).add(desc_ext); + desc_overall_cfgfile.add(desc_generic).add(desc_ext); + + // parse command line and store results + po::parsed_options opts(po::parse_command_line(argc, argv, + desc_overall_cmdline, 0, cmd_line_util::at_option_parser)); + po::variables_map vm; + + po::store(opts, vm); + po::notify(vm); + + // Try to find a wave.cfg in the same directory as the executable was + // started from. If this exists, treat it as a wave config file + fs::path filename(argv[0], fs::native); + + filename = filename.branch_path() / "wave.cfg"; + cmd_line_util::read_config_file_options(filename.string(), + desc_overall_cfgfile, vm, true); + + // if there is specified at least one config file, parse it and add the + // options to the main variables_map + if (vm.count("config-file")) { + vector const &cfg_files = + vm["config-file"].as >(); + vector::const_iterator end = cfg_files.end(); + for (vector::const_iterator cit = cfg_files.begin(); + cit != end; ++cit) + { + // parse a single config file and store the results + cmd_line_util::read_config_file_options(*cit, + desc_overall_cfgfile, vm); + } + } + + // ... act as required + if (vm.count("help")) { + po::options_description desc_help ( + "Usage: wave [options] [@config-file(s)] [file]"); + + desc_help.add(desc_cmdline).add(desc_generic).add(desc_ext); + cout << desc_help << endl; + return 1; + } + + if (vm.count("version")) { + return print_version(); + } + + if (vm.count("copyright")) { + return print_copyright(); + } + + // extract the arguments from the parsed command line + vector arguments; + + std::remove_copy_if(opts.options.begin(), opts.options.end(), + inserter(arguments, arguments.end()), cmd_line_util::is_argument()); + + // if there is no input file given, then exit + if (0 == arguments.size() || 0 == arguments[0].value.size() || + arguments[0].value[0] == "-") + { + // preprocess the given input from stdin + return do_actual_work("stdin", std::cin, vm); + } + else { + std::string file_name(arguments[0].value[0]); + ifstream instream(file_name.c_str()); + + // preprocess the given input file + if (!instream.is_open()) { + cerr << "wave: could not open input file: " << file_name << endl; + return -1; + } + return do_actual_work(file_name, instream, vm); + } + } + catch (std::exception &e) { + cout << "wave: exception caught: " << e.what() << endl; + return 6; + } + catch (...) { + cerr << "wave: unexpected exception caught." << endl; + return 7; + } +} + diff --git a/tool/cpp.hpp b/tool/cpp.hpp new file mode 100644 index 000000000..1f6a992ab --- /dev/null +++ b/tool/cpp.hpp @@ -0,0 +1,43 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED) +#define CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// This file may be used as a precompiled header (if applicable) + +/////////////////////////////////////////////////////////////////////////////// +// include often used files from the stdlib +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// include boost config +#include // global configuration information + +/////////////////////////////////////////////////////////////////////////////// +// build version +#include "cpp_version.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// configure this app here (global configuration constants) +#include "cpp_config.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// include required boost libraries +#include +#include + +#endif // !defined(CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED) diff --git a/tool/cpp_config.hpp b/tool/cpp_config.hpp new file mode 100644 index 000000000..272936221 --- /dev/null +++ b/tool/cpp_config.hpp @@ -0,0 +1,63 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + Global application configuration of the Wave driver command + + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED) +#define CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment the following, if you need debug output, the +// BOOST_SPIRIT_DEBUG_FLAGS constants below helps to fine control the amount of +// the generated debug output +//#define BOOST_SPIRIT_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// debug rules, subrules and grammars only, for possible flags see +// spirit/debug.hpp +#if defined(BOOST_SPIRIT_DEBUG) + +#define BOOST_SPIRIT_DEBUG_FLAGS ( \ + BOOST_SPIRIT_DEBUG_FLAGS_NODES | \ + BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES \ + ) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// Debug flags for the Wave library, possible flags (defined in +// wave_config.hpp): +// +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR 0x0001 +// #define BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION 0x0002 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR 0x0004 +// #define BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR 0x0008 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR 0x0010 +// #define BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR 0x0020 +// #define BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR 0x0040 + +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP ( 0 \ + /* insert the required flags from above */ \ + ) \ + /**/ +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Include the configuration stuff for the Wave library itself +#include + +/////////////////////////////////////////////////////////////////////////////// +// MSVC specific #pragma's +#if defined(BOOST_MSVC) +#pragma warning (disable: 4355) // 'this' used in base member initializer list +#pragma warning (disable: 4800) // forcing value to bool 'true' or 'false' +#pragma inline_depth(255) +#pragma inline_recursion(on) +#endif // defined(BOOST_MSVC) + +#endif // !defined(CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED) diff --git a/tool/cpp_version.hpp b/tool/cpp_version.hpp new file mode 100644 index 000000000..a1f98a2eb --- /dev/null +++ b/tool/cpp_version.hpp @@ -0,0 +1,20 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED) +#define CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED + +#include + +#define CPP_VERSION_MAJOR BOOST_WAVE_VERSION_MAJOR +#define CPP_VERSION_MINOR BOOST_WAVE_VERSION_MINOR +#define CPP_VERSION_SUBMINOR BOOST_WAVE_VERSION_SUBMINOR +#define CPP_VERSION_DATE 20050218L + +#endif // !defined(CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED) diff --git a/tool/stop_watch.hpp b/tool/stop_watch.hpp new file mode 100644 index 000000000..955a6ddab --- /dev/null +++ b/tool/stop_watch.hpp @@ -0,0 +1,84 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(STOP_WATCH_HPP_HK040911_INCLUDED) +#define STOP_WATCH_HPP_HK040911_INCLUDED + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// +class stop_watch : public boost::timer { + + typedef boost::timer base_t; + +public: + stop_watch() : is_suspended_since(0), suspended_overall(0) {} + + void suspend() + { + if (0 == is_suspended_since) { + // if not already suspended + is_suspended_since = this->base_t::elapsed(); + } + } + void resume() + { + if (0 != is_suspended_since) { + // if really suspended + suspended_overall += this->base_t::elapsed() - is_suspended_since; + is_suspended_since = 0; + } + } + double elapsed() const + { + if (0 == is_suspended_since) { + // currently running + return this->base_t::elapsed() - suspended_overall; + } + + // currently suspended + BOOST_ASSERT(is_suspended_since >= suspended_overall); + return is_suspended_since - suspended_overall; + } + + std::string format_elapsed_time() const + { + double current = elapsed(); + char time_buffer[sizeof("1234:56:78.90 abcd.")+1]; + + using namespace std; + if (current >= 3600) { + // show hours + sprintf (time_buffer, "%d:%02d:%02d.%03d hrs.", + (int)(current) / 3600, ((int)(current) % 3600) / 60, + ((int)(current) % 3600) % 60, + (int)(current * 1000) % 1000); + } + else if (current >= 60) { + // show minutes + sprintf (time_buffer, "%d:%02d.%03d min.", + (int)(current) / 60, (int)(current) % 60, + (int)(current * 1000) % 1000); + } + else { + // show seconds + sprintf(time_buffer, "%d.%03d sec.", (int)current, + (int)(current * 1000) % 1000); + } + return time_buffer; + } + +private: + double is_suspended_since; + double suspended_overall; +}; + +#endif // !defined(STOP_WATCH_HPP_HK040911_INCLUDED) diff --git a/tool/trace_macro_expansion.hpp b/tool/trace_macro_expansion.hpp new file mode 100644 index 000000000..ea92f1a2b --- /dev/null +++ b/tool/trace_macro_expansion.hpp @@ -0,0 +1,511 @@ +/*============================================================================= + Wave: A Standard compliant C++ preprocessor library + http://spirit.sourceforge.net/ + + Copyright (c) 2001-2005 Hartmut Kaiser. 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) +=============================================================================*/ + +#if !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED) +#define TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "stop_watch.hpp" + +#ifdef BOOST_NO_STRINGSTREAM +#include +#define BOOST_WAVE_OSSTREAM std::ostrstream +std::string BOOST_WAVE_GETSTRING(std::ostrstream& ss) +{ + ss << ends; + std::string rval = ss.str(); + ss.freeze(false); + return rval; +} +#else +#include +#define BOOST_WAVE_GETSTRING(ss) ss.str() +#define BOOST_WAVE_OSSTREAM std::ostringstream +#endif + +// trace_flags: enable single tracing functionality +enum trace_flags { + trace_nothing = 0, // disable tracing + trace_macros = 1, // enable macro tracing + trace_includes = 2 // enable include file tracing +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// The trace_macro_expansion policy is used to trace the macro expansion of +// macros whenever it is requested from inside the input stream to preprocess +// through the '#pragma wave_option(trace: enable)' directive. The macro +// tracing is disabled with the help of a '#pragma wave_option(trace: disable)' +// directive. +// +// This policy type is used as a template parameter to the boost::wave::context<> +// object. +// +/////////////////////////////////////////////////////////////////////////////// +class trace_macro_expansion +: public boost::wave::context_policies::default_preprocessing_hooks +{ +public: + trace_macro_expansion(std::ostream &outstrm_, trace_flags flags_) + : outstrm(outstrm_), level(0), flags(flags_), logging_flags(trace_nothing) + { + } + ~trace_macro_expansion() + { + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanding_function_like_macro' is called, whenever a + // function-like macro is to be expanded. + // + // The 'macrodef' parameter marks the position, where the macro to expand + // is defined. + // The 'formal_args' parameter holds the formal arguments used during the + // definition of the macro. + // The 'definition' parameter holds the macro definition for the macro to + // trace. + // + // The 'macrocall' parameter marks the position, where this macro invoked. + // The 'arguments' parameter holds the macro arguments used during the + // invocation of the macro + // + /////////////////////////////////////////////////////////////////////////// + template + void expanding_function_like_macro( + TokenT const ¯odef, std::vector const &formal_args, + ContainerT const &definition, + TokenT const ¯ocall, std::vector const &arguments) + { + if (!enabled_macro_tracing()) return; + + if (0 == get_level()) { + // output header line + BOOST_WAVE_OSSTREAM stream; + + stream + << macrocall.get_position() << ": " + << macrocall.get_value() << "("; + + // argument list + for (typename ContainerT::size_type i = 0; i < arguments.size(); ++i) { + stream << boost::wave::util::impl::as_string(arguments[i]); + if (i < arguments.size()-1) + stream << ", "; + } + stream << ")" << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + increment_level(); + } + + // output definition reference + { + BOOST_WAVE_OSSTREAM stream; + + stream + << macrodef.get_position() << ": see macro definition: " + << macrodef.get_value() << "("; + + // formal argument list + for (typename std::vector::size_type i = 0; + i < formal_args.size(); ++i) + { + stream << formal_args[i].get_value(); + if (i < formal_args.size()-1) + stream << ", "; + } + stream << ")" << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + } + + if (formal_args.size() > 0) { + // map formal and real arguments + open_trace_body("invoked with\n"); + for (typename std::vector::size_type j = 0; + j < formal_args.size(); ++j) + { + using namespace boost::wave; + + BOOST_WAVE_OSSTREAM stream; + stream << formal_args[j].get_value() << " = "; +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (T_ELLIPSIS == token_id(formal_args[j])) { + // ellipsis + for (typename ContainerT::size_type k = j; + k < arguments.size(); ++k) + { + stream << boost::wave::util::impl::as_string(arguments[k]); + if (k < arguments.size()-1) + stream << ", "; + } + } + else +#endif + { + stream << boost::wave::util::impl::as_string(arguments[j]); + } + stream << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + } + close_trace_body(); + } + open_trace_body(); + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanding_object_like_macro' is called, whenever a + // object-like macro is to be expanded . + // + // The 'macrodef' parameter marks the position, where the macro to expand + // is defined. + // The 'definition' parameter holds the macro definition for the macro to + // trace. + // + // The 'macrocall' parameter marks the position, where this macro invoked. + // + /////////////////////////////////////////////////////////////////////////// + template + void expanding_object_like_macro(TokenT const ¯odef, + ContainerT const &definition, TokenT const ¯ocall) + { + if (!enabled_macro_tracing()) return; + + if (0 == get_level()) { + // output header line + BOOST_WAVE_OSSTREAM stream; + + stream + << macrocall.get_position() << ": " + << macrocall.get_value() << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + increment_level(); + } + + // output definition reference + { + BOOST_WAVE_OSSTREAM stream; + + stream + << macrodef.get_position() << ": see macro definition: " + << macrodef.get_value() << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + } + open_trace_body(); + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanded_macro' is called, whenever the expansion of a + // macro is finished but before the rescanning process starts. + // + // The parameter 'result' contains the token sequence generated as the + // result of the macro expansion. + // + /////////////////////////////////////////////////////////////////////////// + template + void expanded_macro(ContainerT const &result) + { + if (!enabled_macro_tracing()) return; + + BOOST_WAVE_OSSTREAM stream; + stream << boost::wave::util::impl::as_string(result) << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + + open_trace_body("rescanning\n"); + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'rescanned_macro' is called, whenever the rescanning of a + // macro is finished. + // + // The parameter 'result' contains the token sequence generated as the + // result of the rescanning. + // + /////////////////////////////////////////////////////////////////////////// + template + void rescanned_macro(ContainerT const &result) + { + if (!enabled_macro_tracing() || get_level() == 0) + return; + + BOOST_WAVE_OSSTREAM stream; + stream << boost::wave::util::impl::as_string(result) << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + close_trace_body(); + close_trace_body(); + + if (1 == get_level()) + decrement_level(); + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'interpret_pragma' is called, whenever a #pragma wave + // directive is found, which isn't known to the core Wave library. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'pending' may be used to push tokens back into the input + // stream, which are to be used as the replacement text for the whole + // #pragma wave() directive. + // + // The parameter 'option' contains the name of the interpreted pragma. + // + // The parameter 'values' holds the values of the parameter provided to + // the pragma operator. + // + // The parameter 'act_token' contains the actual #pragma token, which may + // be used for error output. + // + // If the return value is 'false', the whole #pragma directive is + // interpreted as unknown and a corresponding error message is issued. A + // return value of 'true' signs a successful interpretation of the given + // #pragma. + // + /////////////////////////////////////////////////////////////////////////// + template + bool + interpret_pragma(ContextT const &ctx, ContainerT &pending, + typename ContextT::token_type const &option, ContainerT const &values, + typename ContextT::token_type const &act_token) + { + typedef typename ContextT::token_type token_type; + + if (option.get_value() == "timer") { + // #pragma wave timer(value) + if (0 == values.size()) { + // no value means '1' + using namespace boost::wave; + timer(token_type(T_INTLIT, "1", act_token.get_position())); + } + else { + timer(values.front()); + } + return true; + } + else if (option.get_value() == "trace") { + // enable/disable tracing option + return interpret_pragma_trace(ctx, values, act_token); + } + else if (option.get_value() == "system") { + // try to spawn the given argument as a system command and return the + // std::cout of this process as the replacement of this _Pragma + return interpret_pragma_system(ctx, pending, values, act_token); + } + if (option.get_value() == "stop") { + // stop the execution and output the argument + BOOST_WAVE_THROW(preprocess_exception, error_directive, + boost::wave::util::impl::as_string(values), + act_token.get_position()); + } + return false; + } + +protected: + // Interpret the different Wave specific pragma directives/operators + template + bool + interpret_pragma_trace(ContextT const &/*ctx*/, ContainerT const &values, + typename ContextT::token_type const &act_token) + { + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + + bool valid_option = false; + + if (1 == values.size()) { + token_type const &value = values.front(); + + if (value.get_value() == "enable" || + value.get_value() == "on" || + value.get_value() == "1") + { + // #pragma wave trace(enable) + enable_tracing(static_cast( + tracing_enabled() | trace_macros)); + valid_option = true; + } + else if (value.get_value() == "disable" || + value.get_value() == "off" || + value.get_value() == "0") + { + // #pragma wave trace(disable) + enable_tracing(static_cast( + tracing_enabled() & ~trace_macros)); + valid_option = true; + } + } + if (!valid_option) { + // unknown option value + string_type option_str ("trace"); + + if (values.size() > 0) { + option_str += "("; + option_str += boost::wave::util::impl::as_string(values); + option_str += ")"; + } + BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, + option_str, act_token.get_position()); + } + return true; + } + + template + bool + interpret_pragma_system(ContextT const &ctx, ContainerT &pending, + ContainerT const &values, + typename ContextT::token_type const &act_token) + { + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + + if (0 == values.size()) return false; // ill_formed_pragma_option + + string_type stdout_file(std::tmpnam(0)); + string_type stderr_file(std::tmpnam(0)); + string_type system_str(boost::wave::util::impl::as_string(values)); + string_type native_cmd(system_str); + + system_str += " >" + stdout_file + " 2>" + stderr_file; + if (0 != std::system(system_str.c_str())) { + // unable to spawn the command + string_type error_str("unable to spawn command: "); + + error_str += native_cmd; + BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, + error_str, act_token.get_position()); + } + + // rescan the content of the stdout_file and insert it as the + // _Pragma replacement + typedef typename ContextT::lexer_type lexer_type; + typedef typename ContextT::input_policy_type input_policy_type; + typedef boost::wave::iteration_context + iteration_context_type; + + iteration_context_type iter_ctx(stdout_file.c_str(), + act_token.get_position(), ctx.get_language()); + ContainerT pragma; + + for (/**/; iter_ctx.first != iter_ctx.last; ++iter_ctx.first) + pragma.push_back(*iter_ctx.first); + + // prepend the newly generated token sequence to the 'pending' container + pending.splice(pending.begin(), pragma); + + // erase the created tempfiles + std::remove(stdout_file.c_str()); + std::remove(stderr_file.c_str()); + return true; + } + + // The function enable_tracing is called, whenever the status of the + // tracing was changed. + // The parameter 'enable' is to be used as the new tracing status. + void enable_tracing(trace_flags flags) + { logging_flags = flags; } + + // The function tracing_enabled should return the current tracing status. + trace_flags tracing_enabled() + { return logging_flags; } + + // Helper functions for generating the trace output + void open_trace_body(char const *label = 0) + { + if (label) + output(label); + output("[\n"); + increment_level(); + } + void close_trace_body() + { + if (get_level() > 0) { + decrement_level(); + output("]\n"); + outstrm << std::flush; // flush the stream buffer + } + } + + template + void output(StringT const &outstr) const + { + indent(get_level()); + outstrm << outstr; // output the given string + } + + void indent(int level) const + { + for (int i = 0; i < level; ++i) + outstrm << " "; // indent + } + + int increment_level() { return ++level; } + int decrement_level() { BOOST_ASSERT(level > 0); return --level; } + int get_level() const { return level; } + + bool enabled_macro_tracing() const + { + return (flags & trace_macros) && (logging_flags & trace_macros); + } + bool enabled_include_tracing() const + { + return (flags & trace_includes) && (logging_flags & trace_includes); + } + + template + void timer(TokenT const &value) + { + if (value.get_value() == "0" || value.get_value() == "restart") { + // restart the timer + elapsed_time.restart(); + } + else if (value.get_value() == "1") { + // print out the current elapsed time + std::cerr + << value.get_position() << ": " + << elapsed_time.format_elapsed_time() + << std::endl; + } + else if (value.get_value() == "suspend") { + // suspend the timer + elapsed_time.suspend(); + } + else if (value.get_value() == "resume") { + // resume the timer + elapsed_time.resume(); + } + } + +private: + std::ostream &outstrm; // output stream + int level; // indentation level + trace_flags flags; // enabled globally + trace_flags logging_flags; // enabled by a #pragma + + stop_watch elapsed_time; // trace timings +}; + +#undef BOOST_WAVE_GETSTRING +#undef BOOST_WAVE_OSSTREAM + +#endif // !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED)