OgreGLSLPreprocessor.cpp 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292
  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. #include "OgreGLSLPreprocessor.h"
  25. #include <ctype.h>
  26. #include <stdio.h>
  27. #include <assert.h>
  28. namespace CamelotEngine {
  29. // Limit max number of macro arguments to this
  30. #define MAX_MACRO_ARGS 16
  31. #if CM_PLATFORM == CM_PLATFORM_WIN32 && !defined( __MINGW32__ )
  32. #define snprintf _snprintf
  33. #endif
  34. //---------------------------------------------------------------------------//
  35. /// Return closest power of two not smaller than given number
  36. static size_t ClosestPow2 (size_t x)
  37. {
  38. if (!(x & (x - 1)))
  39. return x;
  40. while (x & (x + 1))
  41. x |= (x + 1);
  42. return x + 1;
  43. }
  44. void CPreprocessor::Token::Append (const char *iString, size_t iLength)
  45. {
  46. Token t (Token::TK_TEXT, iString, iLength);
  47. Append (t);
  48. }
  49. void CPreprocessor::Token::Append (const Token &iOther)
  50. {
  51. if (!iOther.String)
  52. return;
  53. if (!String)
  54. {
  55. String = iOther.String;
  56. Length = iOther.Length;
  57. Allocated = iOther.Allocated;
  58. iOther.Allocated = 0; // !!! not quite correct but effective
  59. return;
  60. }
  61. if (Allocated)
  62. {
  63. size_t new_alloc = ClosestPow2 (Length + iOther.Length);
  64. if (new_alloc < 64)
  65. new_alloc = 64;
  66. if (new_alloc != Allocated)
  67. {
  68. Allocated = new_alloc;
  69. Buffer = (char *)realloc (Buffer, Allocated);
  70. }
  71. }
  72. else if (String + Length != iOther.String)
  73. {
  74. Allocated = ClosestPow2 (Length + iOther.Length);
  75. if (Allocated < 64)
  76. Allocated = 64;
  77. char *newstr = (char *)malloc (Allocated);
  78. memcpy (newstr, String, Length);
  79. Buffer = newstr;
  80. }
  81. if (Allocated)
  82. memcpy (Buffer + Length, iOther.String, iOther.Length);
  83. Length += iOther.Length;
  84. }
  85. bool CPreprocessor::Token::GetValue (long &oValue) const
  86. {
  87. long val = 0;
  88. size_t i = 0;
  89. while (isspace (String [i]))
  90. i++;
  91. long base = 10;
  92. if (String [i] == '0')
  93. if (Length > i + 1 && String [i + 1] == 'x')
  94. base = 16, i += 2;
  95. else
  96. base = 8;
  97. for (; i < Length; i++)
  98. {
  99. long c = long (String [i]);
  100. if (isspace (c))
  101. // Possible end of number
  102. break;
  103. if (c >= 'a' && c <= 'z')
  104. c -= ('a' - 'A');
  105. c -= '0';
  106. if (c < 0)
  107. return false;
  108. if (c > 9)
  109. c -= ('A' - '9' - 1);
  110. if (c >= base)
  111. return false;
  112. val = (val * base) + c;
  113. }
  114. // Check that all other characters are just spaces
  115. for (; i < Length; i++)
  116. if (!isspace (String [i]))
  117. return false;
  118. oValue = val;
  119. return true;
  120. }
  121. void CPreprocessor::Token::SetValue (long iValue)
  122. {
  123. char tmp [21];
  124. int len = snprintf (tmp, sizeof (tmp), "%ld", iValue);
  125. Length = 0;
  126. Append (tmp, len);
  127. Type = TK_NUMBER;
  128. }
  129. void CPreprocessor::Token::AppendNL (int iCount)
  130. {
  131. static const char newlines [8] =
  132. { '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n' };
  133. while (iCount > 8)
  134. {
  135. Append (newlines, 8);
  136. iCount -= 8;
  137. }
  138. if (iCount > 0)
  139. Append (newlines, iCount);
  140. }
  141. int CPreprocessor::Token::CountNL ()
  142. {
  143. if (Type == TK_EOS || Type == TK_ERROR)
  144. return 0;
  145. const char *s = String;
  146. int l = Length;
  147. int c = 0;
  148. while (l > 0)
  149. {
  150. const char *n = (const char *)memchr (s, '\n', l);
  151. if (!n)
  152. return c;
  153. c++;
  154. l -= (n - s + 1);
  155. s = n + 1;
  156. }
  157. return c;
  158. }
  159. //---------------------------------------------------------------------------//
  160. CPreprocessor::Token CPreprocessor::Macro::Expand (
  161. int iNumArgs, CPreprocessor::Token *iArgs, Macro *iMacros)
  162. {
  163. Expanding = true;
  164. CPreprocessor cpp;
  165. cpp.MacroList = iMacros;
  166. // Define a new macro for every argument
  167. int i;
  168. for (i = 0; i < iNumArgs; i++)
  169. cpp.Define (Args [i].String, Args [i].Length,
  170. iArgs [i].String, iArgs [i].Length);
  171. // The rest arguments are empty
  172. for (; i < NumArgs; i++)
  173. cpp.Define (Args [i].String, Args [i].Length, "", 0);
  174. // Now run the macro expansion through the supplimentary preprocessor
  175. Token xt = cpp.Parse (Value);
  176. Expanding = false;
  177. // Remove the extra macros we have defined
  178. for (int j = NumArgs - 1; j >= 0; j--)
  179. cpp.Undef (Args [j].String, Args [j].Length);
  180. cpp.MacroList = NULL;
  181. return xt;
  182. }
  183. //---------------------------------------------------------------------------//
  184. static void DefaultError (void *iData, int iLine, const char *iError,
  185. const char *iToken, size_t iTokenLen)
  186. {
  187. (void)iData;
  188. char line [1000];
  189. if (iToken)
  190. snprintf (line, sizeof (line), "line %d: %s: `%.*s'\n",
  191. iLine, iError, int (iTokenLen), iToken);
  192. else
  193. snprintf (line, sizeof (line), "line %d: %s\n", iLine, iError);
  194. // TODO LOG PORT - Log this somewhere?
  195. //LogManager::getSingleton ().logMessage (line);
  196. }
  197. //---------------------------------------------------------------------------//
  198. CPreprocessor::ErrorHandlerFunc CPreprocessor::ErrorHandler = DefaultError;
  199. CPreprocessor::CPreprocessor (const Token &iToken, int iLine) : MacroList (NULL)
  200. {
  201. Source = iToken.String;
  202. SourceEnd = iToken.String + iToken.Length;
  203. EnableOutput = 1;
  204. Line = iLine;
  205. BOL = true;
  206. }
  207. CPreprocessor::~CPreprocessor ()
  208. {
  209. delete MacroList;
  210. }
  211. void CPreprocessor::Error (int iLine, const char *iError, const Token *iToken)
  212. {
  213. if (iToken)
  214. ErrorHandler (ErrorData, iLine, iError, iToken->String, iToken->Length);
  215. else
  216. ErrorHandler (ErrorData, iLine, iError, NULL, 0);
  217. }
  218. CPreprocessor::Token CPreprocessor::GetToken (bool iExpand)
  219. {
  220. if (Source >= SourceEnd)
  221. return Token (Token::TK_EOS);
  222. const char *begin = Source;
  223. char c = *Source++;
  224. if (c == '\n' || (c == '\r' && *Source == '\n'))
  225. {
  226. Line++;
  227. BOL = true;
  228. if (c == '\r')
  229. Source++;
  230. return Token (Token::TK_NEWLINE, begin, Source - begin);
  231. }
  232. else if (isspace (c))
  233. {
  234. while (Source < SourceEnd &&
  235. *Source != '\r' &&
  236. *Source != '\n' &&
  237. isspace (*Source))
  238. Source++;
  239. return Token (Token::TK_WHITESPACE, begin, Source - begin);
  240. }
  241. else if (isdigit (c))
  242. {
  243. BOL = false;
  244. if (c == '0' && Source < SourceEnd && Source [0] == 'x') // hex numbers
  245. {
  246. Source++;
  247. while (Source < SourceEnd && isxdigit (*Source))
  248. Source++;
  249. }
  250. else
  251. while (Source < SourceEnd && isdigit (*Source))
  252. Source++;
  253. return Token (Token::TK_NUMBER, begin, Source - begin);
  254. }
  255. else if (c == '_' || isalnum (c))
  256. {
  257. BOL = false;
  258. while (Source < SourceEnd && (*Source == '_' || isalnum (*Source)))
  259. Source++;
  260. Token t (Token::TK_KEYWORD, begin, Source - begin);
  261. if (iExpand)
  262. t = ExpandMacro (t);
  263. return t;
  264. }
  265. else if (c == '"' || c == '\'')
  266. {
  267. BOL = false;
  268. while (Source < SourceEnd && *Source != c)
  269. {
  270. if (*Source == '\\')
  271. {
  272. Source++;
  273. if (Source >= SourceEnd)
  274. break;
  275. }
  276. if (*Source == '\n')
  277. Line++;
  278. Source++;
  279. }
  280. if (Source < SourceEnd)
  281. Source++;
  282. return Token (Token::TK_STRING, begin, Source - begin);
  283. }
  284. else if (c == '/' && *Source == '/')
  285. {
  286. BOL = false;
  287. Source++;
  288. while (Source < SourceEnd && *Source != '\r' && *Source != '\n')
  289. Source++;
  290. return Token (Token::TK_LINECOMMENT, begin, Source - begin);
  291. }
  292. else if (c == '/' && *Source == '*')
  293. {
  294. BOL = false;
  295. Source++;
  296. while (Source < SourceEnd && (Source [0] != '*' || Source [1] != '/'))
  297. {
  298. if (*Source == '\n')
  299. Line++;
  300. Source++;
  301. }
  302. if (Source < SourceEnd && *Source == '*')
  303. Source++;
  304. if (Source < SourceEnd && *Source == '/')
  305. Source++;
  306. return Token (Token::TK_COMMENT, begin, Source - begin);
  307. }
  308. else if (c == '#' && BOL)
  309. {
  310. // Skip all whitespaces after '#'
  311. while (Source < SourceEnd && isspace (*Source))
  312. Source++;
  313. while (Source < SourceEnd && !isspace (*Source))
  314. Source++;
  315. return Token (Token::TK_DIRECTIVE, begin, Source - begin);
  316. }
  317. else if (c == '\\' && Source < SourceEnd && (*Source == '\r' || *Source == '\n'))
  318. {
  319. // Treat backslash-newline as a whole token
  320. if (*Source == '\r')
  321. Source++;
  322. if (*Source == '\n')
  323. Source++;
  324. Line++;
  325. BOL = true;
  326. return Token (Token::TK_LINECONT, begin, Source - begin);
  327. }
  328. else
  329. {
  330. BOL = false;
  331. // Handle double-char operators here
  332. if (c == '>' && (*Source == '>' || *Source == '='))
  333. Source++;
  334. else if (c == '<' && (*Source == '<' || *Source == '='))
  335. Source++;
  336. else if (c == '!' && *Source == '=')
  337. Source++;
  338. else if (c == '=' && *Source == '=')
  339. Source++;
  340. else if ((c == '|' || c == '&' || c == '^') && *Source == c)
  341. Source++;
  342. return Token (Token::TK_PUNCTUATION, begin, Source - begin);
  343. }
  344. }
  345. CPreprocessor::Macro *CPreprocessor::IsDefined (const Token &iToken)
  346. {
  347. for (Macro *cur = MacroList; cur; cur = cur->Next)
  348. if (cur->Name == iToken)
  349. return cur;
  350. return NULL;
  351. }
  352. CPreprocessor::Token CPreprocessor::ExpandMacro (const Token &iToken)
  353. {
  354. Macro *cur = IsDefined (iToken);
  355. if (cur && !cur->Expanding)
  356. {
  357. Token *args = NULL;
  358. int nargs = 0;
  359. int old_line = Line;
  360. if (cur->NumArgs != 0)
  361. {
  362. Token t = GetArguments (nargs, args, cur->ExpandFunc ? false : true);
  363. if (t.Type == Token::TK_ERROR)
  364. {
  365. delete [] args;
  366. return t;
  367. }
  368. // Put the token back into the source pool; we'll handle it later
  369. if (t.String)
  370. {
  371. // Returned token should never be allocated on heap
  372. assert (t.Allocated == 0);
  373. Source = t.String;
  374. Line -= t.CountNL ();
  375. }
  376. }
  377. if (nargs > cur->NumArgs)
  378. {
  379. char tmp [60];
  380. snprintf (tmp, sizeof (tmp), "Macro `%.*s' passed %d arguments, but takes just %d",
  381. int (cur->Name.Length), cur->Name.String,
  382. nargs, cur->NumArgs);
  383. Error (old_line, tmp);
  384. return Token (Token::TK_ERROR);
  385. }
  386. Token t = cur->ExpandFunc ?
  387. cur->ExpandFunc (this, nargs, args) :
  388. cur->Expand (nargs, args, MacroList);
  389. t.AppendNL (Line - old_line);
  390. delete [] args;
  391. return t;
  392. }
  393. return iToken;
  394. }
  395. /**
  396. * Operator priority:
  397. * 0: Whole expression
  398. * 1: '(' ')'
  399. * 2: ||
  400. * 3: &&
  401. * 4: |
  402. * 5: ^
  403. * 6: &
  404. * 7: '==' '!='
  405. * 8: '<' '<=' '>' '>='
  406. * 9: '<<' '>>'
  407. * 10: '+' '-'
  408. * 11: '*' '/' '%'
  409. * 12: unary '+' '-' '!' '~'
  410. */
  411. CPreprocessor::Token CPreprocessor::GetExpression (
  412. Token &oResult, int iLine, int iOpPriority)
  413. {
  414. char tmp [40];
  415. do
  416. {
  417. oResult = GetToken (true);
  418. } while (oResult.Type == Token::TK_WHITESPACE ||
  419. oResult.Type == Token::TK_NEWLINE ||
  420. oResult.Type == Token::TK_COMMENT ||
  421. oResult.Type == Token::TK_LINECOMMENT ||
  422. oResult.Type == Token::TK_LINECONT);
  423. Token op (Token::TK_WHITESPACE, "", 0);
  424. // Handle unary operators here
  425. if (oResult.Type == Token::TK_PUNCTUATION && oResult.Length == 1)
  426. if (strchr ("+-!~", oResult.String [0]))
  427. {
  428. char uop = oResult.String [0];
  429. op = GetExpression (oResult, iLine, 12);
  430. long val;
  431. if (!GetValue (oResult, val, iLine))
  432. {
  433. snprintf (tmp, sizeof (tmp), "Unary '%c' not applicable", uop);
  434. Error (iLine, tmp, &oResult);
  435. return Token (Token::TK_ERROR);
  436. }
  437. if (uop == '-')
  438. oResult.SetValue (-val);
  439. else if (uop == '!')
  440. oResult.SetValue (!val);
  441. else if (uop == '~')
  442. oResult.SetValue (~val);
  443. }
  444. else if (oResult.String [0] == '(')
  445. {
  446. op = GetExpression (oResult, iLine, 1);
  447. if (op.Type == Token::TK_ERROR)
  448. return op;
  449. if (op.Type == Token::TK_EOS)
  450. {
  451. Error (iLine, "Unclosed parenthesis in #if expression");
  452. return Token (Token::TK_ERROR);
  453. }
  454. assert (op.Type == Token::TK_PUNCTUATION &&
  455. op.Length == 1 &&
  456. op.String [0] == ')');
  457. op = GetToken (true);
  458. }
  459. while (op.Type == Token::TK_WHITESPACE ||
  460. op.Type == Token::TK_NEWLINE ||
  461. op.Type == Token::TK_COMMENT ||
  462. op.Type == Token::TK_LINECOMMENT ||
  463. op.Type == Token::TK_LINECONT)
  464. op = GetToken (true);
  465. while (true)
  466. {
  467. if (op.Type != Token::TK_PUNCTUATION)
  468. return op;
  469. int prio = 0;
  470. if (op.Length == 1)
  471. switch (op.String [0])
  472. {
  473. case ')': return op;
  474. case '|': prio = 4; break;
  475. case '^': prio = 5; break;
  476. case '&': prio = 6; break;
  477. case '<':
  478. case '>': prio = 8; break;
  479. case '+':
  480. case '-': prio = 10; break;
  481. case '*':
  482. case '/':
  483. case '%': prio = 11; break;
  484. }
  485. else if (op.Length == 2)
  486. switch (op.String [0])
  487. {
  488. case '|': if (op.String [1] == '|') prio = 2; break;
  489. case '&': if (op.String [1] == '&') prio = 3; break;
  490. case '=': if (op.String [1] == '=') prio = 7; break;
  491. case '!': if (op.String [1] == '=') prio = 7; break;
  492. case '<':
  493. if (op.String [1] == '=')
  494. prio = 8;
  495. else if (op.String [1] == '<')
  496. prio = 9;
  497. break;
  498. case '>':
  499. if (op.String [1] == '=')
  500. prio = 8;
  501. else if (op.String [1] == '>')
  502. prio = 9;
  503. break;
  504. }
  505. if (!prio)
  506. {
  507. Error (iLine, "Expecting operator, got", &op);
  508. return Token (Token::TK_ERROR);
  509. }
  510. if (iOpPriority >= prio)
  511. return op;
  512. Token rop;
  513. Token nextop = GetExpression (rop, iLine, prio);
  514. long vlop, vrop;
  515. if (!GetValue (oResult, vlop, iLine))
  516. {
  517. snprintf (tmp, sizeof (tmp), "Left operand of '%.*s' is not a number",
  518. int (op.Length), op.String);
  519. Error (iLine, tmp, &oResult);
  520. return Token (Token::TK_ERROR);
  521. }
  522. if (!GetValue (rop, vrop, iLine))
  523. {
  524. snprintf (tmp, sizeof (tmp), "Right operand of '%.*s' is not a number",
  525. int (op.Length), op.String);
  526. Error (iLine, tmp, &rop);
  527. return Token (Token::TK_ERROR);
  528. }
  529. switch (op.String [0])
  530. {
  531. case '|':
  532. if (prio == 2)
  533. oResult.SetValue (vlop || vrop);
  534. else
  535. oResult.SetValue (vlop | vrop);
  536. break;
  537. case '&':
  538. if (prio == 3)
  539. oResult.SetValue (vlop && vrop);
  540. else
  541. oResult.SetValue (vlop & vrop);
  542. break;
  543. case '<':
  544. if (op.Length == 1)
  545. oResult.SetValue (vlop < vrop);
  546. else if (prio == 8)
  547. oResult.SetValue (vlop <= vrop);
  548. else if (prio == 9)
  549. oResult.SetValue (vlop << vrop);
  550. break;
  551. case '>':
  552. if (op.Length == 1)
  553. oResult.SetValue (vlop > vrop);
  554. else if (prio == 8)
  555. oResult.SetValue (vlop >= vrop);
  556. else if (prio == 9)
  557. oResult.SetValue (vlop >> vrop);
  558. break;
  559. case '^': oResult.SetValue (vlop ^ vrop); break;
  560. case '!': oResult.SetValue (vlop != vrop); break;
  561. case '=': oResult.SetValue (vlop == vrop); break;
  562. case '+': oResult.SetValue (vlop + vrop); break;
  563. case '-': oResult.SetValue (vlop - vrop); break;
  564. case '*': oResult.SetValue (vlop * vrop); break;
  565. case '/':
  566. case '%':
  567. if (vrop == 0)
  568. {
  569. Error (iLine, "Division by zero");
  570. return Token (Token::TK_ERROR);
  571. }
  572. if (op.String [0] == '/')
  573. oResult.SetValue (vlop / vrop);
  574. else
  575. oResult.SetValue (vlop % vrop);
  576. break;
  577. }
  578. op = nextop;
  579. }
  580. }
  581. bool CPreprocessor::GetValue (const Token &iToken, long &oValue, int iLine)
  582. {
  583. Token r;
  584. const Token *vt = &iToken;
  585. if ((vt->Type == Token::TK_KEYWORD ||
  586. vt->Type == Token::TK_TEXT ||
  587. vt->Type == Token::TK_NUMBER) &&
  588. !vt->String)
  589. {
  590. Error (iLine, "Trying to evaluate an empty expression");
  591. return false;
  592. }
  593. if (vt->Type == Token::TK_TEXT)
  594. {
  595. CPreprocessor cpp (iToken, iLine);
  596. cpp.MacroList = MacroList;
  597. Token t;
  598. t = cpp.GetExpression (r, iLine);
  599. cpp.MacroList = NULL;
  600. if (t.Type == Token::TK_ERROR)
  601. return false;
  602. if (t.Type != Token::TK_EOS)
  603. {
  604. Error (iLine, "Garbage after expression", &t);
  605. return false;
  606. }
  607. vt = &r;
  608. }
  609. Macro *m;
  610. switch (vt->Type)
  611. {
  612. case Token::TK_EOS:
  613. case Token::TK_ERROR:
  614. return false;
  615. case Token::TK_KEYWORD:
  616. // Try to expand the macro
  617. if ((m = IsDefined (*vt)) && !m->Expanding)
  618. {
  619. Token x = ExpandMacro (*vt);
  620. m->Expanding = true;
  621. bool rc = GetValue (x, oValue, iLine);
  622. m->Expanding = false;
  623. return rc;
  624. }
  625. // Undefined macro, "expand" to 0 (mimic cpp behaviour)
  626. oValue = 0;
  627. break;
  628. case Token::TK_TEXT:
  629. case Token::TK_NUMBER:
  630. if (!vt->GetValue (oValue))
  631. {
  632. Error (iLine, "Not a numeric expression", vt);
  633. return false;
  634. }
  635. break;
  636. default:
  637. Error (iLine, "Unexpected token", vt);
  638. return false;
  639. }
  640. return true;
  641. }
  642. CPreprocessor::Token CPreprocessor::GetArgument (Token &oArg, bool iExpand)
  643. {
  644. do
  645. {
  646. oArg = GetToken (iExpand);
  647. } while (oArg.Type == Token::TK_WHITESPACE ||
  648. oArg.Type == Token::TK_NEWLINE ||
  649. oArg.Type == Token::TK_COMMENT ||
  650. oArg.Type == Token::TK_LINECOMMENT ||
  651. oArg.Type == Token::TK_LINECONT);
  652. if (!iExpand)
  653. if (oArg.Type == Token::TK_EOS)
  654. return oArg;
  655. else if (oArg.Type == Token::TK_PUNCTUATION &&
  656. (oArg.String [0] == ',' ||
  657. oArg.String [0] == ')'))
  658. {
  659. Token t = oArg;
  660. oArg = Token (Token::TK_TEXT, "", 0);
  661. return t;
  662. }
  663. else if (oArg.Type != Token::TK_KEYWORD)
  664. {
  665. Error (Line, "Unexpected token", &oArg);
  666. return Token (Token::TK_ERROR);
  667. }
  668. UINT32 len = oArg.Length;
  669. while (true)
  670. {
  671. Token t = GetToken (iExpand);
  672. switch (t.Type)
  673. {
  674. case Token::TK_EOS:
  675. Error (Line, "Unfinished list of arguments");
  676. case Token::TK_ERROR:
  677. return Token (Token::TK_ERROR);
  678. case Token::TK_PUNCTUATION:
  679. if (t.String [0] == ',' ||
  680. t.String [0] == ')')
  681. {
  682. // Trim whitespaces at the end
  683. oArg.Length = len;
  684. return t;
  685. }
  686. break;
  687. case Token::TK_LINECONT:
  688. case Token::TK_COMMENT:
  689. case Token::TK_LINECOMMENT:
  690. case Token::TK_NEWLINE:
  691. // ignore these tokens
  692. continue;
  693. default:
  694. break;
  695. }
  696. if (!iExpand && t.Type != Token::TK_WHITESPACE)
  697. {
  698. Error (Line, "Unexpected token", &oArg);
  699. return Token (Token::TK_ERROR);
  700. }
  701. oArg.Append (t);
  702. if (t.Type != Token::TK_WHITESPACE)
  703. len = oArg.Length;
  704. }
  705. }
  706. CPreprocessor::Token CPreprocessor::GetArguments (int &oNumArgs, Token *&oArgs,
  707. bool iExpand)
  708. {
  709. Token args [MAX_MACRO_ARGS];
  710. int nargs = 0;
  711. // Suppose we'll leave by the wrong path
  712. oNumArgs = 0;
  713. oArgs = NULL;
  714. Token t;
  715. do
  716. {
  717. t = GetToken (iExpand);
  718. } while (t.Type == Token::TK_WHITESPACE ||
  719. t.Type == Token::TK_COMMENT ||
  720. t.Type == Token::TK_LINECOMMENT);
  721. if (t.Type != Token::TK_PUNCTUATION || t.String [0] != '(')
  722. {
  723. oNumArgs = 0;
  724. oArgs = NULL;
  725. return t;
  726. }
  727. while (true)
  728. {
  729. if (nargs == MAX_MACRO_ARGS)
  730. {
  731. Error (Line, "Too many arguments to macro");
  732. return Token (Token::TK_ERROR);
  733. }
  734. t = GetArgument (args [nargs++], iExpand);
  735. switch (t.Type)
  736. {
  737. case Token::TK_EOS:
  738. Error (Line, "Unfinished list of arguments");
  739. case Token::TK_ERROR:
  740. return Token (Token::TK_ERROR);
  741. case Token::TK_PUNCTUATION:
  742. if (t.String [0] == ')')
  743. {
  744. t = GetToken (iExpand);
  745. goto Done;
  746. } // otherwise we've got a ','
  747. break;
  748. default:
  749. Error (Line, "Unexpected token", &t);
  750. break;
  751. }
  752. }
  753. Done:
  754. oNumArgs = nargs;
  755. oArgs = new Token [nargs];
  756. for (int i = 0; i < nargs; i++)
  757. oArgs [i] = args [i];
  758. return t;
  759. }
  760. bool CPreprocessor::HandleDefine (Token &iBody, int iLine)
  761. {
  762. // Create an additional preprocessor to process macro body
  763. CPreprocessor cpp (iBody, iLine);
  764. Token t = cpp.GetToken (false);
  765. if (t.Type != Token::TK_KEYWORD)
  766. {
  767. Error (iLine, "Macro name expected after #define");
  768. return false;
  769. }
  770. Macro *m = new Macro (t);
  771. m->Body = iBody;
  772. t = cpp.GetArguments (m->NumArgs, m->Args, false);
  773. while (t.Type == Token::TK_WHITESPACE)
  774. t = cpp.GetToken (false);
  775. switch (t.Type)
  776. {
  777. case Token::TK_NEWLINE:
  778. case Token::TK_EOS:
  779. // Assign "" to token
  780. t = Token (Token::TK_TEXT, "", 0);
  781. break;
  782. case Token::TK_ERROR:
  783. delete m;
  784. return false;
  785. default:
  786. t.Type = Token::TK_TEXT;
  787. assert (t.String + t.Length == cpp.Source);
  788. t.Length = cpp.SourceEnd - t.String;
  789. break;
  790. }
  791. m->Value = t;
  792. m->Next = MacroList;
  793. MacroList = m;
  794. return true;
  795. }
  796. bool CPreprocessor::HandleUnDef (Token &iBody, int iLine)
  797. {
  798. CPreprocessor cpp (iBody, iLine);
  799. Token t = cpp.GetToken (false);
  800. if (t.Type != Token::TK_KEYWORD)
  801. {
  802. Error (iLine, "Expecting a macro name after #undef, got", &t);
  803. return false;
  804. }
  805. // Don't barf if macro does not exist - standard C behaviour
  806. Undef (t.String, t.Length);
  807. do
  808. {
  809. t = cpp.GetToken (false);
  810. } while (t.Type == Token::TK_WHITESPACE ||
  811. t.Type == Token::TK_COMMENT ||
  812. t.Type == Token::TK_LINECOMMENT);
  813. if (t.Type != Token::TK_EOS)
  814. Error (iLine, "Warning: Ignoring garbage after directive", &t);
  815. return true;
  816. }
  817. bool CPreprocessor::HandleIfDef (Token &iBody, int iLine)
  818. {
  819. if (EnableOutput & (1 << 31))
  820. {
  821. Error (iLine, "Too many embedded #if directives");
  822. return false;
  823. }
  824. CPreprocessor cpp (iBody, iLine);
  825. Token t = cpp.GetToken (false);
  826. if (t.Type != Token::TK_KEYWORD)
  827. {
  828. Error (iLine, "Expecting a macro name after #ifdef, got", &t);
  829. return false;
  830. }
  831. EnableOutput <<= 1;
  832. if (IsDefined (t))
  833. EnableOutput |= 1;
  834. do
  835. {
  836. t = cpp.GetToken (false);
  837. } while (t.Type == Token::TK_WHITESPACE ||
  838. t.Type == Token::TK_COMMENT ||
  839. t.Type == Token::TK_LINECOMMENT);
  840. if (t.Type != Token::TK_EOS)
  841. Error (iLine, "Warning: Ignoring garbage after directive", &t);
  842. return true;
  843. }
  844. CPreprocessor::Token CPreprocessor::ExpandDefined (CPreprocessor *iParent, int iNumArgs, Token *iArgs)
  845. {
  846. if (iNumArgs != 1)
  847. {
  848. iParent->Error (iParent->Line, "The defined() function takes exactly one argument");
  849. return Token (Token::TK_ERROR);
  850. }
  851. const char *v = iParent->IsDefined (iArgs [0]) ? "1" : "0";
  852. return Token (Token::TK_NUMBER, v, 1);
  853. }
  854. bool CPreprocessor::HandleIf (Token &iBody, int iLine)
  855. {
  856. Macro defined (Token (Token::TK_KEYWORD, "defined", 7));
  857. defined.Next = MacroList;
  858. defined.ExpandFunc = ExpandDefined;
  859. defined.NumArgs = 1;
  860. // Temporary add the defined() function to the macro list
  861. MacroList = &defined;
  862. long val;
  863. bool rc = GetValue (iBody, val, iLine);
  864. // Restore the macro list
  865. MacroList = defined.Next;
  866. defined.Next = NULL;
  867. if (!rc)
  868. return false;
  869. EnableOutput <<= 1;
  870. if (val)
  871. EnableOutput |= 1;
  872. return true;
  873. }
  874. bool CPreprocessor::HandleElse (Token &iBody, int iLine)
  875. {
  876. if (EnableOutput == 1)
  877. {
  878. Error (iLine, "#else without #if");
  879. return false;
  880. }
  881. // Negate the result of last #if
  882. EnableOutput ^= 1;
  883. if (iBody.Length)
  884. Error (iLine, "Warning: Ignoring garbage after #else", &iBody);
  885. return true;
  886. }
  887. bool CPreprocessor::HandleEndIf (Token &iBody, int iLine)
  888. {
  889. EnableOutput >>= 1;
  890. if (EnableOutput == 0)
  891. {
  892. Error (iLine, "#endif without #if");
  893. return false;
  894. }
  895. if (iBody.Length)
  896. Error (iLine, "Warning: Ignoring garbage after #endif", &iBody);
  897. return true;
  898. }
  899. CPreprocessor::Token CPreprocessor::HandleDirective (Token &iToken, int iLine)
  900. {
  901. // Analyze preprocessor directive
  902. const char *directive = iToken.String + 1;
  903. int dirlen = iToken.Length - 1;
  904. while (dirlen && isspace (*directive))
  905. dirlen--, directive++;
  906. int old_line = Line;
  907. // Collect the remaining part of the directive until EOL
  908. Token t, last;
  909. do
  910. {
  911. t = GetToken (false);
  912. if (t.Type == Token::TK_NEWLINE)
  913. {
  914. // No directive arguments
  915. last = t;
  916. t.Length = 0;
  917. goto Done;
  918. }
  919. } while (t.Type == Token::TK_WHITESPACE ||
  920. t.Type == Token::TK_LINECONT ||
  921. t.Type == Token::TK_COMMENT ||
  922. t.Type == Token::TK_LINECOMMENT);
  923. for (;;)
  924. {
  925. last = GetToken (false);
  926. switch (last.Type)
  927. {
  928. case Token::TK_EOS:
  929. // Can happen and is not an error
  930. goto Done;
  931. case Token::TK_LINECOMMENT:
  932. case Token::TK_COMMENT:
  933. // Skip comments in macros
  934. continue;
  935. case Token::TK_ERROR:
  936. return last;
  937. case Token::TK_LINECONT:
  938. continue;
  939. case Token::TK_NEWLINE:
  940. goto Done;
  941. default:
  942. break;
  943. }
  944. t.Append (last);
  945. t.Type = Token::TK_TEXT;
  946. }
  947. Done:
  948. #define IS_DIRECTIVE(s) \
  949. ((dirlen == sizeof (s) - 1) && (strncmp (directive, s, sizeof (s) - 1) == 0))
  950. bool rc;
  951. if (IS_DIRECTIVE ("define"))
  952. rc = HandleDefine (t, iLine);
  953. else if (IS_DIRECTIVE ("undef"))
  954. rc = HandleUnDef (t, iLine);
  955. else if (IS_DIRECTIVE ("ifdef"))
  956. rc = HandleIfDef (t, iLine);
  957. else if (IS_DIRECTIVE ("ifndef"))
  958. {
  959. rc = HandleIfDef (t, iLine);
  960. if (rc)
  961. EnableOutput ^= 1;
  962. }
  963. else if (IS_DIRECTIVE ("if"))
  964. rc = HandleIf (t, iLine);
  965. else if (IS_DIRECTIVE ("else"))
  966. rc = HandleElse (t, iLine);
  967. else if (IS_DIRECTIVE ("endif"))
  968. rc = HandleEndIf (t, iLine);
  969. else
  970. {
  971. //Error (iLine, "Unknown preprocessor directive", &iToken);
  972. //return Token (Token::TK_ERROR);
  973. // Unknown preprocessor directive, roll back and pass through
  974. Line = old_line;
  975. Source = iToken.String + iToken.Length;
  976. iToken.Type = Token::TK_TEXT;
  977. return iToken;
  978. }
  979. #undef IS_DIRECTIVE
  980. if (!rc)
  981. return Token (Token::TK_ERROR);
  982. return last;
  983. }
  984. void CPreprocessor::Define (const char *iMacroName, size_t iMacroNameLen,
  985. const char *iMacroValue, size_t iMacroValueLen)
  986. {
  987. Macro *m = new Macro (Token (Token::TK_KEYWORD, iMacroName, iMacroNameLen));
  988. m->Value = Token (Token::TK_TEXT, iMacroValue, iMacroValueLen);
  989. m->Next = MacroList;
  990. MacroList = m;
  991. }
  992. void CPreprocessor::Define (const char *iMacroName, size_t iMacroNameLen,
  993. long iMacroValue)
  994. {
  995. Macro *m = new Macro (Token (Token::TK_KEYWORD, iMacroName, iMacroNameLen));
  996. m->Value.SetValue (iMacroValue);
  997. m->Next = MacroList;
  998. MacroList = m;
  999. }
  1000. bool CPreprocessor::Undef (const char *iMacroName, size_t iMacroNameLen)
  1001. {
  1002. Macro **cur = &MacroList;
  1003. Token name (Token::TK_KEYWORD, iMacroName, iMacroNameLen);
  1004. while (*cur)
  1005. {
  1006. if ((*cur)->Name == name)
  1007. {
  1008. Macro *next = (*cur)->Next;
  1009. (*cur)->Next = NULL;
  1010. delete (*cur);
  1011. *cur = next;
  1012. return true;
  1013. }
  1014. cur = &(*cur)->Next;
  1015. }
  1016. return false;
  1017. }
  1018. CPreprocessor::Token CPreprocessor::Parse (const Token &iSource)
  1019. {
  1020. Source = iSource.String;
  1021. SourceEnd = Source + iSource.Length;
  1022. Line = 1;
  1023. BOL = true;
  1024. EnableOutput = 1;
  1025. // Accumulate output into this token
  1026. Token output (Token::TK_TEXT);
  1027. int empty_lines = 0;
  1028. // Enable output only if all embedded #if's were true
  1029. bool old_output_enabled = true;
  1030. bool output_enabled = true;
  1031. int output_disabled_line = 0;
  1032. while (Source < SourceEnd)
  1033. {
  1034. int old_line = Line;
  1035. Token t = GetToken (true);
  1036. NextToken:
  1037. switch (t.Type)
  1038. {
  1039. case Token::TK_ERROR:
  1040. return t;
  1041. case Token::TK_EOS:
  1042. return output; // Force termination
  1043. case Token::TK_COMMENT:
  1044. // C comments are replaced with single spaces.
  1045. if (output_enabled)
  1046. {
  1047. output.Append (" ", 1);
  1048. output.AppendNL (Line - old_line);
  1049. }
  1050. break;
  1051. case Token::TK_LINECOMMENT:
  1052. // C++ comments are ignored
  1053. continue;
  1054. case Token::TK_DIRECTIVE:
  1055. // Handle preprocessor directives
  1056. t = HandleDirective (t, old_line);
  1057. output_enabled = ((EnableOutput & (EnableOutput + 1)) == 0);
  1058. if (output_enabled != old_output_enabled)
  1059. {
  1060. if (output_enabled)
  1061. output.AppendNL (old_line - output_disabled_line);
  1062. else
  1063. output_disabled_line = old_line;
  1064. old_output_enabled = output_enabled;
  1065. }
  1066. if (output_enabled)
  1067. output.AppendNL (Line - old_line - t.CountNL ());
  1068. goto NextToken;
  1069. case Token::TK_LINECONT:
  1070. // Backslash-Newline sequences are deleted, no matter where.
  1071. empty_lines++;
  1072. break;
  1073. case Token::TK_NEWLINE:
  1074. if (empty_lines)
  1075. {
  1076. // Compensate for the backslash-newline combinations
  1077. // we have encountered, otherwise line numeration is broken
  1078. if (output_enabled)
  1079. output.AppendNL (empty_lines);
  1080. empty_lines = 0;
  1081. }
  1082. // Fallthrough to default
  1083. case Token::TK_WHITESPACE:
  1084. // Fallthrough to default
  1085. default:
  1086. // Passthrough all other tokens
  1087. if (output_enabled)
  1088. output.Append (t);
  1089. break;
  1090. }
  1091. }
  1092. if (EnableOutput != 1)
  1093. {
  1094. Error (Line, "Unclosed #if at end of source");
  1095. return Token (Token::TK_ERROR);
  1096. }
  1097. return output;
  1098. }
  1099. char *CPreprocessor::Parse (const char *iSource, size_t iLength, size_t &oLength)
  1100. {
  1101. Token retval = Parse (Token (Token::TK_TEXT, iSource, iLength));
  1102. if (retval.Type == Token::TK_ERROR)
  1103. return NULL;
  1104. oLength = retval.Length;
  1105. retval.Allocated = 0;
  1106. return retval.Buffer;
  1107. }
  1108. } // namespace CamelotEngine