Pete,

I translated the French parts of my program into English.
My secret goal is that someone smart will find it so ugly and so fragile that he'll feel challenged to write a nice version for all of us ;-)

It doesn't handle very well Rob's example (well, my brain doesn't handle it neither ^^), but it was useful to understand a few crazy pipelines I came across. It reads a file consisting of a single line, containing your pipeline just before it runs (without the rexx quotes or rexx comas).
Email me if you've got a problem with it.

Hope it can help.

Michaël







/*------------------------------------------------------------------*/
/* Analyses a ready-to-run pipeline (without quotes, comas) to      */
/* create a "dot" file, ready to use for the PC program Graphviz.   */
/* The pipeline must be on one line.                                */
/*------------------------------------------------------------------*/

arg fnIn ftIn fmIn

call analysePipeline

call createDotFile

exit 0


/*
 *------------------------------------------------------------------
 * Split the pipeline in its parts, ...
 *------------------------------------------------------------------
 */

analysePipeline :

  pipelineOnOneLine = fnIn ftIn fmIn

  tempFile   = "PIPE2DOT TEMPO A"
  outputFile = fnIn "DOT A"

  "ERASE "tempFile

  /* The pipeline must be on a single line for the current program */

  allTheFile.0 = 0
  'pipe < 'pipelineOnOneLine,
  '| stem allTheFile.'
  if (RC <> 0) then exit RC

  if (allTheFile.0 <> 1) then exit -1

  thePipeline = allTheFile.1

  /* Neutralizes the things I don't know how to treat */

  'pipe var thePipeline',
  '| change /(/ ( /', /* To make options readable more quickly */
  '| change /)/ ) /', /* Idem */
  '| change /*:/_PIPELINE_EXTREMITY_/',
  '| change /*.output./_PIPELINE_OUTPUT_/',
  '| var allThePipeline'
  if (RC <> 0) then exit RC

  parse value allThePipeline with word1 word2 .

  /* Default separator and endchar characters */

  theSepCharacter = "|"
  theEndCharacter = ""

  /* If there are options (SEPARATOR or ENDCHAR) , parses them */

  if (substr(word2,1,1) = "(") then do
    parse value allThePipeline with word1 restOfPipeline
    begOfOptions = pos("(", restOfPipeline) + 1
    endOfOptions = pos(")", restOfPipeline) - 1
    lgtOfOptions = endOfOptions - begOfOptions + 1
    theOptions = substr(restOfPipeline, begOfOptions, lgtOfOptions)

    do i=1 to words(theOptions)
      theWord = word(theOptions, i)
      upper theWord
      if (1 = abbrev('SEPARATOR',theWord,3)) then do
       theSepCharacter = word(theOptions, i+1)
      end
      else if (1 = abbrev('ENDCHAR',theWord,3)) then do
       theEndCharacter = word(theOptions, i+1)
      end
    end
    restOfPipeline = substr(restOfPipeline, endOfOptions + 2)
    restOfPipeline = strip(restOfPipeline)
  end
  else do
    restOfPipeline = subword(allThePipeline, 2)
  end

  /* Splits on the endchar if there is one, or done otherwise */

  if (theEndCharacter <> "") then do
    arrayOfPipelines.0 = 0
    'pipe var restOfPipeline',
    '| split at str /'theEndCharacter'/',
    '| strip',
    '| stem arrayOfPipelines.'
    if (RC <> 0) then exit RC
  end
  else do
    arrayOfPipelines.0 = 1
    arrayOfPipelines.1 = restOfPipeline
  end

  return

/*
 *------------------------------------------------------------------
 * Creates the file for Graphviz
 *------------------------------------------------------------------
 */

createDotFile :

  call initColorNames

  begOfDotOptions = ' [label = "'
  endOfDotOptions = '"]'

  /* Graphviz "dot" format beginning */

  "pipe strliteral /digraph g {/ | >> "tempFile

  /*
   * For each ex-endchar-separated part, split on the sep character,
   * to get each stage
   */

  do i=1 to arrayOfPipelines.0
    thePart = arrayOfPipelines.i
    theColor = getColorName(i)
    'pipe (stagesep % endchar €)',
    '  var thePart',
    '% split at str /'theSepCharacter'/',
    '% strip',
    '% i1: if pick substr -1;-1 of w1 == /:/',
    '%   i2: if pick w2 == //',
    '%     spec /STAGE_/ n substr 1;-2 of w1 n',
    '%   i2:',
    '%     spec /STAGE_/ n substr 1;-2 of w1 n ',
             '/'begOfDotOptions'/ n 1-* n /'endOfDotOptions'/ n',
    '%   i2:',
    '% i1:',
    '%     spec /STAGE_'i'_/ n  recno strip n ',
             '/'begOfDotOptions'/ n 1-* n /'endOfDotOptions'/ n',
    '% i1:',
    '% OUT: fanout',
    '% spec 1-* 1 /;/ n',
    '% IN: faninany',
    '% >> 'tempFile,
    '€',
    '  OUT:',
    '% spec w1 1',
    '% FIRST: take first',
    '% IN_1: faninany',
    '% IN_2: faninany',
    '% join 1 / -> /',
    '% spec 1-* 1 / [color='theColor'];/ n',
    '% IN:',
    '€',
    '  FIRST:',
    '% LAST: drop last',
    '% duplicate 1',
    '% IN_1:',
    '€',
    '  LAST:',
    '% IN_2:'
    if (RC <> 0) then exit RC

  end

  /* Graphviz "dot" format ending */

  "pipe strliteral /}/ | >> "tempFile

  /* 1. Quickly and dirtily removes spaces */
  /* 2. Changes characters badly transfered by Filezilla */

  "pipe < "tempFile,
  "| change /[/ xAD",
  "| change /]/ xBD",
  "| change /{/ xC0",
  "| change /}/ xD0",
  "| change /                      / / /",
  "| change /                     /  / /",
  "| change /                    /   / /",
  "| change /                   /    / /",
  "| change /                  /     / /",
  "| change /                 /      / /",
  "| change /                /       / /",
  "| change /               /        / /",
  "| change /              /         / /",
  "| change /             /          / /",
  "| change /            /           / /",
  "| change /           /            / /",
  "| change /          /             / /",
  "| change /         /              / /",
  "| change /        /               / /",
  "| change /       /                / /",
  "| change /      /                 / /",
  "| change /     /                  / /",
  "| change /    /                   / /",
  "| change /   /                    / /",
  "| change /  /                     / /",
  "| > "outputFile
  if (RC <> 0) then exit RC

  "ERASE "tempFile

  return

/*
 *------------------------------------------------------------------
 * We can use only a finite number of colors, so some lines
 * will have to have the same colors.
 * Maths note :
 * The "-1" and "+1" are here because the rank I want (realRank)
 * is not proportionnal to the rank I give (colorRank).
 * But "realRank - 1" IS proportional to "colorRank - 1"
 *------------------------------------------------------------------
 */

getColorName :

  arg colorRank

  realRank = (colorRank - 1) // arrayColors.0 + 1

  return arrayColors.realRank


/*
 *------------------------------------------------------------------
 * Uses only a small number of colors (because anyway, some other
 * colors are difficult to differentiate
 *------------------------------------------------------------------
 */

initColorNames :

  i=0
  i=i+1;arrayColors.i = "red"
  i=i+1;arrayColors.i = "blue"
  i=i+1;arrayColors.i = "green"
  i=i+1;arrayColors.i = "magenta"
  i=i+1;arrayColors.i = "black"
  i=i+1;arrayColors.i = "brown"
  i=i+1;arrayColors.i = "dimgray"
  i=i+1;arrayColors.i = "darkorange"
  i=i+1;arrayColors.i = "darkturquoise"
  i=i+1;arrayColors.i = "violet"
  i=i+1;arrayColors.i = "forestgreen"
  i=i+1;arrayColors.i = "firebrick"
  i=i+1;arrayColors.i = "crimson"
  i=i+1;arrayColors.i = "blueviolet"
  arrayColors.0 = i

  return

Reply via email to