"Fossies" - the Fresh Open Source Software Archive

Member "ragel-6.10/ragel/gendata.cpp" (24 Mar 2017, 31894 Bytes) of package /linux/misc/ragel-6.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gendata.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.9_vs_6.10.

    1 /*
    2  *  Copyright 2005-2007 Adrian Thurston <thurston@complang.org>
    3  */
    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 
   22 #include "gendata.h"
   23 #include "ragel.h"
   24 #include <iostream>
   25 
   26 /*
   27  * Code generators.
   28  */
   29 
   30 #include "cstable.h"
   31 #include "csftable.h"
   32 #include "csflat.h"
   33 #include "csfflat.h"
   34 #include "csgoto.h"
   35 #include "csfgoto.h"
   36 #include "csipgoto.h"
   37 #include "cssplit.h"
   38 
   39 #include "cdtable.h"
   40 #include "cdftable.h"
   41 #include "cdflat.h"
   42 #include "cdfflat.h"
   43 #include "cdgoto.h"
   44 #include "cdfgoto.h"
   45 #include "cdipgoto.h"
   46 #include "cdsplit.h"
   47 
   48 #include "dotcodegen.h"
   49 
   50 #include "javacodegen.h"
   51 
   52 #include "gocodegen.h"
   53 #include "gotable.h"
   54 #include "goftable.h"
   55 #include "goflat.h"
   56 #include "gofflat.h"
   57 #include "gogoto.h"
   58 #include "gofgoto.h"
   59 #include "goipgoto.h"
   60 
   61 #include "mltable.h"
   62 #include "mlftable.h"
   63 #include "mlflat.h"
   64 #include "mlfflat.h"
   65 #include "mlgoto.h"
   66 #include "mlfgoto.h"
   67 
   68 #include "rubytable.h"
   69 #include "rubyftable.h"
   70 #include "rubyflat.h"
   71 #include "rubyfflat.h"
   72 #include "rbxgoto.h"
   73 
   74 string itoa( int i )
   75 {
   76     char buf[16];
   77     sprintf( buf, "%i", i );
   78     return buf;
   79 }
   80 
   81 using std::cout;
   82 using std::cerr;
   83 using std::endl;
   84 
   85 /* Invoked by the parser when a ragel definition is opened. */
   86 CodeGenData *dotMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
   87 {
   88     CodeGenData *codeGen = new GraphvizDotGen(out);
   89 
   90     codeGen->sourceFileName = sourceFileName;
   91     codeGen->fsmName = fsmName;
   92 
   93     /* For normal code generation we want a transition on every character so we never
   94      * end up in an undefined state. For graphviz this just clutters the
   95      * drawing so we turn it off. */
   96     codeGen->wantComplete = false;
   97 
   98     return codeGen;
   99 }
  100 
  101 /* Invoked by the parser when a ragel definition is opened. */
  102 CodeGenData *cdMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
  103 {
  104     CodeGenData *codeGen = 0;
  105     switch ( hostLang->lang ) {
  106     case HostLang::C:
  107         switch ( codeStyle ) {
  108         case GenTables:
  109             codeGen = new CTabCodeGen(out);
  110             break;
  111         case GenFTables:
  112             codeGen = new CFTabCodeGen(out);
  113             break;
  114         case GenFlat:
  115             codeGen = new CFlatCodeGen(out);
  116             break;
  117         case GenFFlat:
  118             codeGen = new CFFlatCodeGen(out);
  119             break;
  120         case GenGoto:
  121             codeGen = new CGotoCodeGen(out);
  122             break;
  123         case GenFGoto:
  124             codeGen = new CFGotoCodeGen(out);
  125             break;
  126         case GenIpGoto:
  127             codeGen = new CIpGotoCodeGen(out);
  128             break;
  129         case GenSplit:
  130             codeGen = new CSplitCodeGen(out);
  131             break;
  132         }
  133         break;
  134 
  135     case HostLang::D:
  136         switch ( codeStyle ) {
  137         case GenTables:
  138             codeGen = new DTabCodeGen(out);
  139             break;
  140         case GenFTables:
  141             codeGen = new DFTabCodeGen(out);
  142             break;
  143         case GenFlat:
  144             codeGen = new DFlatCodeGen(out);
  145             break;
  146         case GenFFlat:
  147             codeGen = new DFFlatCodeGen(out);
  148             break;
  149         case GenGoto:
  150             codeGen = new DGotoCodeGen(out);
  151             break;
  152         case GenFGoto:
  153             codeGen = new DFGotoCodeGen(out);
  154             break;
  155         case GenIpGoto:
  156             codeGen = new DIpGotoCodeGen(out);
  157             break;
  158         case GenSplit:
  159             codeGen = new DSplitCodeGen(out);
  160             break;
  161         }
  162         break;
  163 
  164     case HostLang::D2:
  165         switch ( codeStyle ) {
  166         case GenTables:
  167             codeGen = new D2TabCodeGen(out);
  168             break;
  169         case GenFTables:
  170             codeGen = new D2FTabCodeGen(out);
  171             break;
  172         case GenFlat:
  173             codeGen = new D2FlatCodeGen(out);
  174             break;
  175         case GenFFlat:
  176             codeGen = new D2FFlatCodeGen(out);
  177             break;
  178         case GenGoto:
  179             codeGen = new D2GotoCodeGen(out);
  180             break;
  181         case GenFGoto:
  182             codeGen = new D2FGotoCodeGen(out);
  183             break;
  184         case GenIpGoto:
  185             codeGen = new D2IpGotoCodeGen(out);
  186             break;
  187         case GenSplit:
  188             codeGen = new D2SplitCodeGen(out);
  189             break;
  190         }
  191         break;
  192 
  193     default: break;
  194     }
  195 
  196     codeGen->sourceFileName = sourceFileName;
  197     codeGen->fsmName = fsmName;
  198 
  199     return codeGen;
  200 }
  201 
  202 /* Invoked by the parser when a ragel definition is opened. */
  203 CodeGenData *javaMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
  204 {
  205     CodeGenData *codeGen = new JavaTabCodeGen(out);
  206 
  207     codeGen->sourceFileName = sourceFileName;
  208     codeGen->fsmName = fsmName;
  209 
  210     return codeGen;
  211 }
  212 
  213 /* Invoked by the parser when a ragel definition is opened. */
  214 CodeGenData *goMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
  215 {
  216     CodeGenData *codeGen = 0;
  217 
  218     switch ( codeStyle ) {
  219     case GenTables:
  220         codeGen = new GoTabCodeGen(out);
  221         break;
  222     case GenFTables:
  223         codeGen = new GoFTabCodeGen(out);
  224         break;
  225     case GenFlat:
  226         codeGen = new GoFlatCodeGen(out);
  227         break;
  228     case GenFFlat:
  229         codeGen = new GoFFlatCodeGen(out);
  230         break;
  231     case GenGoto:
  232         codeGen = new GoGotoCodeGen(out);
  233         break;
  234     case GenFGoto:
  235         codeGen = new GoFGotoCodeGen(out);
  236         break;
  237     case GenIpGoto:
  238         codeGen = new GoIpGotoCodeGen(out);
  239         break;
  240     default:
  241         cerr << "Invalid output style, only -T0, -T1, -F0, -F1, -G0, -G1 and -G2 are supported for Go.\n";
  242         exit(1);
  243     }
  244 
  245     codeGen->sourceFileName = sourceFileName;
  246     codeGen->fsmName = fsmName;
  247 
  248     return codeGen;
  249 }
  250 
  251 /* Invoked by the parser when a ragel definition is opened. */
  252 CodeGenData *rubyMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
  253 {
  254     CodeGenData *codeGen = 0;
  255     switch ( codeStyle ) {
  256         case GenTables: 
  257             codeGen = new RubyTabCodeGen(out);
  258             break;
  259         case GenFTables:
  260             codeGen = new RubyFTabCodeGen(out);
  261             break;
  262         case GenFlat:
  263             codeGen = new RubyFlatCodeGen(out);
  264             break;
  265         case GenFFlat:
  266             codeGen = new RubyFFlatCodeGen(out);
  267             break;
  268         case GenGoto:
  269             if ( rubyImpl == Rubinius ) {
  270                 codeGen = new RbxGotoCodeGen(out);
  271             } else {
  272                 cerr << "Goto style is still _very_ experimental " 
  273                     "and only supported using Rubinius.\n"
  274                     "You may want to enable the --rbx flag "
  275                     " to give it a try.\n";
  276                 exit(1);
  277             }
  278             break;
  279         default:
  280             cout << "Invalid code style\n";
  281             exit(1);
  282             break;
  283     }
  284     codeGen->sourceFileName = sourceFileName;
  285     codeGen->fsmName = fsmName;
  286 
  287     return codeGen;
  288 }
  289 
  290 /* Invoked by the parser when a ragel definition is opened. */
  291 CodeGenData *csharpMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
  292 {
  293     CodeGenData *codeGen = 0;
  294 
  295     switch ( codeStyle ) {
  296     case GenTables:
  297         codeGen = new CSharpTabCodeGen(out);
  298         break;
  299     case GenFTables:
  300         codeGen = new CSharpFTabCodeGen(out);
  301         break;
  302     case GenFlat:
  303         codeGen = new CSharpFlatCodeGen(out);
  304         break;
  305     case GenFFlat:
  306         codeGen = new CSharpFFlatCodeGen(out);
  307         break;
  308     case GenGoto:
  309         codeGen = new CSharpGotoCodeGen(out);
  310         break;
  311     case GenFGoto:
  312         codeGen = new CSharpFGotoCodeGen(out);
  313         break;
  314     case GenIpGoto:
  315         codeGen = new CSharpIpGotoCodeGen(out);
  316         break;
  317     case GenSplit:
  318         codeGen = new CSharpSplitCodeGen(out);
  319         break;
  320     }
  321 
  322     codeGen->sourceFileName = sourceFileName;
  323     codeGen->fsmName = fsmName;
  324 
  325     return codeGen;
  326 }
  327 
  328 /* Invoked by the parser when a ragel definition is opened. */
  329 CodeGenData *ocamlMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
  330 {
  331     CodeGenData *codeGen = 0;
  332 
  333     switch ( codeStyle ) {
  334     case GenTables:
  335         codeGen = new OCamlTabCodeGen(out);
  336         break;
  337     case GenFTables:
  338         codeGen = new OCamlFTabCodeGen(out);
  339         break;
  340     case GenFlat:
  341         codeGen = new OCamlFlatCodeGen(out);
  342         break;
  343     case GenFFlat:
  344         codeGen = new OCamlFFlatCodeGen(out);
  345         break;
  346     case GenGoto:
  347         codeGen = new OCamlGotoCodeGen(out);
  348         break;
  349     case GenFGoto:
  350         codeGen = new OCamlFGotoCodeGen(out);
  351         break;
  352     default:
  353         cerr << "I only support the -T0 -T1 -F0 -F1 -G0 and -G1 output styles for OCaml.\n";
  354         exit(1);
  355     }
  356 
  357     codeGen->sourceFileName = sourceFileName;
  358     codeGen->fsmName = fsmName;
  359 
  360     return codeGen;
  361 }
  362 
  363 
  364 CodeGenData *makeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
  365 {
  366     CodeGenData *cgd = 0;
  367     if ( generateDot )
  368         cgd = dotMakeCodeGen( sourceFileName, fsmName, out );
  369     else if ( hostLang == &hostLangC )
  370         cgd = cdMakeCodeGen( sourceFileName, fsmName, out );
  371     else if ( hostLang == &hostLangD )
  372         cgd = cdMakeCodeGen( sourceFileName, fsmName, out );
  373     else if ( hostLang == &hostLangD2 )
  374         cgd = cdMakeCodeGen( sourceFileName, fsmName, out );
  375     else if ( hostLang == &hostLangGo )
  376         cgd = goMakeCodeGen( sourceFileName, fsmName, out );
  377     else if ( hostLang == &hostLangJava )
  378         cgd = javaMakeCodeGen( sourceFileName, fsmName, out );
  379     else if ( hostLang == &hostLangRuby )
  380         cgd = rubyMakeCodeGen( sourceFileName, fsmName, out );
  381     else if ( hostLang == &hostLangCSharp )
  382         cgd = csharpMakeCodeGen( sourceFileName, fsmName, out );
  383     else if ( hostLang == &hostLangOCaml )
  384         cgd = ocamlMakeCodeGen( sourceFileName, fsmName, out );
  385     return cgd;
  386 }
  387 
  388 void lineDirective( ostream &out, const char *fileName, int line )
  389 {
  390     if ( !generateDot ) {
  391         if ( hostLang == &hostLangC )
  392             cdLineDirective( out, fileName, line );
  393         else if ( hostLang == &hostLangD )
  394             cdLineDirective( out, fileName, line );
  395         else if ( hostLang == &hostLangD2 )
  396             cdLineDirective( out, fileName, line );
  397         else if ( hostLang == &hostLangGo )
  398             goLineDirective( out, fileName, line );
  399         else if ( hostLang == &hostLangJava )
  400             javaLineDirective( out, fileName, line );
  401         else if ( hostLang == &hostLangRuby )
  402             rubyLineDirective( out, fileName, line );
  403         else if ( hostLang == &hostLangCSharp )
  404             csharpLineDirective( out, fileName, line );
  405         else if ( hostLang == &hostLangOCaml )
  406             ocamlLineDirective( out, fileName, line );
  407     }
  408 }
  409 
  410 void genLineDirective( ostream &out )
  411 {
  412     std::streambuf *sbuf = out.rdbuf();
  413     output_filter *filter = static_cast<output_filter*>(sbuf);
  414     lineDirective( out, filter->fileName, filter->line + 1 );
  415 }
  416 
  417 
  418 /* Total error count. */
  419 /* int gblErrorCount = 0; */
  420 
  421 CodeGenData::CodeGenData( ostream &out )
  422 :
  423     sourceFileName(0),
  424     fsmName(0), 
  425     out(out),
  426     redFsm(0), 
  427     allActions(0),
  428     allActionTables(0),
  429     allConditions(0),
  430     allCondSpaces(0),
  431     allStates(0),
  432     nameIndex(0),
  433     startState(-1),
  434     errState(-1),
  435     getKeyExpr(0),
  436     accessExpr(0),
  437     prePushExpr(0),
  438     postPopExpr(0),
  439     pExpr(0),
  440     peExpr(0),
  441     eofExpr(0),
  442     csExpr(0),
  443     topExpr(0),
  444     stackExpr(0),
  445     actExpr(0),
  446     tokstartExpr(0),
  447     tokendExpr(0),
  448     dataExpr(0),
  449     wantComplete(true),
  450     hasLongestMatch(false),
  451     noEnd(false),
  452     noPrefix(false),
  453     noFinal(false),
  454     noError(false),
  455     noEntry(false),
  456     noCS(false)
  457 {}
  458 
  459 
  460 void CodeGenData::createMachine()
  461 {
  462     redFsm = new RedFsmAp();
  463 }
  464 
  465 void CodeGenData::initActionList( unsigned long length )
  466 { 
  467     allActions = new GenAction[length];
  468     for ( unsigned long a = 0; a < length; a++ )
  469         actionList.append( allActions+a );
  470 }
  471 
  472 void CodeGenData::newAction( int anum, const char *name,
  473         const InputLoc &loc, GenInlineList *inlineList )
  474 {
  475     allActions[anum].actionId = anum;
  476     allActions[anum].name = name;
  477     allActions[anum].loc = loc;
  478     allActions[anum].inlineList = inlineList;
  479 }
  480 
  481 void CodeGenData::initActionTableList( unsigned long length )
  482 { 
  483     allActionTables = new RedAction[length];
  484 }
  485 
  486 void CodeGenData::initStateList( unsigned long length )
  487 {
  488     allStates = new RedStateAp[length];
  489     for ( unsigned long s = 0; s < length; s++ )
  490         redFsm->stateList.append( allStates+s );
  491 
  492     /* We get the start state as an offset, set the pointer now. */
  493     if ( startState >= 0 )
  494         redFsm->startState = allStates + startState;
  495     if ( errState >= 0 )
  496         redFsm->errState = allStates + errState;
  497     for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ )
  498         redFsm->entryPoints.insert( allStates + *en );
  499 
  500     /* The nextStateId is no longer used to assign state ids (they come in set
  501      * from the frontend now), however generation code still depends on it.
  502      * Should eventually remove this variable. */
  503     redFsm->nextStateId = redFsm->stateList.length();
  504 }
  505 
  506 void CodeGenData::setStartState( unsigned long startState )
  507 {
  508     this->startState = startState;
  509 }
  510 
  511 void CodeGenData::setErrorState( unsigned long errState )
  512 {
  513     this->errState = errState;
  514 }
  515 
  516 void CodeGenData::addEntryPoint( char *name, unsigned long entryState )
  517 {
  518     entryPointIds.append( entryState );
  519     entryPointNames.append( name );
  520 }
  521 
  522 void CodeGenData::initTransList( int snum, unsigned long length )
  523 {
  524     /* Could preallocate the out range to save time growing it. For now do
  525      * nothing. */
  526 }
  527 
  528 void CodeGenData::newTrans( int snum, int tnum, Key lowKey, 
  529         Key highKey, long targ, long action )
  530 {
  531     /* Get the current state and range. */
  532     RedStateAp *curState = allStates + snum;
  533     RedTransList &destRange = curState->outRange;
  534 
  535     if ( curState == redFsm->errState )
  536         return;
  537 
  538     /* Make the new transitions. */
  539     RedStateAp *targState = targ >= 0 ? (allStates + targ) : 
  540             wantComplete ? redFsm->getErrorState() : 0;
  541     RedAction *actionTable = action >= 0 ? (allActionTables + action) : 0;
  542     RedTransAp *trans = redFsm->allocateTrans( targState, actionTable );
  543     RedTransEl transEl( lowKey, highKey, trans );
  544 
  545     if ( wantComplete ) {
  546         /* If the machine is to be complete then we need to fill any gaps with
  547          * the error transitions. */
  548         if ( destRange.length() == 0 ) {
  549             /* Range is currently empty. */
  550             if ( keyOps->minKey < lowKey ) {
  551                 /* The first range doesn't start at the low end. */
  552                 Key fillHighKey = lowKey;
  553                 fillHighKey.decrement();
  554 
  555                 /* Create the filler with the state's error transition. */
  556                 RedTransEl newTel( keyOps->minKey, fillHighKey, redFsm->getErrorTrans() );
  557                 destRange.append( newTel );
  558             }
  559         }
  560         else {
  561             /* The range list is not empty, get the the last range. */
  562             RedTransEl *last = &destRange[destRange.length()-1];
  563             Key nextKey = last->highKey;
  564             nextKey.increment();
  565             if ( nextKey < lowKey ) {
  566                 /* There is a gap to fill. Make the high key. */
  567                 Key fillHighKey = lowKey;
  568                 fillHighKey.decrement();
  569 
  570                 /* Create the filler with the state's error transtion. */
  571                 RedTransEl newTel( nextKey, fillHighKey, redFsm->getErrorTrans() );
  572                 destRange.append( newTel );
  573             }
  574         }
  575     }
  576 
  577     /* Filler taken care of. Append the range. */
  578     destRange.append( RedTransEl( lowKey, highKey, trans ) );
  579 }
  580 
  581 void CodeGenData::finishTransList( int snum )
  582 {
  583     /* Get the current state and range. */
  584     RedStateAp *curState = allStates + snum;
  585     RedTransList &destRange = curState->outRange;
  586 
  587     if ( curState == redFsm->errState )
  588         return;
  589 
  590     /* If building a complete machine we may need filler on the end. */
  591     if ( wantComplete ) {
  592         /* Check if there are any ranges already. */
  593         if ( destRange.length() == 0 ) {
  594             /* Fill with the whole alphabet. */
  595             /* Add the range on the lower and upper bound. */
  596             RedTransEl newTel( keyOps->minKey, keyOps->maxKey, redFsm->getErrorTrans() );
  597             destRange.append( newTel );
  598         }
  599         else {
  600             /* Get the last and check for a gap on the end. */
  601             RedTransEl *last = &destRange[destRange.length()-1];
  602             if ( last->highKey < keyOps->maxKey ) {
  603                 /* Make the high key. */
  604                 Key fillLowKey = last->highKey;
  605                 fillLowKey.increment();
  606 
  607                 /* Create the new range with the error trans and append it. */
  608                 RedTransEl newTel( fillLowKey, keyOps->maxKey, redFsm->getErrorTrans() );
  609                 destRange.append( newTel );
  610             }
  611         }
  612     }
  613 }
  614 
  615 void CodeGenData::setId( int snum, int id )
  616 {
  617     RedStateAp *curState = allStates + snum;
  618     curState->id = id;
  619 }
  620 
  621 void CodeGenData::setFinal( int snum )
  622 {
  623     RedStateAp *curState = allStates + snum;
  624     curState->isFinal = true;
  625 }
  626 
  627 
  628 void CodeGenData::setStateActions( int snum, long toStateAction, 
  629         long fromStateAction, long eofAction )
  630 {
  631     RedStateAp *curState = allStates + snum;
  632     if ( toStateAction >= 0 )
  633         curState->toStateAction = allActionTables + toStateAction;
  634     if ( fromStateAction >= 0 )
  635         curState->fromStateAction = allActionTables + fromStateAction;
  636     if ( eofAction >= 0 )
  637         curState->eofAction = allActionTables + eofAction;
  638 }
  639 
  640 void CodeGenData::setEofTrans( int snum, long eofTarget, long actId )
  641 {
  642     RedStateAp *curState = allStates + snum;
  643     RedStateAp *targState = allStates + eofTarget;
  644     RedAction *eofAct = allActionTables + actId;
  645     curState->eofTrans = redFsm->allocateTrans( targState, eofAct );
  646 }
  647 
  648 void CodeGenData::resolveTargetStates( GenInlineList *inlineList )
  649 {
  650     for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
  651         switch ( item->type ) {
  652         case GenInlineItem::Goto: case GenInlineItem::Call:
  653         case GenInlineItem::Next: case GenInlineItem::Entry:
  654             item->targState = allStates + item->targId;
  655             break;
  656         default:
  657             break;
  658         }
  659 
  660         if ( item->children != 0 )
  661             resolveTargetStates( item->children );
  662     }
  663 }
  664 
  665 void CodeGenData::closeMachine()
  666 {
  667     for ( GenActionList::Iter a = actionList; a.lte(); a++ )
  668         resolveTargetStates( a->inlineList );
  669 
  670     /* Note that even if we want a complete graph we do not give the error
  671      * state a default transition. All machines break out of the processing
  672      * loop when in the error state. */
  673 
  674     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  675         for ( GenStateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ )
  676             st->stateCondVect.append( sci );
  677     }
  678 }
  679 
  680 
  681 bool CodeGenData::setAlphType( const char *data )
  682 {
  683     HostType *alphType = findAlphTypeInternal( data );
  684     if ( alphType == 0 )
  685         return false;
  686 
  687     thisKeyOps.setAlphType( alphType );
  688     return true;
  689 }
  690 
  691 void CodeGenData::initCondSpaceList( ulong length )
  692 {
  693     allCondSpaces = new GenCondSpace[length];
  694     for ( ulong c = 0; c < length; c++ )
  695         condSpaceList.append( allCondSpaces + c );
  696 }
  697 
  698 void CodeGenData::newCondSpace( int cnum, int condSpaceId, Key baseKey )
  699 {
  700     GenCondSpace *cond = allCondSpaces + cnum;
  701     cond->condSpaceId = condSpaceId;
  702     cond->baseKey = baseKey;
  703 }
  704 
  705 void CodeGenData::condSpaceItem( int cnum, long condActionId )
  706 {
  707     GenCondSpace *cond = allCondSpaces + cnum;
  708     cond->condSet.append( allActions + condActionId );
  709 }
  710 
  711 void CodeGenData::initStateCondList( int snum, ulong length )
  712 {
  713     /* Could preallocate these, as we could with transitions. */
  714 }
  715 
  716 void CodeGenData::addStateCond( int snum, Key lowKey, Key highKey, long condNum )
  717 {
  718     RedStateAp *curState = allStates + snum;
  719 
  720     /* Create the new state condition. */
  721     GenStateCond *stateCond = new GenStateCond;
  722     stateCond->lowKey = lowKey;
  723     stateCond->highKey = highKey;
  724 
  725     /* Assign it a cond space. */
  726     GenCondSpace *condSpace = allCondSpaces + condNum;
  727     stateCond->condSpace = condSpace;
  728 
  729     curState->stateCondList.append( stateCond );
  730 }
  731 
  732 
  733 GenCondSpace *CodeGenData::findCondSpace( Key lowKey, Key highKey )
  734 {
  735     for ( CondSpaceList::Iter cs = condSpaceList; cs.lte(); cs++ ) {
  736         Key csHighKey = cs->baseKey;
  737         csHighKey += keyOps->alphSize() * (1 << cs->condSet.length());
  738 
  739         if ( lowKey >= cs->baseKey && highKey <= csHighKey )
  740             return cs;
  741     }
  742     return 0;
  743 }
  744 
  745 Condition *CodeGenData::findCondition( Key key )
  746 {
  747     for ( ConditionList::Iter cond = conditionList; cond.lte(); cond++ ) {
  748         Key upperKey = cond->baseKey + (1 << cond->condSet.length());
  749         if ( cond->baseKey <= key && key <= upperKey )
  750             return cond;
  751     }
  752     return 0;
  753 }
  754 
  755 Key CodeGenData::findMaxKey()
  756 {
  757     Key maxKey = keyOps->maxKey;
  758     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  759         assert( st->outSingle.length() == 0 );
  760         assert( st->defTrans == 0 );
  761 
  762         long rangeLen = st->outRange.length();
  763         if ( rangeLen > 0 ) {
  764             Key highKey = st->outRange[rangeLen-1].highKey;
  765             if ( highKey > maxKey )
  766                 maxKey = highKey;
  767         }
  768     }
  769     return maxKey;
  770 }
  771 
  772 void CodeGenData::findFinalActionRefs()
  773 {
  774     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  775         /* Rerence count out of single transitions. */
  776         for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
  777             if ( rtel->value->action != 0 ) {
  778                 rtel->value->action->numTransRefs += 1;
  779                 for ( GenActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
  780                     item->value->numTransRefs += 1;
  781             }
  782         }
  783 
  784         /* Reference count out of range transitions. */
  785         for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
  786             if ( rtel->value->action != 0 ) {
  787                 rtel->value->action->numTransRefs += 1;
  788                 for ( GenActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
  789                     item->value->numTransRefs += 1;
  790             }
  791         }
  792 
  793         /* Reference count default transition. */
  794         if ( st->defTrans != 0 && st->defTrans->action != 0 ) {
  795             st->defTrans->action->numTransRefs += 1;
  796             for ( GenActionTable::Iter item = st->defTrans->action->key; item.lte(); item++ )
  797                 item->value->numTransRefs += 1;
  798         }
  799 
  800         /* Reference count eof transitions. */
  801         if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
  802             st->eofTrans->action->numTransRefs += 1;
  803             for ( GenActionTable::Iter item = st->eofTrans->action->key; item.lte(); item++ )
  804                 item->value->numTransRefs += 1;
  805         }
  806 
  807         /* Reference count to state actions. */
  808         if ( st->toStateAction != 0 ) {
  809             st->toStateAction->numToStateRefs += 1;
  810             for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
  811                 item->value->numToStateRefs += 1;
  812         }
  813 
  814         /* Reference count from state actions. */
  815         if ( st->fromStateAction != 0 ) {
  816             st->fromStateAction->numFromStateRefs += 1;
  817             for ( GenActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ )
  818                 item->value->numFromStateRefs += 1;
  819         }
  820 
  821         /* Reference count EOF actions. */
  822         if ( st->eofAction != 0 ) {
  823             st->eofAction->numEofRefs += 1;
  824             for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
  825                 item->value->numEofRefs += 1;
  826         }
  827     }
  828 }
  829 
  830 void CodeGenData::analyzeAction( GenAction *act, GenInlineList *inlineList )
  831 {
  832     for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
  833         /* Only consider actions that are referenced. */
  834         if ( act->numRefs() > 0 ) {
  835             if ( item->type == GenInlineItem::Goto || item->type == GenInlineItem::GotoExpr )
  836                 redFsm->bAnyActionGotos = true;
  837             else if ( item->type == GenInlineItem::Call || item->type == GenInlineItem::CallExpr )
  838                 redFsm->bAnyActionCalls = true;
  839             else if ( item->type == GenInlineItem::Ret )
  840                 redFsm->bAnyActionRets = true;
  841 
  842             if ( item->type == GenInlineItem::CallExpr || item->type == GenInlineItem::GotoExpr )
  843                 redFsm->bAnyActionByValControl = true;
  844 
  845         }
  846 
  847         /* Check for various things in regular actions. */
  848         if ( act->numTransRefs > 0 || act->numToStateRefs > 0 || act->numFromStateRefs > 0 ) {
  849             /* Any returns in regular actions? */
  850             if ( item->type == GenInlineItem::Ret )
  851                 redFsm->bAnyRegActionRets = true;
  852 
  853             /* Any next statements in the regular actions? */
  854             if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr )
  855                 redFsm->bAnyRegNextStmt = true;
  856 
  857             /* Any by value control in regular actions? */
  858             if ( item->type == GenInlineItem::CallExpr || item->type == GenInlineItem::GotoExpr )
  859                 redFsm->bAnyRegActionByValControl = true;
  860 
  861             /* Any references to the current state in regular actions? */
  862             if ( item->type == GenInlineItem::Curs )
  863                 redFsm->bAnyRegCurStateRef = true;
  864 
  865             if ( item->type == GenInlineItem::Break )
  866                 redFsm->bAnyRegBreak = true;
  867         }
  868 
  869         if ( item->children != 0 )
  870             analyzeAction( act, item->children );
  871     }
  872 }
  873 
  874 void CodeGenData::analyzeActionList( RedAction *redAct, GenInlineList *inlineList )
  875 {
  876     for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
  877         /* Any next statements in the action table? */
  878         if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr )
  879             redAct->bAnyNextStmt = true;
  880 
  881         /* Any references to the current state. */
  882         if ( item->type == GenInlineItem::Curs )
  883             redAct->bAnyCurStateRef = true;
  884 
  885         if ( item->type == GenInlineItem::Break )
  886             redAct->bAnyBreakStmt = true;
  887 
  888         if ( item->children != 0 )
  889             analyzeActionList( redAct, item->children );
  890     }
  891 }
  892 
  893 /* Assign ids to referenced actions. */
  894 void CodeGenData::assignActionIds()
  895 {
  896     int nextActionId = 0;
  897     for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
  898         /* Only ever interested in referenced actions. */
  899         if ( act->numRefs() > 0 )
  900             act->actionId = nextActionId++;
  901     }
  902 }
  903 
  904 void CodeGenData::setValueLimits()
  905 {
  906     redFsm->maxSingleLen = 0;
  907     redFsm->maxRangeLen = 0;
  908     redFsm->maxKeyOffset = 0;
  909     redFsm->maxIndexOffset = 0;
  910     redFsm->maxActListId = 0;
  911     redFsm->maxActionLoc = 0;
  912     redFsm->maxActArrItem = 0;
  913     redFsm->maxSpan = 0;
  914     redFsm->maxCondSpan = 0;
  915     redFsm->maxFlatIndexOffset = 0;
  916     redFsm->maxCondOffset = 0;
  917     redFsm->maxCondLen = 0;
  918     redFsm->maxCondSpaceId = 0;
  919     redFsm->maxCondIndexOffset = 0;
  920 
  921     /* In both of these cases the 0 index is reserved for no value, so the max
  922      * is one more than it would be if they started at 0. */
  923     redFsm->maxIndex = redFsm->transSet.length();
  924     redFsm->maxCond = condSpaceList.length(); 
  925 
  926     /* The nextStateId - 1 is the last state id assigned. */
  927     redFsm->maxState = redFsm->nextStateId - 1;
  928 
  929     for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
  930         if ( csi->condSpaceId > redFsm->maxCondSpaceId )
  931             redFsm->maxCondSpaceId = csi->condSpaceId;
  932     }
  933 
  934     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  935         /* Maximum cond length. */
  936         if ( st->stateCondList.length() > redFsm->maxCondLen )
  937             redFsm->maxCondLen = st->stateCondList.length();
  938 
  939         /* Maximum single length. */
  940         if ( st->outSingle.length() > redFsm->maxSingleLen )
  941             redFsm->maxSingleLen = st->outSingle.length();
  942 
  943         /* Maximum range length. */
  944         if ( st->outRange.length() > redFsm->maxRangeLen )
  945             redFsm->maxRangeLen = st->outRange.length();
  946 
  947         /* The key offset index offset for the state after last is not used, skip it.. */
  948         if ( ! st.last() ) {
  949             redFsm->maxCondOffset += st->stateCondList.length();
  950             redFsm->maxKeyOffset += st->outSingle.length() + st->outRange.length()*2;
  951             redFsm->maxIndexOffset += st->outSingle.length() + st->outRange.length() + 2;
  952         }
  953 
  954         /* Max cond span. */
  955         if ( st->condList != 0 ) {
  956             unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
  957             if ( span > redFsm->maxCondSpan )
  958                 redFsm->maxCondSpan = span;
  959         }
  960 
  961         /* Max key span. */
  962         if ( st->transList != 0 ) {
  963             unsigned long long span = keyOps->span( st->lowKey, st->highKey );
  964             if ( span > redFsm->maxSpan )
  965                 redFsm->maxSpan = span;
  966         }
  967 
  968         /* Max cond index offset. */
  969         if ( ! st.last() ) {
  970             if ( st->condList != 0 )
  971                 redFsm->maxCondIndexOffset += keyOps->span( st->condLowKey, st->condHighKey );
  972         }
  973 
  974         /* Max flat index offset. */
  975         if ( ! st.last() ) {
  976             if ( st->transList != 0 )
  977                 redFsm->maxFlatIndexOffset += keyOps->span( st->lowKey, st->highKey );
  978             redFsm->maxFlatIndexOffset += 1;
  979         }
  980     }
  981 
  982     for ( GenActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) {
  983         /* Maximum id of action lists. */
  984         if ( at->actListId+1 > redFsm->maxActListId )
  985             redFsm->maxActListId = at->actListId+1;
  986 
  987         /* Maximum location of items in action array. */
  988         if ( at->location+1 > redFsm->maxActionLoc )
  989             redFsm->maxActionLoc = at->location+1;
  990 
  991         /* Maximum values going into the action array. */
  992         if ( at->key.length() > redFsm->maxActArrItem )
  993             redFsm->maxActArrItem = at->key.length();
  994         for ( GenActionTable::Iter item = at->key; item.lte(); item++ ) {
  995             if ( item->value->actionId > redFsm->maxActArrItem )
  996                 redFsm->maxActArrItem = item->value->actionId;
  997         }
  998     }
  999 }
 1000 
 1001 
 1002 
 1003 /* Gather various info on the machine. */
 1004 void CodeGenData::analyzeMachine()
 1005 {
 1006     /* Find the true count of action references.  */
 1007     findFinalActionRefs();
 1008 
 1009     /* Check if there are any calls in action code. */
 1010     for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
 1011         /* Record the occurrence of various kinds of actions. */
 1012         if ( act->numToStateRefs > 0 )
 1013             redFsm->bAnyToStateActions = true;
 1014         if ( act->numFromStateRefs > 0 )
 1015             redFsm->bAnyFromStateActions = true;
 1016         if ( act->numEofRefs > 0 )
 1017             redFsm->bAnyEofActions = true;
 1018         if ( act->numTransRefs > 0 )
 1019             redFsm->bAnyRegActions = true;
 1020 
 1021         /* Recurse through the action's parse tree looking for various things. */
 1022         analyzeAction( act, act->inlineList );
 1023     }
 1024 
 1025     /* Analyze reduced action lists. */
 1026     for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
 1027         for ( GenActionTable::Iter act = redAct->key; act.lte(); act++ )
 1028             analyzeActionList( redAct, act->value->inlineList );
 1029     }
 1030 
 1031     /* Find states that have transitions with actions that have next
 1032      * statements. */
 1033     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
 1034         /* Check any actions out of outSinge. */
 1035         for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
 1036             if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
 1037                 st->bAnyRegCurStateRef = true;
 1038         }
 1039 
 1040         /* Check any actions out of outRange. */
 1041         for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
 1042             if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
 1043                 st->bAnyRegCurStateRef = true;
 1044         }
 1045 
 1046         /* Check any action out of default. */
 1047         if ( st->defTrans != 0 && st->defTrans->action != 0 && 
 1048                 st->defTrans->action->anyCurStateRef() )
 1049             st->bAnyRegCurStateRef = true;
 1050         
 1051         if ( st->stateCondList.length() > 0 )
 1052             redFsm->bAnyConditions = true;
 1053 
 1054         if ( st->eofTrans != 0 )
 1055             redFsm->bAnyEofTrans = true;
 1056     }
 1057 
 1058     /* Assign ids to actions that are referenced. */
 1059     assignActionIds();
 1060 
 1061     /* Set the maximums of various values used for deciding types. */
 1062     setValueLimits();
 1063 }
 1064 
 1065 void CodeGenData::write_option_error( InputLoc &loc, char *arg )
 1066 {
 1067     source_warning(loc) << "unrecognized write option \"" << arg << "\"" << endl;
 1068 }
 1069 
 1070 /* returns true if the following section should generate line directives. */
 1071 bool CodeGenData::writeStatement( InputLoc &loc, int nargs, char **args )
 1072 {
 1073     bool followLineDirective = false;
 1074 
 1075     if ( strcmp( args[0], "data" ) == 0 ) {
 1076         out << '\n';
 1077         genLineDirective( out );
 1078         followLineDirective = true;
 1079 
 1080         for ( int i = 1; i < nargs; i++ ) {
 1081             if ( strcmp( args[i], "noerror" ) == 0 )
 1082                 noError = true;
 1083             else if ( strcmp( args[i], "noprefix" ) == 0 )
 1084                 noPrefix = true;
 1085             else if ( strcmp( args[i], "nofinal" ) == 0 )
 1086                 noFinal = true;
 1087             else if ( strcmp( args[i], "noentry" ) == 0 )
 1088                 noEntry = true;
 1089             else
 1090                 write_option_error( loc, args[i] );
 1091         }
 1092         writeData();
 1093     }
 1094     else if ( strcmp( args[0], "init" ) == 0 ) {
 1095         out << '\n';
 1096         genLineDirective( out );
 1097         followLineDirective = true;
 1098 
 1099         for ( int i = 1; i < nargs; i++ ) {
 1100             if ( strcmp( args[i], "nocs" ) == 0 )
 1101                 noCS = true;
 1102             else
 1103                 write_option_error( loc, args[i] );
 1104         }
 1105         writeInit();
 1106     }
 1107     else if ( strcmp( args[0], "exec" ) == 0 ) {
 1108         out << '\n';
 1109         genLineDirective( out );
 1110         followLineDirective = true;
 1111 
 1112         for ( int i = 1; i < nargs; i++ ) {
 1113             if ( strcmp( args[i], "noend" ) == 0 )
 1114                 noEnd = true;
 1115             else
 1116                 write_option_error( loc, args[i] );
 1117         }
 1118         writeExec();
 1119     }
 1120     else if ( strcmp( args[0], "exports" ) == 0 ) {
 1121         out << '\n';
 1122         genLineDirective( out );
 1123         followLineDirective = true;
 1124 
 1125         for ( int i = 1; i < nargs; i++ )
 1126             write_option_error( loc, args[i] );
 1127         writeExports();
 1128     }
 1129     else if ( strcmp( args[0], "start" ) == 0 ) {
 1130         for ( int i = 1; i < nargs; i++ )
 1131             write_option_error( loc, args[i] );
 1132         writeStart();
 1133     }
 1134     else if ( strcmp( args[0], "first_final" ) == 0 ) {
 1135         for ( int i = 1; i < nargs; i++ )
 1136             write_option_error( loc, args[i] );
 1137         writeFirstFinal();
 1138     }
 1139     else if ( strcmp( args[0], "error" ) == 0 ) {
 1140         for ( int i = 1; i < nargs; i++ )
 1141             write_option_error( loc, args[i] );
 1142         writeError();
 1143     }
 1144     else {
 1145         /* EMIT An error here. */
 1146         source_error(loc) << "unrecognized write command \"" << 
 1147                 args[0] << "\"" << endl;
 1148     }
 1149     return followLineDirective;
 1150 }
 1151 
 1152 ostream &CodeGenData::source_warning( const InputLoc &loc )
 1153 {
 1154     cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
 1155     return cerr;
 1156 }
 1157 
 1158 ostream &CodeGenData::source_error( const InputLoc &loc )
 1159 {
 1160     gblErrorCount += 1;
 1161     assert( sourceFileName != 0 );
 1162     cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
 1163     return cerr;
 1164 }
 1165 
 1166