rubycodegen.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. /*
  2. * 2007 Victor Hugo Borja <vic@rubyforge.org>
  3. * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
  4. */
  5. /* This file is part of Ragel.
  6. *
  7. * Ragel is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Ragel is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Ragel; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. #include <iomanip>
  22. #include <sstream>
  23. #include "redfsm.h"
  24. #include "gendata.h"
  25. #include "ragel.h"
  26. #include "rubycodegen.h"
  27. #include "pcheck.h"
  28. #include "vector.h"
  29. #include "version.h"
  30. #include "common.h"
  31. #include "ragel.h"
  32. #include "rubytable.h"
  33. #include "rubyftable.h"
  34. #include "rubyflat.h"
  35. #include "rubyfflat.h"
  36. #include "rbxgoto.h"
  37. using std::ostream;
  38. using std::ostringstream;
  39. using std::string;
  40. using std::cerr;
  41. using std::endl;
  42. using std::istream;
  43. using std::ifstream;
  44. using std::ostream;
  45. using std::ios;
  46. using std::cin;
  47. using std::cout;
  48. using std::cerr;
  49. using std::endl;
  50. /* Target ruby impl */
  51. /* Target language and output style. */
  52. extern CodeStyle codeStyle;
  53. extern int numSplitPartitions;
  54. extern bool noLineDirectives;
  55. /*
  56. * Callbacks invoked by the XML data parser.
  57. */
  58. void rubyLineDirective( ostream &out, const char *fileName, int line )
  59. {
  60. if ( noLineDirectives )
  61. return;
  62. /* Write a comment containing line info. */
  63. out << "# line " << line << " \"";
  64. for ( const char *pc = fileName; *pc != 0; pc++ ) {
  65. if ( *pc == '\\' )
  66. out << "\\\\";
  67. else
  68. out << *pc;
  69. }
  70. out << "\"\n";
  71. }
  72. void RubyCodeGen::genLineDirective( ostream &out )
  73. {
  74. std::streambuf *sbuf = out.rdbuf();
  75. output_filter *filter = static_cast<output_filter*>(sbuf);
  76. rubyLineDirective( out, filter->fileName, filter->line + 1 );
  77. }
  78. string RubyCodeGen::DATA_PREFIX()
  79. {
  80. if ( !noPrefix )
  81. return FSM_NAME() + "_";
  82. return "";
  83. }
  84. std::ostream &RubyCodeGen::STATIC_VAR( string type, string name )
  85. {
  86. out <<
  87. "class << self\n"
  88. " attr_accessor :" << name << "\n"
  89. "end\n"
  90. "self." << name;
  91. return out;
  92. }
  93. std::ostream &RubyCodeGen::OPEN_ARRAY( string type, string name )
  94. {
  95. out <<
  96. "class << self\n"
  97. " attr_accessor :" << name << "\n"
  98. " private :" << name << ", :" << name << "=\n"
  99. "end\n"
  100. "self." << name << " = [\n";
  101. return out;
  102. }
  103. std::ostream &RubyCodeGen::CLOSE_ARRAY()
  104. {
  105. out << "]\n";
  106. return out;
  107. }
  108. string RubyCodeGen::ARR_OFF( string ptr, string offset )
  109. {
  110. return ptr + "[" + offset + "]";
  111. }
  112. string RubyCodeGen::NULL_ITEM()
  113. {
  114. return "nil";
  115. }
  116. string RubyCodeGen::P()
  117. {
  118. ostringstream ret;
  119. if ( pExpr == 0 )
  120. ret << "p";
  121. else {
  122. //ret << "(";
  123. INLINE_LIST( ret, pExpr, 0, false );
  124. //ret << ")";
  125. }
  126. return ret.str();
  127. }
  128. string RubyCodeGen::PE()
  129. {
  130. ostringstream ret;
  131. if ( peExpr == 0 )
  132. ret << "pe";
  133. else {
  134. //ret << "(";
  135. INLINE_LIST( ret, peExpr, 0, false );
  136. //ret << ")";
  137. }
  138. return ret.str();
  139. }
  140. string RubyCodeGen::vEOF()
  141. {
  142. ostringstream ret;
  143. if ( eofExpr == 0 )
  144. ret << "eof";
  145. else {
  146. //ret << "(";
  147. INLINE_LIST( ret, eofExpr, 0, false );
  148. //ret << ")";
  149. }
  150. return ret.str();
  151. }
  152. string RubyCodeGen::vCS()
  153. {
  154. ostringstream ret;
  155. if ( csExpr == 0 )
  156. ret << ACCESS() << "cs";
  157. else {
  158. //ret << "(";
  159. INLINE_LIST( ret, csExpr, 0, false );
  160. //ret << ")";
  161. }
  162. return ret.str();
  163. }
  164. string RubyCodeGen::TOP()
  165. {
  166. ostringstream ret;
  167. if ( topExpr == 0 )
  168. ret << ACCESS() + "top";
  169. else {
  170. //ret << "(";
  171. INLINE_LIST( ret, topExpr, 0, false );
  172. //ret << ")";
  173. }
  174. return ret.str();
  175. }
  176. string RubyCodeGen::STACK()
  177. {
  178. ostringstream ret;
  179. if ( stackExpr == 0 )
  180. ret << ACCESS() + "stack";
  181. else {
  182. //ret << "(";
  183. INLINE_LIST( ret, stackExpr, 0, false );
  184. //ret << ")";
  185. }
  186. return ret.str();
  187. }
  188. string RubyCodeGen::ACT()
  189. {
  190. ostringstream ret;
  191. if ( actExpr == 0 )
  192. ret << ACCESS() + "act";
  193. else {
  194. //ret << "(";
  195. INLINE_LIST( ret, actExpr, 0, false );
  196. //ret << ")";
  197. }
  198. return ret.str();
  199. }
  200. string RubyCodeGen::TOKSTART()
  201. {
  202. ostringstream ret;
  203. if ( tokstartExpr == 0 )
  204. ret << ACCESS() + "ts";
  205. else {
  206. //ret << "(";
  207. INLINE_LIST( ret, tokstartExpr, 0, false );
  208. //ret << ")";
  209. }
  210. return ret.str();
  211. }
  212. string RubyCodeGen::TOKEND()
  213. {
  214. ostringstream ret;
  215. if ( tokendExpr == 0 )
  216. ret << ACCESS() + "te";
  217. else {
  218. //ret << "(";
  219. INLINE_LIST( ret, tokendExpr, 0, false );
  220. //ret << ")";
  221. }
  222. return ret.str();
  223. }
  224. string RubyCodeGen::DATA()
  225. {
  226. ostringstream ret;
  227. if ( dataExpr == 0 )
  228. ret << ACCESS() + "data";
  229. else {
  230. //ret << "(";
  231. INLINE_LIST( ret, dataExpr, 0, false );
  232. //ret << ")";
  233. }
  234. return ret.str();
  235. }
  236. /* Write out the fsm name. */
  237. string RubyCodeGen::FSM_NAME()
  238. {
  239. return fsmName;
  240. }
  241. void RubyCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
  242. {
  243. /* Write the preprocessor line info for going into the source file. */
  244. rubyLineDirective( ret, action->loc.fileName, action->loc.line );
  245. /* Write the block and close it off. */
  246. ret << " begin\n";
  247. INLINE_LIST( ret, action->inlineList, targState, inFinish );
  248. ret << " end\n";
  249. }
  250. string RubyCodeGen::GET_WIDE_KEY()
  251. {
  252. if ( redFsm->anyConditions() )
  253. return "_widec";
  254. else
  255. return GET_KEY();
  256. }
  257. string RubyCodeGen::GET_WIDE_KEY( RedStateAp *state )
  258. {
  259. if ( state->stateCondList.length() > 0 )
  260. return "_widec";
  261. else
  262. return GET_KEY();
  263. }
  264. string RubyCodeGen::GET_KEY()
  265. {
  266. ostringstream ret;
  267. if ( getKeyExpr != 0 ) {
  268. /* Emit the user supplied method of retrieving the key. */
  269. ret << "(";
  270. INLINE_LIST( ret, getKeyExpr, 0, false );
  271. ret << ")";
  272. }
  273. else {
  274. /* Expression for retrieving the key, use dereference and read ordinal,
  275. * for compatibility with Ruby 1.9. */
  276. ret << DATA() << "[" << P() << "].ord";
  277. }
  278. return ret.str();
  279. }
  280. string RubyCodeGen::KEY( Key key )
  281. {
  282. ostringstream ret;
  283. if ( keyOps->isSigned || !hostLang->explicitUnsigned )
  284. ret << key.getVal();
  285. else
  286. ret << (unsigned long) key.getVal();
  287. return ret.str();
  288. }
  289. /* Write out level number of tabs. Makes the nested binary search nice
  290. * looking. */
  291. string RubyCodeGen::TABS( int level )
  292. {
  293. string result;
  294. while ( level-- > 0 )
  295. result += "\t";
  296. return result;
  297. }
  298. string RubyCodeGen::INT( int i )
  299. {
  300. ostringstream ret;
  301. ret << i;
  302. return ret.str();
  303. }
  304. void RubyCodeGen::CONDITION( ostream &ret, GenAction *condition )
  305. {
  306. ret << "\n";
  307. rubyLineDirective( ret, condition->loc.fileName, condition->loc.line );
  308. INLINE_LIST( ret, condition->inlineList, 0, false );
  309. }
  310. /* Emit the alphabet data type. */
  311. string RubyCodeGen::ALPH_TYPE()
  312. {
  313. string ret = keyOps->alphType->data1;
  314. if ( keyOps->alphType->data2 != 0 ) {
  315. ret += " ";
  316. ret += + keyOps->alphType->data2;
  317. }
  318. return ret;
  319. }
  320. /* Emit the alphabet data type. */
  321. string RubyCodeGen::WIDE_ALPH_TYPE()
  322. {
  323. string ret;
  324. if ( redFsm->maxKey <= keyOps->maxKey )
  325. ret = ALPH_TYPE();
  326. else {
  327. long long maxKeyVal = redFsm->maxKey.getLongLong();
  328. HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
  329. assert( wideType != 0 );
  330. ret = wideType->data1;
  331. if ( wideType->data2 != 0 ) {
  332. ret += " ";
  333. ret += wideType->data2;
  334. }
  335. }
  336. return ret;
  337. }
  338. string RubyCodeGen::ARRAY_TYPE( unsigned long maxVal )
  339. {
  340. long long maxValLL = (long long) maxVal;
  341. HostType *arrayType = keyOps->typeSubsumes( maxValLL );
  342. assert( arrayType != 0 );
  343. string ret = arrayType->data1;
  344. if ( arrayType->data2 != 0 ) {
  345. ret += " ";
  346. ret += arrayType->data2;
  347. }
  348. return ret;
  349. }
  350. /* Write out the array of actions. */
  351. std::ostream &RubyCodeGen::ACTIONS_ARRAY()
  352. {
  353. START_ARRAY_LINE();
  354. int totalActions = 0;
  355. ARRAY_ITEM( INT(0), ++totalActions, false );
  356. for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
  357. /* Write out the length, which will never be the last character. */
  358. ARRAY_ITEM( INT(act->key.length()), ++totalActions, false );
  359. for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
  360. ARRAY_ITEM( INT(item->value->actionId), ++totalActions, (act.last() && item.last()) );
  361. }
  362. }
  363. END_ARRAY_LINE();
  364. return out;
  365. }
  366. void RubyCodeGen::STATE_IDS()
  367. {
  368. if ( redFsm->startState != 0 )
  369. STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
  370. if ( !noFinal )
  371. STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
  372. if ( !noError )
  373. STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
  374. out << "\n";
  375. if ( !noEntry && entryPointNames.length() > 0 ) {
  376. for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
  377. STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
  378. " = " << entryPointIds[en.pos()] << ";\n";
  379. }
  380. out << "\n";
  381. }
  382. }
  383. std::ostream &RubyCodeGen::START_ARRAY_LINE()
  384. {
  385. out << "\t";
  386. return out;
  387. }
  388. std::ostream &RubyCodeGen::ARRAY_ITEM( string item, int count, bool last )
  389. {
  390. out << item;
  391. if ( !last )
  392. {
  393. out << ", ";
  394. if ( count % IALL == 0 )
  395. {
  396. END_ARRAY_LINE();
  397. START_ARRAY_LINE();
  398. }
  399. }
  400. return out;
  401. }
  402. std::ostream &RubyCodeGen::END_ARRAY_LINE()
  403. {
  404. out << "\n";
  405. return out;
  406. }
  407. /* Emit the offset of the start state as a decimal integer. */
  408. string RubyCodeGen::START_STATE_ID()
  409. {
  410. ostringstream ret;
  411. ret << redFsm->startState->id;
  412. return ret.str();
  413. };
  414. string RubyCodeGen::ERROR_STATE()
  415. {
  416. ostringstream ret;
  417. if ( redFsm->errState != 0 )
  418. ret << redFsm->errState->id;
  419. else
  420. ret << "-1";
  421. return ret.str();
  422. }
  423. string RubyCodeGen::FIRST_FINAL_STATE()
  424. {
  425. ostringstream ret;
  426. if ( redFsm->firstFinState != 0 )
  427. ret << redFsm->firstFinState->id;
  428. else
  429. ret << redFsm->nextStateId;
  430. return ret.str();
  431. }
  432. string RubyCodeGen::ACCESS()
  433. {
  434. ostringstream ret;
  435. if ( accessExpr != 0 )
  436. INLINE_LIST( ret, accessExpr, 0, false );
  437. return ret.str();
  438. }
  439. /* Write out an inline tree structure. Walks the list and possibly calls out
  440. * to virtual functions than handle language specific items in the tree. */
  441. void RubyCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
  442. int targState, bool inFinish )
  443. {
  444. for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
  445. switch ( item->type ) {
  446. case GenInlineItem::Text:
  447. ret << item->data;
  448. break;
  449. case GenInlineItem::Goto:
  450. GOTO( ret, item->targState->id, inFinish );
  451. break;
  452. case GenInlineItem::Call:
  453. CALL( ret, item->targState->id, targState, inFinish );
  454. break;
  455. case GenInlineItem::Next:
  456. NEXT( ret, item->targState->id, inFinish );
  457. break;
  458. case GenInlineItem::Ret:
  459. RET( ret, inFinish );
  460. break;
  461. case GenInlineItem::PChar:
  462. ret << P();
  463. break;
  464. case GenInlineItem::Char:
  465. ret << GET_KEY();
  466. break;
  467. case GenInlineItem::Hold:
  468. ret << P() << " = " << P() << " - 1;";
  469. break;
  470. case GenInlineItem::Exec:
  471. EXEC( ret, item, targState, inFinish );
  472. break;
  473. case GenInlineItem::Curs:
  474. ret << "(_ps)";
  475. break;
  476. case GenInlineItem::Targs:
  477. ret << "(" << vCS() << ")";
  478. break;
  479. case GenInlineItem::Entry:
  480. ret << item->targState->id;
  481. break;
  482. case GenInlineItem::GotoExpr:
  483. GOTO_EXPR( ret, item, inFinish );
  484. break;
  485. case GenInlineItem::CallExpr:
  486. CALL_EXPR( ret, item, targState, inFinish );
  487. break;
  488. case GenInlineItem::NextExpr:
  489. NEXT_EXPR( ret, item, inFinish );
  490. break;
  491. case GenInlineItem::LmSwitch:
  492. LM_SWITCH( ret, item, targState, inFinish );
  493. break;
  494. case GenInlineItem::LmSetActId:
  495. SET_ACT( ret, item );
  496. break;
  497. case GenInlineItem::LmSetTokEnd:
  498. SET_TOKEND( ret, item );
  499. break;
  500. case GenInlineItem::LmGetTokEnd:
  501. GET_TOKEND( ret, item );
  502. break;
  503. case GenInlineItem::LmInitTokStart:
  504. INIT_TOKSTART( ret, item );
  505. break;
  506. case GenInlineItem::LmInitAct:
  507. INIT_ACT( ret, item );
  508. break;
  509. case GenInlineItem::LmSetTokStart:
  510. SET_TOKSTART( ret, item );
  511. break;
  512. case GenInlineItem::SubAction:
  513. SUB_ACTION( ret, item, targState, inFinish );
  514. break;
  515. case GenInlineItem::Break:
  516. BREAK( ret, targState );
  517. break;
  518. }
  519. }
  520. }
  521. void RubyCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
  522. {
  523. /* The parser gives fexec two children. The double brackets are for D
  524. * code. If the inline list is a single word it will get interpreted as a
  525. * C-style cast by the D compiler. */
  526. ret << " begin " << P() << " = ((";
  527. INLINE_LIST( ret, item->children, targState, inFinish );
  528. ret << "))-1; end\n";
  529. }
  530. void RubyCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
  531. int targState, int inFinish )
  532. {
  533. ret <<
  534. " case " << ACT() << "\n";
  535. for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
  536. /* Write the case label, the action and the case break. */
  537. if ( lma->lmId < 0 )
  538. ret << " else\n";
  539. else
  540. ret << " when " << lma->lmId << " then\n";
  541. /* Write the block and close it off. */
  542. ret << " begin";
  543. INLINE_LIST( ret, lma->children, targState, inFinish );
  544. ret << "end\n";
  545. }
  546. ret << "end \n\t";
  547. }
  548. void RubyCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
  549. {
  550. ret << ACT() << " = " << item->lmId << ";";
  551. }
  552. void RubyCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
  553. {
  554. ret << TOKSTART() << " = " << NULL_ITEM() << ";";
  555. }
  556. void RubyCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
  557. {
  558. ret << ACT() << " = 0\n";
  559. }
  560. void RubyCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
  561. {
  562. ret << TOKSTART() << " = " << P() << "\n";
  563. }
  564. void RubyCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
  565. {
  566. /* The tokend action sets tokend. */
  567. ret << TOKEND() << " = " << P();
  568. if ( item->offset != 0 )
  569. out << "+" << item->offset;
  570. out << "\n";
  571. }
  572. void RubyCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
  573. {
  574. ret << TOKEND();
  575. }
  576. void RubyCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
  577. int targState, bool inFinish )
  578. {
  579. if ( item->children->length() > 0 ) {
  580. /* Write the block and close it off. */
  581. ret << " begin ";
  582. INLINE_LIST( ret, item->children, targState, inFinish );
  583. ret << " end\n";
  584. }
  585. }
  586. int RubyCodeGen::TRANS_ACTION( RedTransAp *trans )
  587. {
  588. /* If there are actions, emit them. Otherwise emit zero. */
  589. int act = 0;
  590. if ( trans->action != 0 )
  591. act = trans->action->location+1;
  592. return act;
  593. }
  594. ostream &RubyCodeGen::source_warning( const InputLoc &loc )
  595. {
  596. cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
  597. return cerr;
  598. }
  599. ostream &RubyCodeGen::source_error( const InputLoc &loc )
  600. {
  601. gblErrorCount += 1;
  602. assert( sourceFileName != 0 );
  603. cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
  604. return cerr;
  605. }
  606. void RubyCodeGen::finishRagelDef()
  607. {
  608. if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
  609. codeStyle == GenIpGoto || codeStyle == GenSplit )
  610. {
  611. /* For directly executable machines there is no required state
  612. * ordering. Choose a depth-first ordering to increase the
  613. * potential for fall-throughs. */
  614. redFsm->depthFirstOrdering();
  615. }
  616. else {
  617. /* The frontend will do this for us, but it may be a good idea to
  618. * force it if the intermediate file is edited. */
  619. redFsm->sortByStateId();
  620. }
  621. /* Choose default transitions and the single transition. */
  622. redFsm->chooseDefaultSpan();
  623. /* Maybe do flat expand, otherwise choose single. */
  624. if ( codeStyle == GenFlat || codeStyle == GenFFlat )
  625. redFsm->makeFlat();
  626. else
  627. redFsm->chooseSingle();
  628. /* If any errors have occured in the input file then don't write anything. */
  629. if ( gblErrorCount > 0 )
  630. return;
  631. if ( codeStyle == GenSplit )
  632. redFsm->partitionFsm( numSplitPartitions );
  633. if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
  634. redFsm->setInTrans();
  635. /* Anlayze Machine will find the final action reference counts, among
  636. * other things. We will use these in reporting the usage
  637. * of fsm directives in action code. */
  638. analyzeMachine();
  639. /* Determine if we should use indicies. */
  640. calcIndexSize();
  641. }
  642. /* Determine if we should use indicies or not. */
  643. void RubyCodeGen::calcIndexSize()
  644. {
  645. int sizeWithInds = 0, sizeWithoutInds = 0;
  646. /* Calculate cost of using with indicies. */
  647. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  648. int totalIndex = st->outSingle.length() + st->outRange.length() +
  649. (st->defTrans == 0 ? 0 : 1);
  650. sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
  651. }
  652. sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
  653. if ( redFsm->anyActions() )
  654. sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
  655. /* Calculate the cost of not using indicies. */
  656. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  657. int totalIndex = st->outSingle.length() + st->outRange.length() +
  658. (st->defTrans == 0 ? 0 : 1);
  659. sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
  660. if ( redFsm->anyActions() )
  661. sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
  662. }
  663. /* If using indicies reduces the size, use them. */
  664. useIndicies = sizeWithInds < sizeWithoutInds;
  665. }
  666. unsigned int RubyCodeGen::arrayTypeSize( unsigned long maxVal )
  667. {
  668. long long maxValLL = (long long) maxVal;
  669. HostType *arrayType = keyOps->typeSubsumes( maxValLL );
  670. assert( arrayType != 0 );
  671. return arrayType->size;
  672. }
  673. void RubyCodeGen::writeInit()
  674. {
  675. out << "begin\n";
  676. out << " " << P() << " ||= 0\n";
  677. if ( !noEnd )
  678. out << " " << PE() << " ||= " << DATA() << ".length\n";
  679. if ( !noCS )
  680. out << " " << vCS() << " = " << START() << "\n";
  681. /* If there are any calls, then the stack top needs initialization. */
  682. if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
  683. out << " " << TOP() << " = 0\n";
  684. if ( hasLongestMatch ) {
  685. out <<
  686. " " << TOKSTART() << " = " << NULL_ITEM() << "\n"
  687. " " << TOKEND() << " = " << NULL_ITEM() << "\n"
  688. " " << ACT() << " = 0\n";
  689. }
  690. out << "end\n";
  691. }
  692. void RubyCodeGen::writeExports()
  693. {
  694. if ( exportList.length() > 0 ) {
  695. for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
  696. STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name )
  697. << " = " << KEY(ex->key) << "\n";
  698. }
  699. out << "\n";
  700. }
  701. }
  702. void RubyCodeGen::writeStart()
  703. {
  704. out << START_STATE_ID();
  705. }
  706. void RubyCodeGen::writeFirstFinal()
  707. {
  708. out << FIRST_FINAL_STATE();
  709. }
  710. void RubyCodeGen::writeError()
  711. {
  712. out << ERROR_STATE();
  713. }
  714. /*
  715. * Local Variables:
  716. * mode: c++
  717. * indent-tabs-mode: 1
  718. * c-file-style: "bsd"
  719. * End:
  720. */