/* * Copyright 2001-2018 Adrian Thurston * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "ragel.h" #include "binary.h" #include "redfsm.h" #include "gendata.h" #include void Binary::genAnalysis() { redFsm->sortByStateId(); /* Choose default transitions and the single transition. */ redFsm->chooseDefaultSpan(); /* Choose the singles. */ redFsm->moveSelectTransToSingle(); if ( redFsm->errState != 0 ) redFsm->getErrorCond(); /* If any errors have occured in the input file then don't write anything. */ if ( red->id->errorCount > 0 ) return; /* Anlayze Machine will find the final action reference counts, among other * things. We will use these in reporting the usage of fsm directives in * action code. */ red->analyzeMachine(); setKeyType(); /* Run the analysis pass over the table data. */ setTableState( TableArray::AnalyzePass ); tableDataPass(); /* Switch the tables over to the code gen mode. */ setTableState( TableArray::GeneratePass ); } void Binary::tableDataPass() { if ( type == Loop ) taActions(); taKeyOffsets(); taSingleLens(); taRangeLens(); taIndexOffsets(); taIndices(); taTransCondSpacesWi(); taTransOffsetsWi(); taTransLengthsWi(); taTransCondSpaces(); taTransOffsets(); taTransLengths(); taCondTargs(); taCondActions(); taToStateActions(); taFromStateActions(); taEofActions(); taEofConds(); taEofTrans(); taKeys(); taCondKeys(); taNfaTargs(); taNfaOffsets(); taNfaPushActions(); taNfaPopTrans(); } void Binary::writeData() { if ( type == Loop ) { /* If there are any transtion functions then output the array. If there * are none, don't bother emitting an empty array that won't be used. */ if ( redFsm->anyActions() ) taActions(); } taKeyOffsets(); taKeys(); taSingleLens(); taRangeLens(); taIndexOffsets(); taTransCondSpaces(); taTransOffsets(); taTransLengths(); taCondKeys(); taCondTargs(); taCondActions(); if ( redFsm->anyToStateActions() ) taToStateActions(); if ( redFsm->anyFromStateActions() ) taFromStateActions(); if ( redFsm->anyEofActions() ) taEofActions(); taEofConds(); if ( redFsm->anyEofTrans() ) taEofTrans(); taNfaTargs(); taNfaOffsets(); taNfaPushActions(); taNfaPopTrans(); STATE_IDS(); } void Binary::setKeyType() { transKeys.setType( ALPH_TYPE(), alphType->size, alphType->isChar ); transKeys.isSigned = keyOps->isSigned; } void Binary::setTableState( TableArray::State state ) { for ( ArrayVector::Iter i = arrayVector; i.lte(); i++ ) { TableArray *tableArray = *i; tableArray->setState( state ); } } void Binary::taKeyOffsets() { keyOffsets.start(); int curKeyOffset = 0; for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { keyOffsets.value( curKeyOffset ); curKeyOffset += st->outSingle.length() + st->outRange.length()*2; } keyOffsets.finish(); } void Binary::taSingleLens() { singleLens.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) singleLens.value( st->outSingle.length() ); singleLens.finish(); } void Binary::taRangeLens() { rangeLens.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) rangeLens.value( st->outRange.length() ); rangeLens.finish(); } void Binary::taIndexOffsets() { indexOffsets.start(); int curIndOffset = 0; for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Write the index offset. */ indexOffsets.value( curIndOffset ); /* Move the index offset ahead. */ curIndOffset += st->outSingle.length() + st->outRange.length(); if ( st->defTrans != 0 ) curIndOffset += 1; } indexOffsets.finish(); } void Binary::taToStateActions() { toStateActions.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) TO_STATE_ACTION(st); toStateActions.finish(); } void Binary::taFromStateActions() { fromStateActions.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) FROM_STATE_ACTION(st); fromStateActions.finish(); } void Binary::taEofActions() { eofActions.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) EOF_ACTION( st ); eofActions.finish(); } void Binary::taEofConds() { /* * EOF Cond Spaces */ eofCondSpaces.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->outCondSpace != 0 ) eofCondSpaces.value( st->outCondSpace->condSpaceId ); else eofCondSpaces.value( -1 ); } eofCondSpaces.finish(); /* * EOF Cond Key Indixes */ eofCondKeyOffs.start(); int curOffset = 0; for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { long off = 0; if ( st->outCondSpace != 0 ) { off = curOffset; curOffset += st->outCondKeys.length(); } eofCondKeyOffs.value( off ); } eofCondKeyOffs.finish(); /* * EOF Cond Key Lengths. */ eofCondKeyLens.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { long len = 0; if ( st->outCondSpace != 0 ) len = st->outCondKeys.length(); eofCondKeyLens.value( len ); } eofCondKeyLens.finish(); /* * EOF Cond Keys */ eofCondKeys.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->outCondSpace != 0 ) { for ( int c = 0; c < st->outCondKeys.length(); c++ ) { CondKey key = st->outCondKeys[c]; eofCondKeys.value( key.getVal() ); } } } eofCondKeys.finish(); } void Binary::taEofTrans() { eofTrans.start(); /* Need to compute transition positions. */ int totalTrans = 0; for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { totalTrans += st->outSingle.length(); totalTrans += st->outRange.length(); if ( st->defTrans != 0 ) totalTrans += 1; } for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { long trans = 0; if ( st->eofTrans != 0 ) { trans = totalTrans + 1; totalTrans += 1; } eofTrans.value( trans ); } eofTrans.finish(); } void Binary::taKeys() { transKeys.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Loop the singles. */ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { transKeys.value( stel->lowKey.getVal() ); } /* Loop the state's transitions. */ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { /* Lower key. */ transKeys.value( rtel->lowKey.getVal() ); /* Upper key. */ transKeys.value( rtel->highKey.getVal() ); } } transKeys.finish(); } void Binary::taIndices() { indices.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Walk the singles. */ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) indices.value( stel->value->id ); /* Walk the ranges. */ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) indices.value( rtel->value->id ); /* The state's default index goes next. */ if ( st->defTrans != 0 ) indices.value( st->defTrans->id ); } indices.finish(); } void Binary::taTransCondSpaces() { transCondSpaces.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Walk the singles. */ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { RedTransAp *trans = stel->value; if ( trans->condSpace != 0 ) transCondSpaces.value( trans->condSpace->condSpaceId ); else transCondSpaces.value( -1 ); } /* Walk the ranges. */ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { RedTransAp *trans = rtel->value; if ( trans->condSpace != 0 ) transCondSpaces.value( trans->condSpace->condSpaceId ); else transCondSpaces.value( -1 ); } /* The state's default index goes next. */ if ( st->defTrans != 0 ) { RedTransAp *trans = st->defTrans; if ( trans->condSpace != 0 ) transCondSpaces.value( trans->condSpace->condSpaceId ); else transCondSpaces.value( -1 ); } } /* Add any eof transitions that have not yet been written out above. */ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->eofTrans != 0 ) { RedTransAp *trans = st->eofTrans; if ( trans->condSpace != 0 ) transCondSpaces.value( trans->condSpace->condSpaceId ); else transCondSpaces.value( -1 ); } } transCondSpaces.finish(); } void Binary::taTransOffsets() { transOffsets.start(); int curOffset = 0; for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Walk the singles. */ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { RedTransAp *trans = stel->value; transOffsets.value( curOffset ); curOffset += trans->numConds(); } /* Walk the ranges. */ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { RedTransAp *trans = rtel->value; transOffsets.value( curOffset ); curOffset += trans->numConds(); } /* The state's default index goes next. */ if ( st->defTrans != 0 ) { RedTransAp *trans = st->defTrans; transOffsets.value( curOffset ); curOffset += trans->numConds(); } } /* Add any eof transitions that have not yet been written out above. */ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->eofTrans != 0 ) { RedTransAp *trans = st->eofTrans; transOffsets.value( curOffset ); curOffset += trans->numConds(); } } errCondOffset = curOffset; transOffsets.finish(); } void Binary::taTransLengths() { transLengths.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Walk the singles. */ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { RedTransAp *trans = stel->value; transLengths.value( trans->numConds() ); } /* Walk the ranges. */ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { RedTransAp *trans = rtel->value; transLengths.value( trans->numConds() ); } /* The state's default index goes next. */ if ( st->defTrans != 0 ) { RedTransAp *trans = st->defTrans; transLengths.value( trans->numConds() ); } } /* Add any eof transitions that have not yet been written out above. */ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->eofTrans != 0 ) { RedTransAp *trans = st->eofTrans; transLengths.value( trans->numConds() ); } } transLengths.finish(); } void Binary::taTransCondSpacesWi() { transCondSpacesWi.start(); for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) { /* Cond Space id. */ if ( trans->condSpace != 0 ) transCondSpacesWi.value( trans->condSpace->condSpaceId ); else transCondSpacesWi.value( -1 ); } transCondSpacesWi.finish(); } void Binary::taTransOffsetsWi() { transOffsetsWi.start(); int curOffset = 0; for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) { transOffsetsWi.value( curOffset ); TransApSet::Iter next = trans; next.increment(); curOffset += trans->numConds(); } transOffsetsWi.finish(); } void Binary::taTransLengthsWi() { transLengthsWi.start(); for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) { transLengthsWi.value( trans->numConds() ); TransApSet::Iter next = trans; next.increment(); } transLengthsWi.finish(); } void Binary::taCondKeys() { condKeys.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Walk the singles. */ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { RedTransAp *trans = stel->value; for ( int c = 0; c < trans->numConds(); c++ ) { CondKey key = trans->outCondKey( c ); condKeys.value( key.getVal() ); } } /* Walk the ranges. */ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { RedTransAp *trans = rtel->value; for ( int c = 0; c < trans->numConds(); c++ ) { CondKey key = trans->outCondKey( c ); condKeys.value( key.getVal() ); } } /* The state's default index goes next. */ if ( st->defTrans != 0 ) { RedTransAp *trans = st->defTrans; for ( int c = 0; c < trans->numConds(); c++ ) { CondKey key = trans->outCondKey( c ); condKeys.value( key.getVal() ); } } } /* Add any eof transitions that have not yet been written out above. */ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->eofTrans != 0 ) { RedTransAp *trans = st->eofTrans; for ( int c = 0; c < trans->numConds(); c++ ) { CondKey key = trans->outCondKey( c ); condKeys.value( key.getVal() ); } } } condKeys.finish(); } void Binary::taCondTargs() { condTargs.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Walk the singles. */ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { RedTransAp *trans = stel->value; for ( int c = 0; c < trans->numConds(); c++ ) { RedCondPair *cond = trans->outCond( c ); condTargs.value( cond->targ->id ); } } /* Walk the ranges. */ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { RedTransAp *trans = rtel->value; for ( int c = 0; c < trans->numConds(); c++ ) { RedCondPair *cond = trans->outCond( c ); condTargs.value( cond->targ->id ); } } /* The state's default index goes next. */ if ( st->defTrans != 0 ) { RedTransAp *trans = st->defTrans; for ( int c = 0; c < trans->numConds(); c++ ) { RedCondPair *cond = trans->outCond( c ); condTargs.value( cond->targ->id ); } } } /* Add any eof transitions that have not yet been written out above. */ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->eofTrans != 0 ) { RedTransAp *trans = st->eofTrans; for ( int c = 0; c < trans->numConds(); c++ ) { RedCondPair *cond = trans->outCond( c ); condTargs.value( cond->targ->id ); } } } if ( redFsm->errCond != 0 ) { RedCondPair *cond = &redFsm->errCond->p; condTargs.value( cond->targ->id ); } condTargs.finish(); } void Binary::taCondActions() { condActions.start(); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { /* Walk the singles. */ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { RedTransAp *trans = stel->value; for ( int c = 0; c < trans->numConds(); c++ ) { RedCondPair *cond = trans->outCond( c ); COND_ACTION( cond ); } } /* Walk the ranges. */ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { RedTransAp *trans = rtel->value; for ( int c = 0; c < trans->numConds(); c++ ) { RedCondPair *cond = trans->outCond( c ); COND_ACTION( cond ); } } /* The state's default index goes next. */ if ( st->defTrans != 0 ) { RedTransAp *trans = st->defTrans; for ( int c = 0; c < trans->numConds(); c++ ) { RedCondPair *cond = trans->outCond(c); COND_ACTION( cond ); } } } /* Add any eof transitions that have not yet been written out above. */ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->eofTrans != 0 ) { RedTransAp *trans = st->eofTrans; for ( int c = 0; c < trans->numConds(); c++ ) { RedCondPair *cond = trans->outCond(c); COND_ACTION( cond ); } } } if ( redFsm->errCond != 0 ) { RedCondPair *cond = &redFsm->errCond->p; COND_ACTION( cond ); } condActions.finish(); } void Binary::taNfaTargs() { nfaTargs.start(); /* Offset of zero means no NFA targs, put a filler there. */ nfaTargs.value( 0 ); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->nfaTargs != 0 ) { nfaTargs.value( st->nfaTargs->length() ); for ( RedNfaTargs::Iter targ = *st->nfaTargs; targ.lte(); targ++ ) nfaTargs.value( targ->state->id ); } } nfaTargs.finish(); } /* These need to mirror nfa targs. */ void Binary::taNfaPushActions() { nfaPushActions.start(); nfaPushActions.value( 0 ); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->nfaTargs != 0 ) { nfaPushActions.value( 0 ); for ( RedNfaTargs::Iter targ = *st->nfaTargs; targ.lte(); targ++ ) NFA_PUSH_ACTION( targ ); } } nfaPushActions.finish(); } void Binary::taNfaPopTrans() { nfaPopTrans.start(); nfaPopTrans.value( 0 ); for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->nfaTargs != 0 ) { nfaPopTrans.value( 0 ); for ( RedNfaTargs::Iter targ = *st->nfaTargs; targ.lte(); targ++ ) NFA_POP_TEST( targ ); } } nfaPopTrans.finish(); } void Binary::taNfaOffsets() { nfaOffsets.start(); /* Offset of zero means no NFA targs, real targs start at 1. */ long offset = 1; for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->nfaTargs == 0 ) { nfaOffsets.value( 0 ); } else { nfaOffsets.value( offset ); offset += 1 + st->nfaTargs->length(); } } nfaOffsets.finish(); } /* Write out the array of actions. */ std::ostream &Binary::ACTIONS_ARRAY() { out << "\t0, "; int totalActions = 1; for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) { /* Write out the length, which will never be the last character. */ out << act->key.length() << ", "; /* Put in a line break every 8 */ if ( totalActions++ % 8 == 7 ) out << "\n\t"; for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) { out << item->value->actionId; if ( ! (act.last() && item.last()) ) out << ", "; /* Put in a line break every 8 */ if ( totalActions++ % 8 == 7 ) out << "\n\t"; } } out << "\n"; return out; } void Binary::taActions() { actions.start(); /* Put "no-action" at the beginning. */ actions.value( 0 ); for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) { /* Write out the length, which will never be the last character. */ actions.value( act->key.length() ); for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) actions.value( item->value->actionId ); } actions.finish(); }