LCOV - code coverage report
Current view: top level - source/third_party/ogre3d_preprocessor - OgreGLSLPreprocessor.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 32 32 100.0 %
Date: 2023-01-19 00:18:29 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This source file originally came from OGRE v1.12.4 - http://www.ogre3d.org/
       3             :  * with some tweaks as part of 0 A.D.
       4             :  * All changes are released under the original license, as follows:
       5             :  */
       6             : 
       7             : /*
       8             :    -----------------------------------------------------------------------------
       9             :    This source file is part of OGRE
      10             :    (Object-oriented Graphics Rendering Engine)
      11             :    For the latest info, see http://www.ogre3d.org/
      12             : 
      13             :    Copyright (c) 2000-2014 Torus Knot Software Ltd
      14             : 
      15             :    Permission is hereby granted, free of charge, to any person obtaining a copy
      16             :    of this software and associated documentation files (the "Software"), to deal
      17             :    in the Software without restriction, including without limitation the rights
      18             :    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      19             :    copies of the Software, and to permit persons to whom the Software is
      20             :    furnished to do so, subject to the following conditions:
      21             : 
      22             :    The above copyright notice and this permission notice shall be included in
      23             :    all copies or substantial portions of the Software.
      24             : 
      25             :    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      26             :    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      27             :    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      28             :    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      29             :    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      30             :    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      31             :    THE SOFTWARE.
      32             :    -----------------------------------------------------------------------------
      33             : */
      34             : 
      35             : #ifndef __OGRE_CPREPROCESSOR_H__
      36             : #define __OGRE_CPREPROCESSOR_H__
      37             : 
      38             : #include <forward_list>
      39             : #include <stdlib.h>
      40             : #include <string.h>
      41             : #include <vector>
      42             : 
      43             : namespace Ogre
      44             : {
      45             : 
      46             :     /**
      47             :      * This is a simplistic C/C++-like preprocessor.
      48             :      * It takes an non-zero-terminated string on input and outputs a
      49             :      * non-zero-terminated string buffer.
      50             :      *
      51             :      * This preprocessor was designed specifically for GLSL shaders, so
      52             :      * if you want to use it for other purposes you might want to check
      53             :      * if the feature set it provides is enough for you.
      54             :      *
      55             :      * Here's a list of supported features:
      56             :      * - Fast memory allocation-less operation (mostly).
      57             :      * - Line continuation (backslash-newline) is swallowed.
      58             :      * - Line numeration is fully preserved by inserting empty lines where
      59             :      *     required. This is crucial if, say, GLSL compiler reports you an error
      60             :      *     with a line number.
      61             :      * - @c \#define: Parametrized and non-parametrized macros. Invoking a macro with
      62             :      *     less arguments than it takes assignes empty values to missing arguments.
      63             :      * - @c \#undef: Forget defined macros
      64             :      * - @c \#ifdef / @c \#ifndef / @c \#else / @c \#endif: Conditional suppression of parts of code.
      65             :      * - @c \#if: Supports numeric expression of any complexity, also supports the
      66             :      *     defined() pseudo-function.
      67             :      */
      68             :     class CPreprocessor
      69             :     {
      70             :     public:
      71             :         /**
      72             :          * A input token.
      73             :          *
      74             :          * For performance reasons most tokens will point to portions of the
      75             :          * input stream, so no unneeded memory allocation is done. However,
      76             :          * in some cases we must allocate different memory for token storage,
      77             :          * in this case this is signalled by setting the Allocated member
      78             :          * to non-zero in which case the destructor will know that it must
      79             :          * free memory on object destruction.
      80             :          *
      81             :          * Again for performance reasons we use malloc/realloc/free here because
      82             :          * C++-style new[] lacks the realloc() counterpart.
      83             :          */
      84             :         class Token
      85             :         {
      86             :         public:
      87             :             enum Kind
      88             :             {
      89             :                 TK_EOS,          // End of input stream
      90             :                 TK_ERROR,        // An error has been encountered
      91             :                 TK_WHITESPACE,   // A whitespace span (but not newline)
      92             :                 TK_NEWLINE,      // A single newline (CR & LF)
      93             :                 TK_LINECONT,     // Line continuation ('\' followed by LF)
      94             :                 TK_NUMBER,       // A number
      95             :                 TK_KEYWORD,      // A keyword
      96             :                 TK_PUNCTUATION,  // A punctuation character
      97             :                 TK_DIRECTIVE,    // A preprocessor directive
      98             :                 TK_STRING,       // A string
      99             :                 TK_COMMENT,      // A block comment
     100             :                 TK_LINECOMMENT,  // A line comment
     101             :                 TK_TEXT          // An unparsed text (cannot be returned from GetToken())
     102             :             };
     103             : 
     104             :             /// Token type
     105             :             Kind Type;
     106             :             /// True if string was allocated (and must be freed)
     107             :             mutable size_t Allocated;
     108             :             union
     109             :             {
     110             :                 /// A pointer somewhere into the input buffer
     111             :                 const char *String;
     112             :                 /// A memory-allocated string
     113             :                 char *Buffer;
     114             :             };
     115             :             /// Token length in bytes
     116             :             size_t Length;
     117             : 
     118         444 :             Token () : Allocated (0), String (NULL), Length(0)
     119         444 :             { }
     120             : 
     121          49 :             Token (Kind iType) : Type (iType), Allocated (0), String (NULL), Length(0)
     122          49 :             { }
     123             : 
     124         656 :             Token (Kind iType, const char *iString, size_t iLength) :
     125         656 :             Type (iType), Allocated (0), String (iString), Length (iLength)
     126         656 :             { }
     127             : 
     128         338 :             Token (const Token &iOther)
     129         338 :             {
     130         338 :                 Type = iOther.Type;
     131         338 :                 Allocated = iOther.Allocated;
     132         338 :                 iOther.Allocated = 0; // !!! not quite correct but effective
     133         338 :                 String = iOther.String;
     134         338 :                 Length = iOther.Length;
     135         338 :             }
     136             : 
     137        1487 :             ~Token ()
     138        1487 :             { if (Allocated) free (Buffer); }
     139             : 
     140             :             /// Assignment operator
     141         456 :             Token &operator = (const Token &iOther)
     142             :                 {
     143         456 :                     if (Allocated) free (Buffer);
     144         456 :                     Type = iOther.Type;
     145         456 :                     Allocated = iOther.Allocated;
     146         456 :                     iOther.Allocated = 0; // !!! not quite correct but effective
     147         456 :                     String = iOther.String;
     148         456 :                     Length = iOther.Length;
     149         456 :                     return *this;
     150             :                 }
     151             : 
     152             :             /// Append a string to this token
     153             :             void Append (const char *iString, size_t iLength);
     154             : 
     155             :             /// Append a token to this token
     156             :             void Append (const Token &iOther);
     157             : 
     158             :             /// Append given number of newlines to this token
     159             :             void AppendNL (int iCount);
     160             : 
     161             :             /// Count number of newlines in this token
     162             :             int CountNL ();
     163             : 
     164             :             /// Get the numeric value of the token
     165             :             bool GetValue (long &oValue) const;
     166             : 
     167             :             /// Set the numeric value of the token
     168             :             void SetValue (long iValue);
     169             : 
     170             :             /// Test two tokens for equality
     171         141 :             bool operator == (const Token &iOther)
     172             :             {
     173         141 :                 if (iOther.Length != Length)
     174          82 :                     return false;
     175          59 :                 return (memcmp (String, iOther.String, Length) == 0);
     176             :             }
     177             :         };
     178             : 
     179             :         /// A macro definition
     180          51 :         class Macro
     181             :         {
     182             :         public:
     183             :             /// Macro name
     184             :             Token Name;
     185             :             /// The names of the arguments
     186             :             std::vector<Token> Args;
     187             :             /// The macro value
     188             :             Token Value;
     189             :             /// Unparsed macro body (keeps the whole raw unparsed macro body)
     190             :             Token Body;
     191             :             /// A pointer to function implementation (if macro is really a func)
     192             :             Token (*ExpandFunc) (CPreprocessor *iParent, const std::vector<Token>& iArgs);
     193             :             /// true if macro expansion is in progress
     194             :             bool Expanding;
     195             : 
     196          27 :             Macro(const Token& iName) : Name(iName), ExpandFunc(NULL), Expanding(false) {}
     197             : 
     198             :             /// Expand the macro value (will not work for functions)
     199             :             Token Expand (const std::vector<Token>& iArgs, std::forward_list<Macro>& iMacros);
     200             :         };
     201             : 
     202             :         friend class CPreprocessor::Macro;
     203             : 
     204             :         /// The current source text input
     205             :         const char *Source;
     206             :         /// The end of the source text
     207             :         const char *SourceEnd;
     208             :         /// Current line number
     209             :         int Line;
     210             :         /// True if we are at beginning of line
     211             :         bool BOL;
     212             :         /// A stack of 32 booleans packed into one value :)
     213             :         unsigned EnableOutput;
     214             :         unsigned EnableElif;
     215             :         /// The list of macros defined so far
     216             :         std::forward_list<Macro> MacroList;
     217             : 
     218             :         /**
     219             :          * Private constructor to re-parse a single token.
     220             :          */
     221             :         CPreprocessor (const Token &iToken, int iLine);
     222             : 
     223             :         /**
     224             :          * Stateless tokenizer: Parse the input text and return the next token.
     225             :          * @param iExpand
     226             :          *     If true, macros will be expanded to their values
     227             :          * @return
     228             :          *     The next token from the input stream
     229             :          */
     230             :         Token GetToken (bool iExpand);
     231             : 
     232             :         /**
     233             :          * Handle a preprocessor directive.
     234             :          * @param iToken
     235             :          *     The whole preprocessor directive line (until EOL)
     236             :          * @param iLine
     237             :          *     The line where the directive begins (for error reports)
     238             :          * @return
     239             :          *     The last input token that was not proceeded.
     240             :          */
     241             :         Token HandleDirective (Token &iToken, int iLine);
     242             : 
     243             :         /**
     244             :          * Handle a #define directive.
     245             :          * @param iBody
     246             :          *     The body of the directive (everything after the directive
     247             :          *     until end of line).
     248             :          * @param iLine
     249             :          *     The line where the directive begins (for error reports)
     250             :          * @return
     251             :          *     true if everything went ok, false if not
     252             :          */
     253             :         bool HandleDefine (Token &iBody, int iLine);
     254             : 
     255             :         /**
     256             :          * Undefine a previously defined macro
     257             :          * @param iBody
     258             :          *     The body of the directive (everything after the directive
     259             :          *     until end of line).
     260             :          * @param iLine
     261             :          *     The line where the directive begins (for error reports)
     262             :          * @return
     263             :          *     true if everything went ok, false if not
     264             :          */
     265             :         bool HandleUnDef (Token &iBody, int iLine);
     266             : 
     267             :         /**
     268             :          * Handle an #ifdef directive.
     269             :          * @param iBody
     270             :          *     The body of the directive (everything after the directive
     271             :          *     until end of line).
     272             :          * @param iLine
     273             :          *     The line where the directive begins (for error reports)
     274             :          * @return
     275             :          *     true if everything went ok, false if not
     276             :          */
     277             :         bool HandleIfDef (Token &iBody, int iLine);
     278             : 
     279             :         /**
     280             :          * Handle an #if directive.
     281             :          * @param iBody
     282             :          *     The body of the directive (everything after the directive
     283             :          *     until end of line).
     284             :          * @param iLine
     285             :          *     The line where the directive begins (for error reports)
     286             :          * @return
     287             :          *     true if everything went ok, false if not
     288             :          */
     289             :         bool HandleIf (Token &iBody, int iLine);
     290             : 
     291             :         /// @overload
     292             :         bool HandleIf(bool val, int iLine);
     293             : 
     294             :         /**
     295             :          * Handle an #elif directive.
     296             :          * @param iBody
     297             :          *     The body of the directive (everything after the directive
     298             :          *     until end of line).
     299             :          * @param iLine
     300             :          *     The line where the directive begins (for error reports)
     301             :          * @return
     302             :          *     true if everything went ok, false if not
     303             :          */
     304             :         bool HandleElif (Token &iBody, int iLine);
     305             : 
     306             :         /**
     307             :          * Handle an #else directive.
     308             :          * @param iBody
     309             :          *     The body of the directive (everything after the directive
     310             :          *     until end of line).
     311             :          * @param iLine
     312             :          *     The line where the directive begins (for error reports)
     313             :          * @return
     314             :          *     true if everything went ok, false if not
     315             :          */
     316             :         bool HandleElse (Token &iBody, int iLine);
     317             : 
     318             :         /**
     319             :          * Handle an #endif directive.
     320             :          * @param iBody
     321             :          *     The body of the directive (everything after the directive
     322             :          *     until end of line).
     323             :          * @param iLine
     324             :          *     The line where the directive begins (for error reports)
     325             :          * @return
     326             :          *     true if everything went ok, false if not
     327             :          */
     328             :         bool HandleEndIf (Token &iBody, int iLine);
     329             : 
     330             :         /**
     331             :          * Get a single function argument until next ',' or ')'.
     332             :          * @param oArg
     333             :          *     The argument is returned in this variable.
     334             :          * @param iExpand
     335             :          *     If false, parameters are not expanded and no expressions are
     336             :          *     allowed; only a single keyword is expected per argument.
     337             :          * @param shouldAppendArg
     338             :          *     When true, the argument will be appended the word word __arg_
     339             :          *     e.g. #define myMacro(x) --> #define myMacro(x__arg_)
     340             :          *     This workaround a bug where calling myMacro( x ) would cause
     341             :          *     issues.
     342             :          * @return
     343             :          *     The first unhandled token after argument.
     344             :          */
     345             :         Token GetArgument (Token &oArg, bool iExpand, bool shouldAppendArg);
     346             : 
     347             :         /**
     348             :          * Get all the arguments of a macro: '(' arg1 { ',' arg2 { ',' ... }} ')'
     349             :          * @param oArgs
     350             :          *     This is set to a pointer to an array of parsed arguments.
     351             :          * @param shouldAppendArg
     352             :          *      See GetArgument.
     353             :          * @param iExpand
     354             :          *     If false, parameters are not expanded and no expressions are
     355             :          *     allowed; only a single keyword is expected per argument.
     356             :          */
     357             :         Token GetArguments (std::vector<Token>& oArgs, bool iExpand, bool shouldAppendArg);
     358             : 
     359             :         /**
     360             :          * Parse an expression, compute it and return the result.
     361             :          * @param oResult
     362             :          *     A token containing the result of expression
     363             :          * @param iLine
     364             :          *     The line at which the expression starts (for error reports)
     365             :          * @param iOpPriority
     366             :          *     Operator priority (at which operator we will stop if
     367             :          *     proceeding recursively -- used internally. Parser stops
     368             :          *     when it encounters an operator with higher or equal priority).
     369             :          * @return
     370             :          *     The last unhandled token after the expression
     371             :          */
     372             :         Token GetExpression (Token &oResult, int iLine, int iOpPriority = 0);
     373             : 
     374             :         /**
     375             :          * Get the numeric value of a token.
     376             :          * If the token was produced by expanding a macro, we will get
     377             :          * an TEXT token which can contain a whole expression; in this
     378             :          * case we will call GetExpression to parse it. Otherwise we
     379             :          * just call the token's GetValue() method.
     380             :          * @param iToken
     381             :          *     The token to get the numeric value of
     382             :          * @param oValue
     383             :          *     The variable to put the value into
     384             :          * @param iLine
     385             :          *     The line where the directive begins (for error reports)
     386             :          * @return
     387             :          *     true if ok, false if not
     388             :          */
     389             :         bool GetValue (const Token &iToken, long &oValue, int iLine);
     390             : 
     391             :         /// @overload
     392             :         /// same as above, but considers the defined() function
     393             :         bool GetValueDef(const Token &iToken, long &oValue, int iLine);
     394             : 
     395             :         /**
     396             :          * Expand the given macro, if it exists.
     397             :          * If macro has arguments, they are collected from source stream.
     398             :          * @param iToken
     399             :          *     A KEYWORD token containing the (possible) macro name.
     400             :          * @return
     401             :          *     The expanded token or iToken if it is not a macro
     402             :          */
     403             :         Token ExpandMacro (const Token &iToken);
     404             : 
     405             :         /**
     406             :          * Check if a macro is defined, and if so, return it
     407             :          * @param iToken
     408             :          *     Macro name
     409             :          * @return
     410             :          *     The macro object or NULL if a macro with this name does not exist
     411             :          */
     412             :         Macro *IsDefined (const Token &iToken);
     413             : 
     414             :         /**
     415             :          * The implementation of the defined() preprocessor function
     416             :          * @param iParent
     417             :          *     The parent preprocessor object
     418             :          * @param iArgs
     419             :          *     The arguments themselves
     420             :          * @return
     421             :          *     The return value encapsulated in a token
     422             :          */
     423             :         static Token ExpandDefined (CPreprocessor *iParent, const std::vector<Token>& iArgs);
     424             : 
     425             :         /**
     426             :          * Parse the input string and return a token containing the whole output.
     427             :          * @param iSource
     428             :          *     The source text enclosed in a token
     429             :          * @return
     430             :          *     The output text enclosed in a token
     431             :          */
     432             :         Token Parse (const Token &iSource);
     433             : 
     434             :         /**
     435             :          * Call the error handler
     436             :          * @param iLine
     437             :          *     The line at which the error happened.
     438             :          * @param iError
     439             :          *     The error string.
     440             :          * @param iToken
     441             :          *     If not NULL contains the erroneous token
     442             :          */
     443             :         static void Error (int iLine, const char *iError, const Token *iToken = NULL);
     444             : 
     445             :     public:
     446             :         /// Create an empty preprocessor object
     447          31 :         CPreprocessor() {}
     448             : 
     449             :         /// Destroy the preprocessor object
     450             :         virtual ~CPreprocessor ();
     451             : 
     452             :         /**
     453             :          * Define a macro without parameters.
     454             :          * @param iMacroName
     455             :          *     The name of the defined macro
     456             :          * @param iMacroNameLen
     457             :          *     The length of the name of the defined macro
     458             :          * @param iMacroValue
     459             :          *     The value of the defined macro
     460             :          * @param iMacroValueLen
     461             :          *     The length of the value of the defined macro
     462             :          */
     463             :         void Define (const char *iMacroName, size_t iMacroNameLen,
     464             :                      const char *iMacroValue, size_t iMacroValueLen);
     465             : 
     466             :         /**
     467             :          * Define a numerical macro.
     468             :          * @param iMacroName
     469             :          *     The name of the defined macro
     470             :          * @param iMacroNameLen
     471             :          *     The length of the name of the defined macro
     472             :          * @param iMacroValue
     473             :          *     The value of the defined macro
     474             :          */
     475             :         void Define (const char *iMacroName, size_t iMacroNameLen, long iMacroValue);
     476             : 
     477             :         /**
     478             :          * Undefine a macro.
     479             :          * @param iMacroName
     480             :          *     The name of the macro to undefine
     481             :          * @param iMacroNameLen
     482             :          *     The length of the name of the macro to undefine
     483             :          * @return
     484             :          *     true if the macro has been undefined, false if macro doesn't exist
     485             :          */
     486             :         bool Undef (const char *iMacroName, size_t iMacroNameLen);
     487             : 
     488             :         /**
     489             :          * Parse the input string and return a newly-allocated output string.
     490             :          * @note
     491             :          *     The returned preprocessed string is NOT zero-terminated
     492             :          *     (just like the input string).
     493             :          * @param iSource
     494             :          *     The source text
     495             :          * @param iLength
     496             :          *     The length of the source text in characters
     497             :          * @param oLength
     498             :          *     The length of the output string.
     499             :          * @return
     500             :          *     The output from preprocessor, allocated with malloc().
     501             :          *     The parser can actually allocate more than needed for performance
     502             :          *     reasons, but this should not be a problem unless you will want
     503             :          *     to store the returned pointer for long time in which case you
     504             :          *     might want to realloc() it.
     505             :          *     If an error has been encountered, the function returns NULL.
     506             :          *     In some cases the function may return an unallocated address
     507             :          *     that's *inside* the source buffer. You must free() the result
     508             :          *     string only if the returned address is not inside the source text.
     509             :          */
     510             :         char *Parse (const char *iSource, size_t iLength, size_t &oLength);
     511             : 
     512             :         /**
     513             :          * Call the error handler
     514             :          * @param iLine
     515             :          *     The line at which the error happened.
     516             :          * @param iError
     517             :          *     The error string.
     518             :          * @param iToken
     519             :          *     If not NULL contains the erroneous token
     520             :          */
     521             :         typedef void (*ErrorHandlerFunc) (int iLine, const char *iError, const Token *iToken);
     522             : 
     523             :         /**
     524             :          * A pointer to the preprocessor's error handler.
     525             :          * You can assign the address of your own function to this variable
     526             :          * and implement your own error handling (e.g. throwing an exception etc).
     527             :          */
     528             :         static ErrorHandlerFunc ErrorHandler;
     529             : 
     530             :     };
     531             : 
     532             : } // namespace Ogre
     533             : 
     534             : #endif // __OGRE_CPREPROCESSOR_H__

Generated by: LCOV version 1.13