BsGLSLPreprocessor.h 18 KB

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