aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/ragel6/dotcodegen.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/tools/ragel6/dotcodegen.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/tools/ragel6/dotcodegen.cpp')
-rw-r--r--contrib/tools/ragel6/dotcodegen.cpp320
1 files changed, 320 insertions, 0 deletions
diff --git a/contrib/tools/ragel6/dotcodegen.cpp b/contrib/tools/ragel6/dotcodegen.cpp
new file mode 100644
index 0000000000..7a83c46c0d
--- /dev/null
+++ b/contrib/tools/ragel6/dotcodegen.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ragel.h"
+#include "dotcodegen.h"
+#include "gendata.h"
+
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+/* Override this so that write statement processing is ignored */
+bool GraphvizDotGen::writeStatement( InputLoc &, int, char ** )
+{
+ return false;
+}
+
+std::ostream &GraphvizDotGen::KEY( Key key )
+{
+ if ( displayPrintables && key.isPrintable() ) {
+ // Output values as characters, ensuring we escape the quote (") character
+ char cVal = (char) key.getVal();
+ switch ( cVal ) {
+ case '"': case '\\':
+ out << "'\\" << cVal << "'";
+ break;
+ case '\a':
+ out << "'\\\\a'";
+ break;
+ case '\b':
+ out << "'\\\\b'";
+ break;
+ case '\t':
+ out << "'\\\\t'";
+ break;
+ case '\n':
+ out << "'\\\\n'";
+ break;
+ case '\v':
+ out << "'\\\\v'";
+ break;
+ case '\f':
+ out << "'\\\\f'";
+ break;
+ case '\r':
+ out << "'\\\\r'";
+ break;
+ case ' ':
+ out << "SP";
+ break;
+ default:
+ out << "'" << cVal << "'";
+ break;
+ }
+ }
+ else {
+ if ( keyOps->isSigned )
+ out << key.getVal();
+ else
+ out << (unsigned long) key.getVal();
+ }
+
+ return out;
+}
+
+std::ostream &GraphvizDotGen::TRANS_ACTION( RedStateAp *fromState, RedTransAp *trans )
+{
+ int n = 0;
+ RedAction *actions[3];
+
+ if ( fromState->fromStateAction != 0 )
+ actions[n++] = fromState->fromStateAction;
+ if ( trans->action != 0 )
+ actions[n++] = trans->action;
+ if ( trans->targ != 0 && trans->targ->toStateAction != 0 )
+ actions[n++] = trans->targ->toStateAction;
+
+ if ( n > 0 )
+ out << " / ";
+
+ /* Loop the existing actions and write out what's there. */
+ for ( int a = 0; a < n; a++ ) {
+ for ( GenActionTable::Iter actIt = actions[a]->key.first(); actIt.lte(); actIt++ ) {
+ GenAction *action = actIt->value;
+ out << action->nameOrLoc();
+ if ( a < n-1 || !actIt.last() )
+ out << ", ";
+ }
+ }
+ return out;
+}
+
+std::ostream &GraphvizDotGen::ACTION( RedAction *action )
+{
+ /* The action. */
+ out << " / ";
+ for ( GenActionTable::Iter actIt = action->key.first(); actIt.lte(); actIt++ ) {
+ GenAction *action = actIt->value;
+ if ( action->name != 0 )
+ out << action->name;
+ else
+ out << action->loc.line << ":" << action->loc.col;
+ if ( !actIt.last() )
+ out << ", ";
+ }
+ return out;
+}
+
+std::ostream &GraphvizDotGen::ONCHAR( Key lowKey, Key highKey )
+{
+ GenCondSpace *condSpace;
+ if ( lowKey > keyOps->maxKey && (condSpace=findCondSpace(lowKey, highKey) ) ) {
+ Key values = ( lowKey - condSpace->baseKey ) / keyOps->alphSize();
+
+ lowKey = keyOps->minKey +
+ (lowKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
+ highKey = keyOps->minKey +
+ (highKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
+ KEY( lowKey );
+ if ( lowKey != highKey ) {
+ out << "..";
+ KEY( highKey );
+ }
+ out << "(";
+
+ for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ bool set = values & (1 << csi.pos());
+ if ( !set )
+ out << "!";
+ out << (*csi)->nameOrLoc();
+ if ( !csi.last() )
+ out << ", ";
+ }
+ out << ")";
+ }
+ else {
+ /* Output the key. Possibly a range. */
+ KEY( lowKey );
+ if ( highKey != lowKey ) {
+ out << "..";
+ KEY( highKey );
+ }
+ }
+ return out;
+}
+
+void GraphvizDotGen::writeTransList( RedStateAp *state )
+{
+ /* Build the set of unique transitions out of this state. */
+ RedTransSet stTransSet;
+ for ( RedTransList::Iter tel = state->outRange; tel.lte(); tel++ ) {
+ /* If we haven't seen the transitions before, the move forward
+ * emitting all the transitions on the same character. */
+ if ( stTransSet.insert( tel->value ) ) {
+ /* Write out the from and to states. */
+ out << "\t" << state->id << " -> ";
+
+ if ( tel->value->targ == 0 )
+ out << "err_" << state->id;
+ else
+ out << tel->value->targ->id;
+
+ /* Begin the label. */
+ out << " [ label = \"";
+ ONCHAR( tel->lowKey, tel->highKey );
+
+ /* Walk the transition list, finding the same. */
+ for ( RedTransList::Iter mtel = tel.next(); mtel.lte(); mtel++ ) {
+ if ( mtel->value == tel->value ) {
+ out << ", ";
+ ONCHAR( mtel->lowKey, mtel->highKey );
+ }
+ }
+
+ /* Write the action and close the transition. */
+ TRANS_ACTION( state, tel->value );
+ out << "\" ];\n";
+ }
+ }
+
+ /* Write the default transition. */
+ if ( state->defTrans != 0 ) {
+ /* Write out the from and to states. */
+ out << "\t" << state->id << " -> ";
+
+ if ( state->defTrans->targ == 0 )
+ out << "err_" << state->id;
+ else
+ out << state->defTrans->targ->id;
+
+ /* Begin the label. */
+ out << " [ label = \"DEF";
+
+ /* Write the action and close the transition. */
+ TRANS_ACTION( state, state->defTrans );
+ out << "\" ];\n";
+ }
+}
+
+void GraphvizDotGen::writeDotFile( )
+{
+ out <<
+ "digraph " << fsmName << " {\n"
+ " rankdir=LR;\n";
+
+ /* Define the psuedo states. Transitions will be done after the states
+ * have been defined as either final or not final. */
+ out << " node [ shape = point ];\n";
+
+ if ( redFsm->startState != 0 )
+ out << " ENTRY;\n";
+
+ /* Psuedo states for entry points in the entry map. */
+ for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
+ RedStateAp *state = allStates + *en;
+ out << " en_" << state->id << ";\n";
+ }
+
+ /* Psuedo states for final states with eof actions. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 && st->eofTrans->action != 0 )
+ out << " eof_" << st->id << ";\n";
+ if ( st->eofAction != 0 )
+ out << " eof_" << st->id << ";\n";
+ }
+
+ out << " node [ shape = circle, height = 0.2 ];\n";
+
+ /* Psuedo states for states whose default actions go to error. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ bool needsErr = false;
+ if ( st->defTrans != 0 && st->defTrans->targ == 0 )
+ needsErr = true;
+ else {
+ for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ ) {
+ if ( tel->value->targ == 0 ) {
+ needsErr = true;
+ break;
+ }
+ }
+ }
+
+ if ( needsErr )
+ out << " err_" << st->id << " [ label=\"\"];\n";
+ }
+
+ /* Attributes common to all nodes, plus double circle for final states. */
+ out << " node [ fixedsize = true, height = 0.65, shape = doublecircle ];\n";
+
+ /* List Final states. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->isFinal )
+ out << " " << st->id << ";\n";
+ }
+
+ /* List transitions. */
+ out << " node [ shape = circle ];\n";
+
+ /* Walk the states. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ writeTransList( st );
+
+ /* Transitions into the start state. */
+ if ( redFsm->startState != 0 )
+ out << " ENTRY -> " << redFsm->startState->id << " [ label = \"IN\" ];\n";
+
+ /* Transitions into the entry points. */
+ for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
+ RedStateAp *state = allStates + *en;
+ char *name = entryPointNames[en.pos()];
+ out << " en_" << state->id << " -> " << state->id <<
+ " [ label = \"" << name << "\" ];\n";
+ }
+
+ /* Out action transitions. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
+ out << " " << st->id << " -> eof_" <<
+ st->id << " [ label = \"EOF";
+ ACTION( st->eofTrans->action ) << "\" ];\n";
+ }
+ if ( st->eofAction != 0 ) {
+ out << " " << st->id << " -> eof_" <<
+ st->id << " [ label = \"EOF";
+ ACTION( st->eofAction ) << "\" ];\n";
+ }
+ }
+
+ out <<
+ "}\n";
+}
+
+void GraphvizDotGen::finishRagelDef()
+{
+ /* For dot file generation we want to pick default transitions. */
+ redFsm->chooseDefaultSpan();
+}