ast.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _AST_H_
  23. #define _AST_H_
  24. class ExprEvalState;
  25. class Namespace;
  26. class SimObject;
  27. class SimGroup;
  28. /// Enable this #define if you are seeing the message "precompile size mismatch" in the console.
  29. /// This will help track down which node type is causing the error. It could be
  30. /// due to incorrect compiler optimization.
  31. //#define DEBUG_AST_NODES
  32. enum TypeReq
  33. {
  34. TypeReqNone,
  35. TypeReqUInt,
  36. TypeReqFloat,
  37. TypeReqString,
  38. TypeReqVar
  39. };
  40. /// Representation of a node for the scripting language parser.
  41. ///
  42. /// When the scripting language is evaluated, it is turned from a string representation,
  43. /// into a parse tree, thence into byte code, which is ultimately interpreted by the VM.
  44. ///
  45. /// This is the base class for the nodes in the parse tree. There are a great many subclasses,
  46. /// each representing a different language construct.
  47. struct StmtNode
  48. {
  49. StmtNode *next; ///< Next entry in parse tree.
  50. StmtNode();
  51. virtual ~StmtNode() {}
  52. /// @name next Accessors
  53. /// @{
  54. ///
  55. void append(StmtNode *next);
  56. StmtNode *getNext() const { return next; }
  57. /// @}
  58. /// @name Debug Info
  59. /// @{
  60. StringTableEntry dbgFileName; ///< Name of file this node is associated with.
  61. S32 dbgLineNumber; ///< Line number this node is associated with.
  62. #ifdef DEBUG_AST_NODES
  63. virtual String dbgStmtType() const = 0;
  64. #endif
  65. /// @}
  66. /// @name Breaking
  67. /// @{
  68. void addBreakCount();
  69. void addBreakLine(U32 ip);
  70. /// @}
  71. /// @name Compilation
  72. /// @{
  73. virtual U32 precompileStmt(U32 loopCount) = 0;
  74. virtual U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint) = 0;
  75. virtual void setPackage(StringTableEntry packageName);
  76. /// @}
  77. };
  78. /// Helper macro
  79. #ifndef DEBUG_AST_NODES
  80. # define DBG_STMT_TYPE(s) virtual String dbgStmtType() const { return String(#s); }
  81. #else
  82. # define DBG_STMT_TYPE(s)
  83. #endif
  84. struct BreakStmtNode : StmtNode
  85. {
  86. static BreakStmtNode *alloc( S32 lineNumber );
  87. U32 precompileStmt(U32 loopCount);
  88. U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
  89. DBG_STMT_TYPE(BreakStmtNode);
  90. };
  91. struct ContinueStmtNode : StmtNode
  92. {
  93. static ContinueStmtNode *alloc( S32 lineNumber );
  94. U32 precompileStmt(U32 loopCount);
  95. U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
  96. DBG_STMT_TYPE(ContinueStmtNode);
  97. };
  98. /// A mathematical expression.
  99. struct ExprNode : StmtNode
  100. {
  101. U32 precompileStmt(U32 loopCount);
  102. U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
  103. virtual U32 precompile(TypeReq type) = 0;
  104. virtual U32 compile(U32 *codeStream, U32 ip, TypeReq type) = 0;
  105. virtual TypeReq getPreferredType() = 0;
  106. };
  107. struct ReturnStmtNode : StmtNode
  108. {
  109. ExprNode *expr;
  110. static ReturnStmtNode *alloc( S32 lineNumber, ExprNode *expr );
  111. U32 precompileStmt(U32 loopCount);
  112. U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
  113. DBG_STMT_TYPE(ReturnStmtNode);
  114. };
  115. struct IfStmtNode : StmtNode
  116. {
  117. ExprNode *testExpr;
  118. StmtNode *ifBlock, *elseBlock;
  119. U32 endifOffset;
  120. U32 elseOffset;
  121. bool integer;
  122. bool propagate;
  123. static IfStmtNode *alloc( S32 lineNumber, ExprNode *testExpr, StmtNode *ifBlock, StmtNode *elseBlock, bool propagateThrough );
  124. void propagateSwitchExpr(ExprNode *left, bool string);
  125. ExprNode *getSwitchOR(ExprNode *left, ExprNode *list, bool string);
  126. U32 precompileStmt(U32 loopCount);
  127. U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
  128. DBG_STMT_TYPE(IfStmtNode);
  129. };
  130. struct LoopStmtNode : StmtNode
  131. {
  132. ExprNode *testExpr;
  133. ExprNode *initExpr;
  134. ExprNode *endLoopExpr;
  135. StmtNode *loopBlock;
  136. bool isDoLoop;
  137. U32 breakOffset;
  138. U32 continueOffset;
  139. U32 loopBlockStartOffset;
  140. bool integer;
  141. static LoopStmtNode *alloc( S32 lineNumber, ExprNode *testExpr, ExprNode *initExpr, ExprNode *endLoopExpr, StmtNode *loopBlock, bool isDoLoop );
  142. U32 precompileStmt(U32 loopCount);
  143. U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
  144. DBG_STMT_TYPE(LoopStmtNode);
  145. };
  146. /// A "foreach" statement.
  147. struct IterStmtNode : StmtNode
  148. {
  149. /// Local variable name to use for the container element.
  150. StringTableEntry varName;
  151. /// Expression evaluating to a SimSet object.
  152. ExprNode* containerExpr;
  153. /// The statement body.
  154. StmtNode* body;
  155. /// If true, this is a 'foreach$'.
  156. bool isStringIter;
  157. /// Bytecode size of body statement. Set by precompileStmt.
  158. U32 bodySize;
  159. static IterStmtNode* alloc( S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter );
  160. U32 precompileStmt( U32 loopCount );
  161. U32 compileStmt( U32* codeStream, U32 ip, U32 continuePoint, U32 breakPoint );
  162. };
  163. /// A binary mathematical expression (ie, left op right).
  164. struct BinaryExprNode : ExprNode
  165. {
  166. S32 op;
  167. ExprNode *left;
  168. ExprNode *right;
  169. };
  170. struct FloatBinaryExprNode : BinaryExprNode
  171. {
  172. static FloatBinaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *left, ExprNode *right );
  173. U32 precompile(TypeReq type);
  174. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  175. TypeReq getPreferredType();
  176. DBG_STMT_TYPE(FloatBinaryExprNode);
  177. };
  178. struct ConditionalExprNode : ExprNode
  179. {
  180. ExprNode *testExpr;
  181. ExprNode *trueExpr;
  182. ExprNode *falseExpr;
  183. bool integer;
  184. static ConditionalExprNode *alloc( S32 lineNumber, ExprNode *testExpr, ExprNode *trueExpr, ExprNode *falseExpr );
  185. virtual U32 precompile(TypeReq type);
  186. virtual U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  187. virtual TypeReq getPreferredType();
  188. DBG_STMT_TYPE(ConditionalExprNode);
  189. };
  190. struct IntBinaryExprNode : BinaryExprNode
  191. {
  192. TypeReq subType;
  193. U32 operand;
  194. static IntBinaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *left, ExprNode *right );
  195. void getSubTypeOperand();
  196. U32 precompile(TypeReq type);
  197. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  198. TypeReq getPreferredType();
  199. DBG_STMT_TYPE(IntBinaryExprNode);
  200. };
  201. struct StreqExprNode : BinaryExprNode
  202. {
  203. bool eq;
  204. static StreqExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right, bool eq );
  205. U32 precompile(TypeReq type);
  206. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  207. TypeReq getPreferredType();
  208. DBG_STMT_TYPE(StreqExprNode);
  209. };
  210. struct StrcatExprNode : BinaryExprNode
  211. {
  212. int appendChar;
  213. static StrcatExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right, int appendChar );
  214. U32 precompile(TypeReq type);
  215. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  216. TypeReq getPreferredType();
  217. DBG_STMT_TYPE(StrcatExprNode);
  218. };
  219. struct CommaCatExprNode : BinaryExprNode
  220. {
  221. static CommaCatExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right );
  222. U32 precompile(TypeReq type);
  223. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  224. TypeReq getPreferredType();
  225. DBG_STMT_TYPE(CommaCatExprNode);
  226. };
  227. struct IntUnaryExprNode : ExprNode
  228. {
  229. S32 op;
  230. ExprNode *expr;
  231. bool integer;
  232. static IntUnaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *expr );
  233. U32 precompile(TypeReq type);
  234. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  235. TypeReq getPreferredType();
  236. DBG_STMT_TYPE(IntUnaryExprNode);
  237. };
  238. struct FloatUnaryExprNode : ExprNode
  239. {
  240. S32 op;
  241. ExprNode *expr;
  242. static FloatUnaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *expr );
  243. U32 precompile(TypeReq type);
  244. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  245. TypeReq getPreferredType();
  246. DBG_STMT_TYPE(FloatUnaryExprNode);
  247. };
  248. struct VarNode : ExprNode
  249. {
  250. StringTableEntry varName;
  251. ExprNode *arrayIndex;
  252. static VarNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex );
  253. U32 precompile(TypeReq type);
  254. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  255. TypeReq getPreferredType();
  256. DBG_STMT_TYPE(VarNode);
  257. };
  258. struct IntNode : ExprNode
  259. {
  260. S32 value;
  261. U32 index; // if it's converted to float/string
  262. static IntNode *alloc( S32 lineNumber, S32 value );
  263. U32 precompile(TypeReq type);
  264. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  265. TypeReq getPreferredType();
  266. DBG_STMT_TYPE(IntNode);
  267. };
  268. struct FloatNode : ExprNode
  269. {
  270. F64 value;
  271. U32 index;
  272. static FloatNode *alloc( S32 lineNumber, F64 value );
  273. U32 precompile(TypeReq type);
  274. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  275. TypeReq getPreferredType();
  276. DBG_STMT_TYPE(FloatNode);
  277. };
  278. struct StrConstNode : ExprNode
  279. {
  280. char *str;
  281. F64 fVal;
  282. U32 index;
  283. bool tag;
  284. bool doc; // Specifies that this string is a documentation block.
  285. static StrConstNode *alloc( S32 lineNumber, char *str, bool tag, bool doc = false );
  286. U32 precompile(TypeReq type);
  287. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  288. TypeReq getPreferredType();
  289. DBG_STMT_TYPE(StrConstNode);
  290. };
  291. struct ConstantNode : ExprNode
  292. {
  293. StringTableEntry value;
  294. F64 fVal;
  295. U32 index;
  296. static ConstantNode *alloc( S32 lineNumber, StringTableEntry value );
  297. U32 precompile(TypeReq type);
  298. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  299. TypeReq getPreferredType();
  300. DBG_STMT_TYPE(ConstantNode);
  301. };
  302. struct AssignExprNode : ExprNode
  303. {
  304. StringTableEntry varName;
  305. ExprNode *expr;
  306. ExprNode *arrayIndex;
  307. TypeReq subType;
  308. static AssignExprNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr );
  309. U32 precompile(TypeReq type);
  310. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  311. TypeReq getPreferredType();
  312. DBG_STMT_TYPE(AssignExprNode);
  313. };
  314. struct AssignDecl
  315. {
  316. S32 lineNumber;
  317. S32 token;
  318. ExprNode *expr;
  319. bool integer;
  320. };
  321. struct AssignOpExprNode : ExprNode
  322. {
  323. StringTableEntry varName;
  324. ExprNode *expr;
  325. ExprNode *arrayIndex;
  326. S32 op;
  327. U32 operand;
  328. TypeReq subType;
  329. static AssignOpExprNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr, S32 op );
  330. U32 precompile(TypeReq type);
  331. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  332. TypeReq getPreferredType();
  333. DBG_STMT_TYPE(AssignOpExprNode);
  334. };
  335. struct TTagSetStmtNode : StmtNode
  336. {
  337. StringTableEntry tag;
  338. ExprNode *valueExpr;
  339. ExprNode *stringExpr;
  340. static TTagSetStmtNode *alloc( S32 lineNumber, StringTableEntry tag, ExprNode *valueExpr, ExprNode *stringExpr );
  341. U32 precompileStmt(U32 loopCount);
  342. U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
  343. DBG_STMT_TYPE(TTagSetStmtNode);
  344. };
  345. struct TTagDerefNode : ExprNode
  346. {
  347. ExprNode *expr;
  348. static TTagDerefNode *alloc( S32 lineNumber, ExprNode *expr );
  349. U32 precompile(TypeReq type);
  350. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  351. TypeReq getPreferredType();
  352. DBG_STMT_TYPE(TTagDerefNode);
  353. };
  354. struct TTagExprNode : ExprNode
  355. {
  356. StringTableEntry tag;
  357. static TTagExprNode *alloc( S32 lineNumber, StringTableEntry tag );
  358. U32 precompile(TypeReq type);
  359. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  360. TypeReq getPreferredType();
  361. DBG_STMT_TYPE(TTagExprNode);
  362. };
  363. struct FuncCallExprNode : ExprNode
  364. {
  365. StringTableEntry funcName;
  366. StringTableEntry nameSpace;
  367. ExprNode *args;
  368. U32 callType;
  369. enum {
  370. FunctionCall,
  371. MethodCall,
  372. ParentCall
  373. };
  374. static FuncCallExprNode *alloc( S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode *args, bool dot );
  375. U32 precompile(TypeReq type);
  376. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  377. TypeReq getPreferredType();
  378. DBG_STMT_TYPE(FuncCallExprNode);
  379. };
  380. struct AssertCallExprNode : ExprNode
  381. {
  382. ExprNode *testExpr;
  383. const char *message;
  384. U32 messageIndex;
  385. static AssertCallExprNode *alloc( S32 lineNumber, ExprNode *testExpr, const char *message );
  386. U32 precompile(TypeReq type);
  387. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  388. TypeReq getPreferredType();
  389. DBG_STMT_TYPE(AssertCallExprNode);
  390. };
  391. struct SlotDecl
  392. {
  393. S32 lineNumber;
  394. ExprNode *object;
  395. StringTableEntry slotName;
  396. ExprNode *array;
  397. };
  398. struct SlotAccessNode : ExprNode
  399. {
  400. ExprNode *objectExpr, *arrayExpr;
  401. StringTableEntry slotName;
  402. static SlotAccessNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName );
  403. U32 precompile(TypeReq type);
  404. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  405. TypeReq getPreferredType();
  406. DBG_STMT_TYPE(SlotAccessNode);
  407. };
  408. struct InternalSlotDecl
  409. {
  410. S32 lineNumber;
  411. ExprNode *object;
  412. ExprNode *slotExpr;
  413. bool recurse;
  414. };
  415. struct InternalSlotAccessNode : ExprNode
  416. {
  417. ExprNode *objectExpr, *slotExpr;
  418. bool recurse;
  419. static InternalSlotAccessNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *slotExpr, bool recurse );
  420. U32 precompile(TypeReq type);
  421. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  422. TypeReq getPreferredType();
  423. DBG_STMT_TYPE(InternalSlotAccessNode);
  424. };
  425. struct SlotAssignNode : ExprNode
  426. {
  427. ExprNode *objectExpr, *arrayExpr;
  428. StringTableEntry slotName;
  429. ExprNode *valueExpr;
  430. U32 typeID;
  431. static SlotAssignNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName, ExprNode *valueExpr, U32 typeID = -1 );
  432. U32 precompile(TypeReq type);
  433. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  434. TypeReq getPreferredType();
  435. DBG_STMT_TYPE(SlotAssignNode);
  436. };
  437. struct SlotAssignOpNode : ExprNode
  438. {
  439. ExprNode *objectExpr, *arrayExpr;
  440. StringTableEntry slotName;
  441. S32 op;
  442. ExprNode *valueExpr;
  443. U32 operand;
  444. TypeReq subType;
  445. static SlotAssignOpNode *alloc( S32 lineNumber, ExprNode *objectExpr, StringTableEntry slotName, ExprNode *arrayExpr, S32 op, ExprNode *valueExpr );
  446. U32 precompile(TypeReq type);
  447. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  448. TypeReq getPreferredType();
  449. DBG_STMT_TYPE(SlotAssignOpNode);
  450. };
  451. struct ObjectDeclNode : ExprNode
  452. {
  453. ExprNode *classNameExpr;
  454. StringTableEntry parentObject;
  455. ExprNode *objectNameExpr;
  456. ExprNode *argList;
  457. SlotAssignNode *slotDecls;
  458. ObjectDeclNode *subObjects;
  459. bool isDatablock;
  460. U32 failOffset;
  461. bool isClassNameInternal;
  462. bool isSingleton;
  463. static ObjectDeclNode *alloc( S32 lineNumber, ExprNode *classNameExpr, ExprNode *objectNameExpr, ExprNode *argList, StringTableEntry parentObject, SlotAssignNode *slotDecls, ObjectDeclNode *subObjects, bool isDatablock, bool classNameInternal, bool isSingleton );
  464. U32 precompile(TypeReq type);
  465. U32 precompileSubObject(bool);
  466. U32 compile(U32 *codeStream, U32 ip, TypeReq type);
  467. U32 compileSubObject(U32 *codeStream, U32 ip, bool);
  468. TypeReq getPreferredType();
  469. DBG_STMT_TYPE(ObjectDeclNode);
  470. };
  471. struct ObjectBlockDecl
  472. {
  473. SlotAssignNode *slots;
  474. ObjectDeclNode *decls;
  475. };
  476. struct FunctionDeclStmtNode : StmtNode
  477. {
  478. StringTableEntry fnName;
  479. VarNode *args;
  480. StmtNode *stmts;
  481. StringTableEntry nameSpace;
  482. StringTableEntry package;
  483. U32 endOffset;
  484. U32 argc;
  485. static FunctionDeclStmtNode *alloc( S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode *args, StmtNode *stmts );
  486. U32 precompileStmt(U32 loopCount);
  487. U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
  488. void setPackage(StringTableEntry packageName);
  489. DBG_STMT_TYPE(FunctionDeclStmtNode);
  490. };
  491. extern StmtNode *gStatementList;
  492. extern void createFunction(const char *fnName, VarNode *args, StmtNode *statements);
  493. extern ExprEvalState gEvalState;
  494. extern bool lookupFunction(const char *fnName, VarNode **args, StmtNode **statements);
  495. typedef const char *(*cfunc)(S32 argc, char **argv);
  496. extern bool lookupCFunction(const char *fnName, cfunc *f);
  497. #endif